From 0b22a4838c440732de8a502dcb23cc81487a166e Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 09:49:50 +0900 Subject: [PATCH 001/128] Remove `RefCell` from generated code --- flutter_ffi_plugin/bin/src/message.dart | 33 ++++++++++--------------- rust_crate/src/interface.rs | 3 +-- rust_crate/src/interface_os.rs | 14 +++++------ 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 691a3f955..a9a6be58c 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -250,8 +250,7 @@ use crate::tokio; use prost::Message; use rinf::send_rust_signal; use rinf::DartSignal; -use rinf::SharedCell; -use std::cell::RefCell; +use rinf::SharedLock; use std::sync::Mutex; use std::sync::OnceLock; use tokio::sync::mpsc::unbounded_channel; @@ -272,7 +271,7 @@ use tokio::sync::mpsc::UnboundedSender; await insertTextToFile( rustPath, ''' -type ${messageName}Cell = SharedCell<( +type ${messageName}Cell = SharedLock<( Option>>, Option>>, )>; @@ -281,10 +280,10 @@ pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = impl ${normalizePascal(messageName)} { pub fn get_dart_signal_receiver() -> UnboundedReceiver> { - let cell = ${snakeName.toUpperCase()}_CHANNEL + let mut lock = ${snakeName.toUpperCase()}_CHANNEL .get_or_init(|| { let (sender, receiver) = unbounded_channel(); - Mutex::new(RefCell::new(Some((Some(sender), Some(receiver))))) + Mutex::new(Some((Some(sender), Some(receiver)))) }) .lock() .unwrap(); @@ -293,17 +292,15 @@ impl ${normalizePascal(messageName)} { // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - let borrowed = cell.borrow(); - let pair = borrowed.as_ref().unwrap(); + let pair = lock.as_ref().unwrap(); let is_closed = pair.0.as_ref().unwrap().is_closed(); - drop(borrowed); if is_closed { let (sender, receiver) = unbounded_channel(); - cell.replace(Some((Some(sender), Some(receiver)))); + lock.replace((Some(sender), Some(receiver))); } } - let pair = cell.take().unwrap(); - cell.replace(Some((pair.0, None))); + let pair = lock.take().unwrap(); + lock.replace((pair.0, None)); pair.1.expect("A receiver can be taken only once") } } @@ -405,7 +402,6 @@ use crate::tokio; use prost::Message; use rinf::debug_print; use rinf::DartSignal; -use std::cell::RefCell; use std::collections::HashMap; use std::sync::Mutex; use std::sync::OnceLock; @@ -452,10 +448,10 @@ hash_map.insert( message, binary, }; - let cell = ${snakeName.toUpperCase()}_CHANNEL + let mut lock = ${snakeName.toUpperCase()}_CHANNEL .get_or_init(|| { let (sender, receiver) = unbounded_channel(); - Mutex::new(RefCell::new(Some((Some(sender), Some(receiver))))) + Mutex::new(Some((Some(sender), Some(receiver)))) }) .lock() .unwrap(); @@ -464,17 +460,14 @@ hash_map.insert( // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - let borrowed = cell.borrow(); - let pair = borrowed.as_ref().unwrap(); + let pair = lock.as_ref().unwrap(); let is_closed = pair.0.as_ref().unwrap().is_closed(); - drop(borrowed); if is_closed { let (sender, receiver) = unbounded_channel(); - cell.replace(Some((Some(sender), Some(receiver)))); + lock.replace((Some(sender), Some(receiver))); } } - let borrowed = cell.borrow(); - let pair = borrowed.as_ref().unwrap(); + let pair = lock.as_ref().unwrap(); let sender = pair.0.as_ref().unwrap(); let _ = sender.send(dart_signal); }), diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index 0e094c8c3..2b6ae7bd5 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::sync::Mutex; use std::sync::OnceLock; @@ -8,7 +7,7 @@ use super::interface_os::*; use super::interface_web::*; /// This is a mutable cell type that can be shared across threads. -pub type SharedCell = OnceLock>>>; +pub type SharedLock = OnceLock>>; /// This contains a message from Dart. /// Optionally, a custom binary called `binary` can also be included. diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 65002ece6..1006a0120 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -1,29 +1,27 @@ -use super::SharedCell; +use super::SharedLock; use allo_isolate::IntoDart; use allo_isolate::Isolate; use allo_isolate::ZeroCopyBuffer; -use std::cell::RefCell; use std::panic::catch_unwind; use std::sync::Mutex; use std::sync::OnceLock; -static DART_ISOLATE: SharedCell = OnceLock::new(); +static DART_ISOLATE: SharedLock = OnceLock::new(); #[no_mangle] pub extern "C" fn prepare_isolate_extern(port: i64) { let _ = catch_unwind(|| { let dart_isolate = Isolate::new(port); - let cell = DART_ISOLATE - .get_or_init(|| Mutex::new(RefCell::new(None))) + let mut cell = DART_ISOLATE + .get_or_init(|| Mutex::new(None)) .lock() .unwrap(); - cell.replace(Some(dart_isolate)); + cell.replace(dart_isolate); }); } pub fn send_rust_signal_extern(message_id: i32, message_bytes: Vec, binary: Vec) { - let cell = DART_ISOLATE.get().unwrap().lock().unwrap(); - let dart_isolate = cell.borrow().unwrap(); + let dart_isolate = DART_ISOLATE.get().unwrap().lock().unwrap().unwrap(); // If a `Vec` is empty, we can't just simply send it to Dart // because panic can occur from null pointers. From 443eba8b6d39cd3d8920c42262c6b92c9aa1c893 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 10:10:31 +0900 Subject: [PATCH 002/128] Rename variables --- flutter_ffi_plugin/bin/src/message.dart | 18 +++++++++--------- rust_crate/src/interface_os.rs | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index a9a6be58c..aa0fb3b52 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -280,7 +280,7 @@ pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = impl ${normalizePascal(messageName)} { pub fn get_dart_signal_receiver() -> UnboundedReceiver> { - let mut lock = ${snakeName.toUpperCase()}_CHANNEL + let mut guard = ${snakeName.toUpperCase()}_CHANNEL .get_or_init(|| { let (sender, receiver) = unbounded_channel(); Mutex::new(Some((Some(sender), Some(receiver)))) @@ -292,15 +292,15 @@ impl ${normalizePascal(messageName)} { // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - let pair = lock.as_ref().unwrap(); + let pair = guard.as_ref().unwrap(); let is_closed = pair.0.as_ref().unwrap().is_closed(); if is_closed { let (sender, receiver) = unbounded_channel(); - lock.replace((Some(sender), Some(receiver))); + guard.replace((Some(sender), Some(receiver))); } } - let pair = lock.take().unwrap(); - lock.replace((pair.0, None)); + let pair = guard.take().unwrap(); + guard.replace((pair.0, None)); pair.1.expect("A receiver can be taken only once") } } @@ -448,7 +448,7 @@ hash_map.insert( message, binary, }; - let mut lock = ${snakeName.toUpperCase()}_CHANNEL + let mut guard = ${snakeName.toUpperCase()}_CHANNEL .get_or_init(|| { let (sender, receiver) = unbounded_channel(); Mutex::new(Some((Some(sender), Some(receiver)))) @@ -460,14 +460,14 @@ hash_map.insert( // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - let pair = lock.as_ref().unwrap(); + let pair = guard.as_ref().unwrap(); let is_closed = pair.0.as_ref().unwrap().is_closed(); if is_closed { let (sender, receiver) = unbounded_channel(); - lock.replace((Some(sender), Some(receiver))); + guard.replace((Some(sender), Some(receiver))); } } - let pair = lock.as_ref().unwrap(); + let pair = guard.as_ref().unwrap(); let sender = pair.0.as_ref().unwrap(); let _ = sender.send(dart_signal); }), diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 1006a0120..fe0698584 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -12,11 +12,11 @@ static DART_ISOLATE: SharedLock = OnceLock::new(); pub extern "C" fn prepare_isolate_extern(port: i64) { let _ = catch_unwind(|| { let dart_isolate = Isolate::new(port); - let mut cell = DART_ISOLATE + let mut guard = DART_ISOLATE .get_or_init(|| Mutex::new(None)) .lock() .unwrap(); - cell.replace(dart_isolate); + guard.replace(dart_isolate); }); } From 19be2d4d2ef98774bec6a7b07326478e6fd4f86f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 10:14:38 +0900 Subject: [PATCH 003/128] Remove `SharedLock` type alias --- flutter_ffi_plugin/bin/src/message.dart | 5 ++--- rust_crate/src/interface.rs | 6 ------ rust_crate/src/interface_os.rs | 3 +-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index aa0fb3b52..5782e7fdd 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -250,7 +250,6 @@ use crate::tokio; use prost::Message; use rinf::send_rust_signal; use rinf::DartSignal; -use rinf::SharedLock; use std::sync::Mutex; use std::sync::OnceLock; use tokio::sync::mpsc::unbounded_channel; @@ -271,10 +270,10 @@ use tokio::sync::mpsc::UnboundedSender; await insertTextToFile( rustPath, ''' -type ${messageName}Cell = SharedLock<( +type ${messageName}Cell = OnceLock>>, Option>>, -)>; +)>>>; pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = OnceLock::new(); diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index 2b6ae7bd5..b13a732a5 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -1,14 +1,8 @@ -use std::sync::Mutex; -use std::sync::OnceLock; - #[cfg(not(target_family = "wasm"))] use super::interface_os::*; #[cfg(target_family = "wasm")] use super::interface_web::*; -/// This is a mutable cell type that can be shared across threads. -pub type SharedLock = OnceLock>>; - /// This contains a message from Dart. /// Optionally, a custom binary called `binary` can also be included. /// This type is generic, and the message diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index fe0698584..3add31e75 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -1,4 +1,3 @@ -use super::SharedLock; use allo_isolate::IntoDart; use allo_isolate::Isolate; use allo_isolate::ZeroCopyBuffer; @@ -6,7 +5,7 @@ use std::panic::catch_unwind; use std::sync::Mutex; use std::sync::OnceLock; -static DART_ISOLATE: SharedLock = OnceLock::new(); +static DART_ISOLATE: OnceLock>> = OnceLock::new(); #[no_mangle] pub extern "C" fn prepare_isolate_extern(port: i64) { From 972b4428d3742e94730ffd71bfbd7ffac4b4974f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 12:00:16 +0900 Subject: [PATCH 004/128] Initial working status of shutdown future --- .../example/native/hub/src/lib.rs | 6 ++ rust_crate/src/macros.rs | 66 ++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs index 26bc5a855..9e7f2b2e2 100755 --- a/flutter_ffi_plugin/example/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs @@ -18,4 +18,10 @@ async fn main() { tokio::spawn(sample_functions::tell_numbers()); tokio::spawn(sample_functions::stream_fractal()); tokio::spawn(sample_functions::run_debug_tests()); + dart_shutdown().await; + for i in 0..15 { + use std::time::Duration; + println!("{i}"); + tokio::time::sleep(Duration::from_secs(1)).await; + } } diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index d06b13cc8..c13eb814a 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -7,14 +7,42 @@ /// at the root of the `hub` crate. macro_rules! write_interface { () => { + use crate::tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; + use std::sync::mpsc::Receiver; + use std::sync::{Mutex, OnceLock}; + + struct ShutdownStore { + shutdown_sender: Option>, + shutdown_receiver: Option>, + done_receiver: Receiver<()>, + } + + type ShutdownStoreShared = OnceLock>>; + static SHUTDOWN_STORE: ShutdownStoreShared = OnceLock::new(); + + fn get_shutdown_receiver() -> UnboundedReceiver<()> { + let mut guard = SHUTDOWN_STORE + .get_or_init(|| Mutex::new(None)) + .lock() + .unwrap(); + guard.as_mut().unwrap().shutdown_receiver.take().unwrap() + } + + async fn dart_shutdown() { + let mut shutdown_receiver = get_shutdown_receiver(); + shutdown_receiver.recv().await; + } + #[cfg(not(target_family = "wasm"))] mod interface_os { use crate::tokio::runtime::Builder; use crate::tokio::runtime::Runtime; + use crate::tokio::sync::mpsc::unbounded_channel; use rinf::externs::os_thread_local::ThreadLocal; use std::cell::RefCell; use std::panic::catch_unwind; - use std::sync::OnceLock; + use std::sync::mpsc::channel as std_channel; + use std::sync::{Mutex, OnceLock}; // We use `os_thread_local` so that when the program fails // and the main thread exits unexpectedly, @@ -36,9 +64,28 @@ macro_rules! write_interface { })); } + // Prepare to notify Dart shutdown. + let (shutdown_sender, shutdown_receiver) = unbounded_channel(); + let (done_sender, done_receiver) = std_channel::<()>(); + let mut guard = crate::SHUTDOWN_STORE + .get_or_init(|| Mutex::new(None)) + .lock() + .unwrap(); + guard.replace(crate::ShutdownStore { + shutdown_sender: Some(shutdown_sender), + shutdown_receiver: Some(shutdown_receiver), + done_receiver, + }); + // Run the main function. let tokio_runtime = Builder::new_multi_thread().enable_all().build().unwrap(); - tokio_runtime.spawn(crate::main()); + tokio_runtime.spawn(async move { + // Start the logic. + crate::main().await; + // After the async runtime has done its job, + // tell the main thread to stop waiting. + let _ = done_sender.send(()); + }); let os_cell = TOKIO_RUNTIME.get_or_init(|| ThreadLocal::new(|| RefCell::new(None))); os_cell.with(move |cell| { @@ -53,11 +100,24 @@ macro_rules! write_interface { #[no_mangle] pub extern "C" fn stop_rust_logic_extern() { + // Tell the Rust logic to perform finalziation code. + let mut guard = crate::SHUTDOWN_STORE + .get_or_init(|| Mutex::new(None)) + .lock() + .unwrap(); + let _ = guard + .as_ref() + .unwrap() + .shutdown_sender + .as_ref() + .unwrap() + .send(()); + let _ = guard.as_ref().unwrap().done_receiver.recv(); + // Dropping the tokio runtime causes it to shut down completely. let _ = catch_unwind(|| { let os_cell = TOKIO_RUNTIME.get_or_init(|| ThreadLocal::new(|| RefCell::new(None))); os_cell.with(move |cell| { - // Dropping the tokio runtime causes it to shut down. cell.take(); }); }); From b9308a76d41f58343f045f0f6a0a4b7c002f507c Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 22:19:51 +0900 Subject: [PATCH 005/128] Use channels with buffers when dealing with lifecycles --- rust_crate/src/macros.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index c13eb814a..379618b64 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -7,20 +7,20 @@ /// at the root of the `hub` crate. macro_rules! write_interface { () => { - use crate::tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; - use std::sync::mpsc::Receiver; + use crate::tokio::sync::mpsc::{Receiver, Sender}; + use std::sync::mpsc::Receiver as StdReceiver; use std::sync::{Mutex, OnceLock}; struct ShutdownStore { - shutdown_sender: Option>, - shutdown_receiver: Option>, - done_receiver: Receiver<()>, + shutdown_sender: Option>, + shutdown_receiver: Option>, + done_receiver: StdReceiver<()>, } type ShutdownStoreShared = OnceLock>>; static SHUTDOWN_STORE: ShutdownStoreShared = OnceLock::new(); - fn get_shutdown_receiver() -> UnboundedReceiver<()> { + fn get_shutdown_receiver() -> Receiver<()> { let mut guard = SHUTDOWN_STORE .get_or_init(|| Mutex::new(None)) .lock() @@ -37,11 +37,11 @@ macro_rules! write_interface { mod interface_os { use crate::tokio::runtime::Builder; use crate::tokio::runtime::Runtime; - use crate::tokio::sync::mpsc::unbounded_channel; + use crate::tokio::sync::mpsc::channel; use rinf::externs::os_thread_local::ThreadLocal; use std::cell::RefCell; use std::panic::catch_unwind; - use std::sync::mpsc::channel as std_channel; + use std::sync::mpsc::sync_channel; use std::sync::{Mutex, OnceLock}; // We use `os_thread_local` so that when the program fails @@ -65,8 +65,8 @@ macro_rules! write_interface { } // Prepare to notify Dart shutdown. - let (shutdown_sender, shutdown_receiver) = unbounded_channel(); - let (done_sender, done_receiver) = std_channel::<()>(); + let (shutdown_sender, shutdown_receiver) = channel(1); + let (done_sender, done_receiver) = sync_channel::<()>(1); let mut guard = crate::SHUTDOWN_STORE .get_or_init(|| Mutex::new(None)) .lock() @@ -111,7 +111,7 @@ macro_rules! write_interface { .shutdown_sender .as_ref() .unwrap() - .send(()); + .try_send(()); let _ = guard.as_ref().unwrap().done_receiver.recv(); // Dropping the tokio runtime causes it to shut down completely. let _ = catch_unwind(|| { From 895fa17164da8007aa1330f1826c85966287e85f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 22:23:23 +0900 Subject: [PATCH 006/128] Organize code --- rust_crate/src/macros.rs | 58 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 379618b64..3fe88e777 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -7,41 +7,17 @@ /// at the root of the `hub` crate. macro_rules! write_interface { () => { - use crate::tokio::sync::mpsc::{Receiver, Sender}; - use std::sync::mpsc::Receiver as StdReceiver; - use std::sync::{Mutex, OnceLock}; - - struct ShutdownStore { - shutdown_sender: Option>, - shutdown_receiver: Option>, - done_receiver: StdReceiver<()>, - } - - type ShutdownStoreShared = OnceLock>>; - static SHUTDOWN_STORE: ShutdownStoreShared = OnceLock::new(); - - fn get_shutdown_receiver() -> Receiver<()> { - let mut guard = SHUTDOWN_STORE - .get_or_init(|| Mutex::new(None)) - .lock() - .unwrap(); - guard.as_mut().unwrap().shutdown_receiver.take().unwrap() - } - - async fn dart_shutdown() { - let mut shutdown_receiver = get_shutdown_receiver(); - shutdown_receiver.recv().await; - } - #[cfg(not(target_family = "wasm"))] mod interface_os { use crate::tokio::runtime::Builder; use crate::tokio::runtime::Runtime; use crate::tokio::sync::mpsc::channel; + use crate::tokio::sync::mpsc::{Receiver, Sender}; use rinf::externs::os_thread_local::ThreadLocal; use std::cell::RefCell; use std::panic::catch_unwind; use std::sync::mpsc::sync_channel; + use std::sync::mpsc::Receiver as StdReceiver; use std::sync::{Mutex, OnceLock}; // We use `os_thread_local` so that when the program fails @@ -50,6 +26,30 @@ macro_rules! write_interface { type TokioRuntime = OnceLock>>>; static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); + // These channels are used for gracefully shutting down the tokio runtime. + // Right before the topmost Flutter widget gets disposed, + // these channels will ensure that Rust logic is properly stopped. + struct ShutdownStore { + shutdown_sender: Option>, + shutdown_receiver: Option>, + done_receiver: StdReceiver<()>, + } + type ShutdownStoreShared = OnceLock>>; + static SHUTDOWN_STORE: ShutdownStoreShared = OnceLock::new(); + + fn get_shutdown_receiver() -> Receiver<()> { + let mut guard = SHUTDOWN_STORE + .get_or_init(|| Mutex::new(None)) + .lock() + .unwrap(); + guard.as_mut().unwrap().shutdown_receiver.take().unwrap() + } + + async fn dart_shutdown() { + let mut shutdown_receiver = get_shutdown_receiver(); + shutdown_receiver.recv().await; + } + #[no_mangle] pub extern "C" fn start_rust_logic_extern() { let _ = catch_unwind(|| { @@ -67,11 +67,11 @@ macro_rules! write_interface { // Prepare to notify Dart shutdown. let (shutdown_sender, shutdown_receiver) = channel(1); let (done_sender, done_receiver) = sync_channel::<()>(1); - let mut guard = crate::SHUTDOWN_STORE + let mut guard = SHUTDOWN_STORE .get_or_init(|| Mutex::new(None)) .lock() .unwrap(); - guard.replace(crate::ShutdownStore { + guard.replace(ShutdownStore { shutdown_sender: Some(shutdown_sender), shutdown_receiver: Some(shutdown_receiver), done_receiver, @@ -101,7 +101,7 @@ macro_rules! write_interface { #[no_mangle] pub extern "C" fn stop_rust_logic_extern() { // Tell the Rust logic to perform finalziation code. - let mut guard = crate::SHUTDOWN_STORE + let mut guard = SHUTDOWN_STORE .get_or_init(|| Mutex::new(None)) .lock() .unwrap(); From 43437f595961b33e64cb12dbfb0e4f43e5c43b0f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 22:27:25 +0900 Subject: [PATCH 007/128] Make `dart_shutdown` function accessible --- rust_crate/src/macros.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 3fe88e777..ee0f9bb47 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -7,18 +7,27 @@ /// at the root of the `hub` crate. macro_rules! write_interface { () => { + async fn dart_shutdown() { + #[cfg(not(target_family = "wasm"))] + { + let mut shutdown_receiver = interface_os::get_shutdown_receiver(); + shutdown_receiver.recv().await; + } + } + #[cfg(not(target_family = "wasm"))] mod interface_os { - use crate::tokio::runtime::Builder; - use crate::tokio::runtime::Runtime; - use crate::tokio::sync::mpsc::channel; - use crate::tokio::sync::mpsc::{Receiver, Sender}; + use crate::tokio; use rinf::externs::os_thread_local::ThreadLocal; use std::cell::RefCell; use std::panic::catch_unwind; use std::sync::mpsc::sync_channel; use std::sync::mpsc::Receiver as StdReceiver; use std::sync::{Mutex, OnceLock}; + use tokio::runtime::Builder; + use tokio::runtime::Runtime; + use tokio::sync::mpsc::channel; + use tokio::sync::mpsc::{Receiver, Sender}; // We use `os_thread_local` so that when the program fails // and the main thread exits unexpectedly, @@ -37,7 +46,7 @@ macro_rules! write_interface { type ShutdownStoreShared = OnceLock>>; static SHUTDOWN_STORE: ShutdownStoreShared = OnceLock::new(); - fn get_shutdown_receiver() -> Receiver<()> { + pub fn get_shutdown_receiver() -> Receiver<()> { let mut guard = SHUTDOWN_STORE .get_or_init(|| Mutex::new(None)) .lock() @@ -45,11 +54,6 @@ macro_rules! write_interface { guard.as_mut().unwrap().shutdown_receiver.take().unwrap() } - async fn dart_shutdown() { - let mut shutdown_receiver = get_shutdown_receiver(); - shutdown_receiver.recv().await; - } - #[no_mangle] pub extern "C" fn start_rust_logic_extern() { let _ = catch_unwind(|| { From a0ce015aa4663b768b84f954c6326070aa1d1190 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 22:31:46 +0900 Subject: [PATCH 008/128] Make the linter happy --- rust_crate/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index ee0f9bb47..1530ce42c 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -105,7 +105,7 @@ macro_rules! write_interface { #[no_mangle] pub extern "C" fn stop_rust_logic_extern() { // Tell the Rust logic to perform finalziation code. - let mut guard = SHUTDOWN_STORE + let guard = SHUTDOWN_STORE .get_or_init(|| Mutex::new(None)) .lock() .unwrap(); From 81381fea4c8786bc92f509e36405bc60450826a3 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Thu, 6 Jun 2024 22:52:46 +0900 Subject: [PATCH 009/128] Make `dart_shutdown` work as expected on the web --- flutter_ffi_plugin/example/native/hub/src/lib.rs | 2 +- rust_crate/src/macros.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs index 9e7f2b2e2..4892a983b 100755 --- a/flutter_ffi_plugin/example/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs @@ -21,7 +21,7 @@ async fn main() { dart_shutdown().await; for i in 0..15 { use std::time::Duration; - println!("{i}"); + rinf::debug_print!("SHUTDOWN {i}"); tokio::time::sleep(Duration::from_secs(1)).await; } } diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 1530ce42c..5f551f44e 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -10,9 +10,17 @@ macro_rules! write_interface { async fn dart_shutdown() { #[cfg(not(target_family = "wasm"))] { + // The receiver will get a signal + // while the topmost Flutter widget is getting disposed. let mut shutdown_receiver = interface_os::get_shutdown_receiver(); shutdown_receiver.recv().await; } + #[cfg(target_family = "wasm")] + { + // The receiver will wait forever because it never gets a message. + let (_sender, receiver) = tokio::sync::oneshot::channel::<()>(); + let _ = receiver.await; + } } #[cfg(not(target_family = "wasm"))] From 649fb3cf4849b1759db72e39084cf0ed9bfed460 Mon Sep 17 00:00:00 2001 From: Thomas Min Date: Fri, 7 Jun 2024 17:09:34 +0900 Subject: [PATCH 010/128] feat: upgrade prost to 0.12.6 --- flutter_ffi_plugin/example/native/hub/Cargo.toml | 2 +- flutter_ffi_plugin/template/native/hub/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index 522c8f6a9..0012c397f 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -13,7 +13,7 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] rinf = "6.11.1" -prost = "0.12.3" +prost = "0.12.6" wasm-bindgen = "0.2.92" # Uncomment this line to target the web tokio_with_wasm = "0.4.4" # Uncomment this line to target the web sample_crate = { path = "../sample_crate" } diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index ab480ee8c..dacb0d73c 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -13,7 +13,7 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] rinf = "6.11.1" -prost = "0.12.3" +prost = "0.12.6" tokio = { version = "1", features = ["rt-multi-thread", "sync", "macros"] } # wasm-bindgen = "0.2.92" # Uncomment this line to target the web # tokio_with_wasm = "0.4.4" # Uncomment this line to target the web From 5e76316e5a4cdfb91313200280ab1342ff8e2cd0 Mon Sep 17 00:00:00 2001 From: temeddix Date: Fri, 7 Jun 2024 21:20:15 +0900 Subject: [PATCH 011/128] Change debug code --- flutter_ffi_plugin/example/native/hub/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs index 4892a983b..c45bce343 100755 --- a/flutter_ffi_plugin/example/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs @@ -21,7 +21,7 @@ async fn main() { dart_shutdown().await; for i in 0..15 { use std::time::Duration; - rinf::debug_print!("SHUTDOWN {i}"); + println!("SHUTDOWN {i}"); tokio::time::sleep(Duration::from_secs(1)).await; } } From 0755b4f7e8e48a31678d8afa3f9b3b9b0bfb3a08 Mon Sep 17 00:00:00 2001 From: Debanjan Basu Date: Fri, 7 Jun 2024 22:45:20 +1000 Subject: [PATCH 012/128] upgraded to take into account sdk versions defined from parent --- flutter_ffi_plugin/android/build.gradle | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/flutter_ffi_plugin/android/build.gradle b/flutter_ffi_plugin/android/build.gradle index 32230e317..cc1414680 100755 --- a/flutter_ffi_plugin/android/build.gradle +++ b/flutter_ffi_plugin/android/build.gradle @@ -24,6 +24,12 @@ rootProject.allprojects { apply plugin: 'com.android.library' +// SDK Version 34 is the LTS as of now, till Flutter upgrades +// There are also deprecated attributes, this takes all of them into account +def compileSdkVersion = Math.max(android.compileSdkVersion, android.compileSdk, 31).toInteger() +// Defaults to the 16 if nothing is specified, or else overrides from the parent +def minSdkVersion = Math.max(android.minSdkVersion, android.minSdk, 16).toInteger() + android { if (project.android.hasProperty("namespace")) { namespace 'com.cunarist.rinf' @@ -31,7 +37,7 @@ android { // Bumping the plugin compileSdkVersion requires all clients of this plugin // to bump the version in their app. - compileSdkVersion 31 + compileSdkVersion compileSdkVersion // Simply use the `android.ndkVersion` // declared in the `./android/app/build.gradle` file of the Flutter project. @@ -58,7 +64,7 @@ android { } defaultConfig { - minSdkVersion 16 + minSdkVersion minSdkVersion } } From 13273ecc642b6055939b4318de8b6c69097e8bdb Mon Sep 17 00:00:00 2001 From: temeddix Date: Fri, 7 Jun 2024 21:49:26 +0900 Subject: [PATCH 013/128] New struct `RuntimeDropper` --- rust_crate/src/macros.rs | 88 +++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 5f551f44e..a3471f262 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -37,15 +37,26 @@ macro_rules! write_interface { use tokio::sync::mpsc::channel; use tokio::sync::mpsc::{Receiver, Sender}; + // This is the runtime where async event loop runs. + type TokioRuntime = OnceLock>>; + static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); + // We use `os_thread_local` so that when the program fails // and the main thread exits unexpectedly, // the whole async tokio runtime can disappear as well. - type TokioRuntime = OnceLock>>>; - static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); + // Without this struct, zombie threads inside the runtime + // might outlive the app. + struct RuntimeDropper; + impl Drop for RuntimeDropper { + fn drop(&mut self) { + drop_tokio_runtime(); + } + } + static RUNTIME_DROPPER: OnceLock> = OnceLock::new(); // These channels are used for gracefully shutting down the tokio runtime. // Right before the topmost Flutter widget gets disposed, - // these channels will ensure that Rust logic is properly stopped. + // these channels will help ensure that Rust logic is properly stopped. struct ShutdownStore { shutdown_sender: Option>, shutdown_receiver: Option>, @@ -55,13 +66,15 @@ macro_rules! write_interface { static SHUTDOWN_STORE: ShutdownStoreShared = OnceLock::new(); pub fn get_shutdown_receiver() -> Receiver<()> { - let mut guard = SHUTDOWN_STORE - .get_or_init(|| Mutex::new(None)) - .lock() - .unwrap(); + let mut guard = SHUTDOWN_STORE.get().unwrap().lock().unwrap(); guard.as_mut().unwrap().shutdown_receiver.take().unwrap() } + fn drop_tokio_runtime() { + // Dropping the tokio runtime causes it to shut down completely. + TOKIO_RUNTIME.get().unwrap().lock().unwrap().take(); + } + #[no_mangle] pub extern "C" fn start_rust_logic_extern() { let _ = catch_unwind(|| { @@ -89,6 +102,10 @@ macro_rules! write_interface { done_receiver, }); + // Prepare to drop the async runtime + // when program fails unexpectedly. + RUNTIME_DROPPER.get_or_init(|| ThreadLocal::new(|| RuntimeDropper)); + // Run the main function. let tokio_runtime = Builder::new_multi_thread().enable_all().build().unwrap(); tokio_runtime.spawn(async move { @@ -98,40 +115,28 @@ macro_rules! write_interface { // tell the main thread to stop waiting. let _ = done_sender.send(()); }); - let os_cell = - TOKIO_RUNTIME.get_or_init(|| ThreadLocal::new(|| RefCell::new(None))); - os_cell.with(move |cell| { - // If there was already a tokio runtime previously, - // most likely due to Dart's hot restart, - // its tasks as well as itself will be terminated, - // being replaced with the new one. - cell.replace(Some(tokio_runtime)); - }); + let mut guard = TOKIO_RUNTIME + .get_or_init(|| Mutex::new(None)) + .lock() + .unwrap(); + guard.replace(tokio_runtime); }); } #[no_mangle] pub extern "C" fn stop_rust_logic_extern() { - // Tell the Rust logic to perform finalziation code. - let guard = SHUTDOWN_STORE - .get_or_init(|| Mutex::new(None)) - .lock() - .unwrap(); - let _ = guard - .as_ref() - .unwrap() - .shutdown_sender - .as_ref() - .unwrap() - .try_send(()); - let _ = guard.as_ref().unwrap().done_receiver.recv(); - // Dropping the tokio runtime causes it to shut down completely. let _ = catch_unwind(|| { - let os_cell = - TOKIO_RUNTIME.get_or_init(|| ThreadLocal::new(|| RefCell::new(None))); - os_cell.with(move |cell| { - cell.take(); - }); + // Tell the Rust logic to perform finalziation code. + let guard = SHUTDOWN_STORE.get().unwrap().lock().unwrap(); + let _ = guard + .as_ref() + .unwrap() + .shutdown_sender + .as_ref() + .unwrap() + .try_send(()); + let _ = guard.as_ref().unwrap().done_receiver.recv(); + drop_tokio_runtime(); }); } @@ -143,13 +148,14 @@ macro_rules! write_interface { binary_pointer: *const u8, binary_size: usize, ) { - let message_bytes = unsafe { - std::slice::from_raw_parts(message_pointer as *mut u8, message_size).to_vec() - }; - let binary = unsafe { - std::slice::from_raw_parts(binary_pointer as *mut u8, binary_size).to_vec() - }; let _ = catch_unwind(|| { + let message_bytes = unsafe { + std::slice::from_raw_parts(message_pointer as *mut u8, message_size) + .to_vec() + }; + let binary = unsafe { + std::slice::from_raw_parts(binary_pointer as *mut u8, binary_size).to_vec() + }; crate::messages::generated::handle_dart_signal( message_id as i32, message_bytes, From 02ecbed9aff48056a33b57b83c78dafb4e3f95a7 Mon Sep 17 00:00:00 2001 From: temeddix Date: Fri, 7 Jun 2024 21:53:05 +0900 Subject: [PATCH 014/128] Terminate tokio runtime after the main function --- rust_crate/src/macros.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index a3471f262..0ca2c868d 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -32,6 +32,7 @@ macro_rules! write_interface { use std::sync::mpsc::sync_channel; use std::sync::mpsc::Receiver as StdReceiver; use std::sync::{Mutex, OnceLock}; + use std::thread; use tokio::runtime::Builder; use tokio::runtime::Runtime; use tokio::sync::mpsc::channel; @@ -111,9 +112,13 @@ macro_rules! write_interface { tokio_runtime.spawn(async move { // Start the logic. crate::main().await; - // After the async runtime has done its job, - // tell the main thread to stop waiting. - let _ = done_sender.send(()); + // After the main function has finished, + // terminate the tokio runtime and + // tell the main thread not to wait before exit. + thread::spawn(move || { + drop_tokio_runtime(); + let _ = done_sender.send(()); + }); }); let mut guard = TOKIO_RUNTIME .get_or_init(|| Mutex::new(None)) From 550557df485ac79c0f21b683fe655fdd29c7f1ef Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 00:23:45 +0900 Subject: [PATCH 015/128] Don't send Rust signal when Dart isolate is not initialized --- rust_crate/src/interface_os.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 3add31e75..7ca44dee1 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -20,7 +20,13 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { } pub fn send_rust_signal_extern(message_id: i32, message_bytes: Vec, binary: Vec) { - let dart_isolate = DART_ISOLATE.get().unwrap().lock().unwrap().unwrap(); + // When `DART_ISOLATE` is not initialized, do nothing. + // This can happen when running test code in Rust. + let mutex = match DART_ISOLATE.get() { + Some(mutex) => mutex, + None => return, + }; + let dart_isolate = mutex.lock().unwrap().unwrap(); // If a `Vec` is empty, we can't just simply send it to Dart // because panic can occur from null pointers. From 2a1566624f36fe2bf61a2c16ec4adbe93b660f12 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 00:30:36 +0900 Subject: [PATCH 016/128] Update example and template code --- flutter_ffi_plugin/example/native/hub/src/lib.rs | 8 ++------ flutter_ffi_plugin/template/native/hub/src/lib.rs | 4 ++++ rust_crate/src/macros.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs index c45bce343..2e28b15c8 100755 --- a/flutter_ffi_plugin/example/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs @@ -18,10 +18,6 @@ async fn main() { tokio::spawn(sample_functions::tell_numbers()); tokio::spawn(sample_functions::stream_fractal()); tokio::spawn(sample_functions::run_debug_tests()); - dart_shutdown().await; - for i in 0..15 { - use std::time::Duration; - println!("SHUTDOWN {i}"); - tokio::time::sleep(Duration::from_secs(1)).await; - } + // Keep the tokio runtime alive until the widget is disposed. + widget_dispose().await; } diff --git a/flutter_ffi_plugin/template/native/hub/src/lib.rs b/flutter_ffi_plugin/template/native/hub/src/lib.rs index 393735909..46d20b0c2 100644 --- a/flutter_ffi_plugin/template/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/template/native/hub/src/lib.rs @@ -19,4 +19,8 @@ async fn main() { SmallNumber { number: 7 }.send_signal_to_dart(); // Get receivers that listen to Dart signals like below. let _ = SmallText::get_dart_signal_receiver(); + // Keep the tokio runtime alive until the widget is disposed. + widget_dispose().await; + // Perform finalization here, such as saving files. + // Ensure this process is quick to avoid blocking the screen. } diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 0ca2c868d..d357307f9 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -7,7 +7,7 @@ /// at the root of the `hub` crate. macro_rules! write_interface { () => { - async fn dart_shutdown() { + async fn widget_dispose() { #[cfg(not(target_family = "wasm"))] { // The receiver will get a signal From 7cd333b3fb67724abbb3621dd74912e621209949 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 10:17:18 +0900 Subject: [PATCH 017/128] Reduce the usage of `OnceLock` --- rust_crate/src/macros.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index d357307f9..367ca157d 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -39,8 +39,8 @@ macro_rules! write_interface { use tokio::sync::mpsc::{Receiver, Sender}; // This is the runtime where async event loop runs. - type TokioRuntime = OnceLock>>; - static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); + type TokioRuntime = Mutex>; + static TOKIO_RUNTIME: TokioRuntime = Mutex::new(None); // We use `os_thread_local` so that when the program fails // and the main thread exits unexpectedly, @@ -63,17 +63,17 @@ macro_rules! write_interface { shutdown_receiver: Option>, done_receiver: StdReceiver<()>, } - type ShutdownStoreShared = OnceLock>>; - static SHUTDOWN_STORE: ShutdownStoreShared = OnceLock::new(); + type ShutdownStoreShared = Mutex>; + static SHUTDOWN_STORE: ShutdownStoreShared = Mutex::new(None); pub fn get_shutdown_receiver() -> Receiver<()> { - let mut guard = SHUTDOWN_STORE.get().unwrap().lock().unwrap(); + let mut guard = SHUTDOWN_STORE.lock().unwrap(); guard.as_mut().unwrap().shutdown_receiver.take().unwrap() } fn drop_tokio_runtime() { // Dropping the tokio runtime causes it to shut down completely. - TOKIO_RUNTIME.get().unwrap().lock().unwrap().take(); + TOKIO_RUNTIME.lock().unwrap().take(); } #[no_mangle] @@ -93,11 +93,7 @@ macro_rules! write_interface { // Prepare to notify Dart shutdown. let (shutdown_sender, shutdown_receiver) = channel(1); let (done_sender, done_receiver) = sync_channel::<()>(1); - let mut guard = SHUTDOWN_STORE - .get_or_init(|| Mutex::new(None)) - .lock() - .unwrap(); - guard.replace(ShutdownStore { + SHUTDOWN_STORE.lock().unwrap().replace(ShutdownStore { shutdown_sender: Some(shutdown_sender), shutdown_receiver: Some(shutdown_receiver), done_receiver, @@ -120,11 +116,7 @@ macro_rules! write_interface { let _ = done_sender.send(()); }); }); - let mut guard = TOKIO_RUNTIME - .get_or_init(|| Mutex::new(None)) - .lock() - .unwrap(); - guard.replace(tokio_runtime); + TOKIO_RUNTIME.lock().unwrap().replace(tokio_runtime); }); } @@ -132,7 +124,7 @@ macro_rules! write_interface { pub extern "C" fn stop_rust_logic_extern() { let _ = catch_unwind(|| { // Tell the Rust logic to perform finalziation code. - let guard = SHUTDOWN_STORE.get().unwrap().lock().unwrap(); + let guard = SHUTDOWN_STORE.lock().unwrap(); let _ = guard .as_ref() .unwrap() From 9bf6a7a630e07aef89bee1c275e62972f145a3d9 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 11:03:44 +0900 Subject: [PATCH 018/128] Remove `stopRustLogic` --- flutter_ffi_plugin/bin/src/message.dart | 5 - flutter_ffi_plugin/example/lib/main.dart | 26 +---- .../example/native/hub/src/lib.rs | 2 - flutter_ffi_plugin/lib/rinf.dart | 10 -- flutter_ffi_plugin/lib/src/interface_os.dart | 8 -- flutter_ffi_plugin/lib/src/interface_web.dart | 4 - .../template/native/hub/src/lib.rs | 11 +- rust_crate/src/interface_os.rs | 14 +-- rust_crate/src/macros.rs | 102 +++--------------- 9 files changed, 25 insertions(+), 157 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 5782e7fdd..d1f65859f 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -502,11 +502,6 @@ Future initializeRust({String? compiledLibPath}) async { startRustLogic(); } -Future finalizeRust() async { - stopRustLogic(); - await Future.delayed(const Duration(milliseconds: 10)); -} - final signalHandlers = { '''; for (final entry in markedMessagesAll.entries) { diff --git a/flutter_ffi_plugin/example/lib/main.dart b/flutter_ffi_plugin/example/lib/main.dart index c1ac998d3..7a8fe6bd7 100755 --- a/flutter_ffi_plugin/example/lib/main.dart +++ b/flutter_ffi_plugin/example/lib/main.dart @@ -1,4 +1,3 @@ -import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:example_app/messages/generated.dart'; import 'package:example_app/messages/counter_number.pb.dart'; @@ -7,31 +6,10 @@ import 'package:example_app/messages/fractal_art.pb.dart'; void main() async { // Wait for Rust initialization to be completed first. await initializeRust(); - runApp(const MyApp()); + runApp(MyApp()); } -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final _appLifecycleListener = AppLifecycleListener( - onExitRequested: () async { - // Terminate Rust tasks before closing the Flutter app. - await finalizeRust(); - return AppExitResponse.exit; - }, - ); - - @override - void dispose() { - _appLifecycleListener.dispose(); - super.dispose(); - } - +class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs index 2e28b15c8..26bc5a855 100755 --- a/flutter_ffi_plugin/example/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs @@ -18,6 +18,4 @@ async fn main() { tokio::spawn(sample_functions::tell_numbers()); tokio::spawn(sample_functions::stream_fractal()); tokio::spawn(sample_functions::run_debug_tests()); - // Keep the tokio runtime alive until the widget is disposed. - widget_dispose().await; } diff --git a/flutter_ffi_plugin/lib/rinf.dart b/flutter_ffi_plugin/lib/rinf.dart index debb3802b..2697e92c8 100755 --- a/flutter_ffi_plugin/lib/rinf.dart +++ b/flutter_ffi_plugin/lib/rinf.dart @@ -27,16 +27,6 @@ void startRustLogic() async { startRustLogicExtern(); } -/// Terminates all Rust tasks. -/// Calling this function before closing the Flutter app -/// can prevent potential resource leaks that may occur -/// if the Rust side is abruptly terminated. -/// Please note that on the web, this function does not have any effect, -/// as tasks are managed by the JavaScript runtime, not Rust. -void stopRustLogic() async { - stopRustLogicExtern(); -} - /// Sends a signal to Rust. void sendDartSignal( int messageId, diff --git a/flutter_ffi_plugin/lib/src/interface_os.dart b/flutter_ffi_plugin/lib/src/interface_os.dart index 7407ed6b7..b3095fc58 100644 --- a/flutter_ffi_plugin/lib/src/interface_os.dart +++ b/flutter_ffi_plugin/lib/src/interface_os.dart @@ -64,14 +64,6 @@ void startRustLogicExtern() { rustFunction(); } -void stopRustLogicExtern() { - final rustFunction = - rustLibrary.lookupFunction( - 'stop_rust_logic_extern', - ); - rustFunction(); -} - /// Sends bytes to Rust. Future sendDartSignalExtern( int messageId, diff --git a/flutter_ffi_plugin/lib/src/interface_web.dart b/flutter_ffi_plugin/lib/src/interface_web.dart index 97642a4a8..c6b2d551a 100644 --- a/flutter_ffi_plugin/lib/src/interface_web.dart +++ b/flutter_ffi_plugin/lib/src/interface_web.dart @@ -41,10 +41,6 @@ void startRustLogicExtern() { jsObject.callMethod('start_rust_logic_extern', []); } -void stopRustLogicExtern() { - // Dummy function to match that of the OS module. -} - void sendDartSignalExtern( int messageId, Uint8List messageBytes, diff --git a/flutter_ffi_plugin/template/native/hub/src/lib.rs b/flutter_ffi_plugin/template/native/hub/src/lib.rs index 46d20b0c2..0a88a5ec1 100644 --- a/flutter_ffi_plugin/template/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/template/native/hub/src/lib.rs @@ -18,9 +18,10 @@ async fn main() { // Send signals to Dart like below. SmallNumber { number: 7 }.send_signal_to_dart(); // Get receivers that listen to Dart signals like below. - let _ = SmallText::get_dart_signal_receiver(); - // Keep the tokio runtime alive until the widget is disposed. - widget_dispose().await; - // Perform finalization here, such as saving files. - // Ensure this process is quick to avoid blocking the screen. + let receiver = SmallText::get_dart_signal_receiver(); + tokio::spawn(async { + while let Some(dart_signal) = receiver.recv().await { + rinf::debug_print!("{dart_signal:?}"); + } + }); } diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 7ca44dee1..57c66f71b 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -3,18 +3,14 @@ use allo_isolate::Isolate; use allo_isolate::ZeroCopyBuffer; use std::panic::catch_unwind; use std::sync::Mutex; -use std::sync::OnceLock; -static DART_ISOLATE: OnceLock>> = OnceLock::new(); +static DART_ISOLATE: Mutex> = Mutex::new(None); #[no_mangle] pub extern "C" fn prepare_isolate_extern(port: i64) { let _ = catch_unwind(|| { let dart_isolate = Isolate::new(port); - let mut guard = DART_ISOLATE - .get_or_init(|| Mutex::new(None)) - .lock() - .unwrap(); + let mut guard = DART_ISOLATE.lock().unwrap(); guard.replace(dart_isolate); }); } @@ -22,11 +18,11 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { pub fn send_rust_signal_extern(message_id: i32, message_bytes: Vec, binary: Vec) { // When `DART_ISOLATE` is not initialized, do nothing. // This can happen when running test code in Rust. - let mutex = match DART_ISOLATE.get() { - Some(mutex) => mutex, + let guard = DART_ISOLATE.lock().unwrap(); + let dart_isolate = match guard.as_ref() { + Some(inner) => inner, None => return, }; - let dart_isolate = mutex.lock().unwrap().unwrap(); // If a `Vec` is empty, we can't just simply send it to Dart // because panic can occur from null pointers. diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 367ca157d..abcc4b807 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -7,22 +7,6 @@ /// at the root of the `hub` crate. macro_rules! write_interface { () => { - async fn widget_dispose() { - #[cfg(not(target_family = "wasm"))] - { - // The receiver will get a signal - // while the topmost Flutter widget is getting disposed. - let mut shutdown_receiver = interface_os::get_shutdown_receiver(); - shutdown_receiver.recv().await; - } - #[cfg(target_family = "wasm")] - { - // The receiver will wait forever because it never gets a message. - let (_sender, receiver) = tokio::sync::oneshot::channel::<()>(); - let _ = receiver.await; - } - } - #[cfg(not(target_family = "wasm"))] mod interface_os { use crate::tokio; @@ -38,43 +22,13 @@ macro_rules! write_interface { use tokio::sync::mpsc::channel; use tokio::sync::mpsc::{Receiver, Sender}; - // This is the runtime where async event loop runs. - type TokioRuntime = Mutex>; - static TOKIO_RUNTIME: TokioRuntime = Mutex::new(None); - // We use `os_thread_local` so that when the program fails // and the main thread exits unexpectedly, // the whole async tokio runtime can disappear as well. - // Without this struct, zombie threads inside the runtime + // Without this solution, zombie threads inside the runtime // might outlive the app. - struct RuntimeDropper; - impl Drop for RuntimeDropper { - fn drop(&mut self) { - drop_tokio_runtime(); - } - } - static RUNTIME_DROPPER: OnceLock> = OnceLock::new(); - - // These channels are used for gracefully shutting down the tokio runtime. - // Right before the topmost Flutter widget gets disposed, - // these channels will help ensure that Rust logic is properly stopped. - struct ShutdownStore { - shutdown_sender: Option>, - shutdown_receiver: Option>, - done_receiver: StdReceiver<()>, - } - type ShutdownStoreShared = Mutex>; - static SHUTDOWN_STORE: ShutdownStoreShared = Mutex::new(None); - - pub fn get_shutdown_receiver() -> Receiver<()> { - let mut guard = SHUTDOWN_STORE.lock().unwrap(); - guard.as_mut().unwrap().shutdown_receiver.take().unwrap() - } - - fn drop_tokio_runtime() { - // Dropping the tokio runtime causes it to shut down completely. - TOKIO_RUNTIME.lock().unwrap().take(); - } + type TokioRuntime = OnceLock>>>; + static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); #[no_mangle] pub extern "C" fn start_rust_logic_extern() { @@ -90,50 +44,18 @@ macro_rules! write_interface { })); } - // Prepare to notify Dart shutdown. - let (shutdown_sender, shutdown_receiver) = channel(1); - let (done_sender, done_receiver) = sync_channel::<()>(1); - SHUTDOWN_STORE.lock().unwrap().replace(ShutdownStore { - shutdown_sender: Some(shutdown_sender), - shutdown_receiver: Some(shutdown_receiver), - done_receiver, - }); - - // Prepare to drop the async runtime - // when program fails unexpectedly. - RUNTIME_DROPPER.get_or_init(|| ThreadLocal::new(|| RuntimeDropper)); - // Run the main function. let tokio_runtime = Builder::new_multi_thread().enable_all().build().unwrap(); - tokio_runtime.spawn(async move { - // Start the logic. - crate::main().await; - // After the main function has finished, - // terminate the tokio runtime and - // tell the main thread not to wait before exit. - thread::spawn(move || { - drop_tokio_runtime(); - let _ = done_sender.send(()); + tokio_runtime.spawn(crate::main()); + TOKIO_RUNTIME + .get_or_init(|| ThreadLocal::new(|| RefCell::new(None))) + .with(move |cell| { + // If there was already a tokio runtime previously, + // most likely due to Dart's hot restart, + // its tasks as well as itself will be terminated, + // being replaced with the new one. + cell.replace(Some(tokio_runtime)); }); - }); - TOKIO_RUNTIME.lock().unwrap().replace(tokio_runtime); - }); - } - - #[no_mangle] - pub extern "C" fn stop_rust_logic_extern() { - let _ = catch_unwind(|| { - // Tell the Rust logic to perform finalziation code. - let guard = SHUTDOWN_STORE.lock().unwrap(); - let _ = guard - .as_ref() - .unwrap() - .shutdown_sender - .as_ref() - .unwrap() - .try_send(()); - let _ = guard.as_ref().unwrap().done_receiver.recv(); - drop_tokio_runtime(); }); } From e6c9b9786417b53b66b0ad1baa4e9b170d972350 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 11:13:12 +0900 Subject: [PATCH 019/128] Do not use `OnceLock` with generated channels --- flutter_ffi_plugin/bin/src/message.dart | 39 ++++++++----------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index d1f65859f..97433bed8 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -251,7 +251,6 @@ use prost::Message; use rinf::send_rust_signal; use rinf::DartSignal; use std::sync::Mutex; -use std::sync::OnceLock; use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::UnboundedReceiver; use tokio::sync::mpsc::UnboundedSender; @@ -270,22 +269,16 @@ use tokio::sync::mpsc::UnboundedSender; await insertTextToFile( rustPath, ''' -type ${messageName}Cell = OnceLock>>, Option>>, -)>>>; +)>>; pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = - OnceLock::new(); + Mutex::new(None); impl ${normalizePascal(messageName)} { pub fn get_dart_signal_receiver() -> UnboundedReceiver> { - let mut guard = ${snakeName.toUpperCase()}_CHANNEL - .get_or_init(|| { - let (sender, receiver) = unbounded_channel(); - Mutex::new(Some((Some(sender), Some(receiver)))) - }) - .lock() - .unwrap(); + let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock().unwrap(); #[cfg(debug_assertions)] { // After Dart's hot restart, @@ -402,12 +395,11 @@ use prost::Message; use rinf::debug_print; use rinf::DartSignal; use std::collections::HashMap; -use std::sync::Mutex; use std::sync::OnceLock; use tokio::sync::mpsc::unbounded_channel; type SignalHandlers = - OnceLock, Vec) + Send>>>>; + OnceLock, Vec) + Send + Sync>>>; static SIGNAL_HANDLERS: SignalHandlers = OnceLock::new(); pub fn handle_dart_signal( @@ -415,10 +407,10 @@ pub fn handle_dart_signal( message_bytes: Vec, binary: Vec ) { - let mutex = SIGNAL_HANDLERS.get_or_init(|| { - let mut hash_map = + let hash_map = SIGNAL_HANDLERS.get_or_init(|| { + let mut new_hash_map = HashMap - ::, Vec) + Send + 'static>> + ::, Vec) + Send + Sync>> ::new(); '''; for (final entry in markedMessagesAll.entries) { @@ -436,7 +428,7 @@ pub fn handle_dart_signal( var modulePath = subpath.replaceAll("/", "::"); modulePath = modulePath == "::" ? "" : modulePath; rustReceiveScript += ''' -hash_map.insert( +new_hash_map.insert( ${markedMessage.id}, Box::new(|message_bytes: Vec, binary: Vec| { use super::$modulePath$filename::*; @@ -447,13 +439,7 @@ hash_map.insert( message, binary, }; - let mut guard = ${snakeName.toUpperCase()}_CHANNEL - .get_or_init(|| { - let (sender, receiver) = unbounded_channel(); - Mutex::new(Some((Some(sender), Some(receiver)))) - }) - .lock() - .unwrap(); + let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock().unwrap(); #[cfg(debug_assertions)] { // After Dart's hot restart, @@ -477,11 +463,10 @@ hash_map.insert( } } rustReceiveScript += ''' - Mutex::new(hash_map) + new_hash_map }); - let guard = mutex.lock().unwrap(); - let signal_handler = guard.get(&message_id).unwrap(); + let signal_handler = hash_map.get(&message_id).unwrap(); signal_handler(message_bytes, binary); } '''; From 4df0b407ffddf5a2d932a2c2d55f65124688eb26 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 12:52:31 +0900 Subject: [PATCH 020/128] Fix message generation --- flutter_ffi_plugin/bin/src/message.dart | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 97433bed8..321c5c58b 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -279,14 +279,16 @@ pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = impl ${normalizePascal(messageName)} { pub fn get_dart_signal_receiver() -> UnboundedReceiver> { let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock().unwrap(); + if guard.is_none() { + let (sender, receiver) = unbounded_channel(); + guard.replace((Some(sender), Some(receiver))); + } #[cfg(debug_assertions)] { // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - let pair = guard.as_ref().unwrap(); - let is_closed = pair.0.as_ref().unwrap().is_closed(); - if is_closed { + if guard.as_ref().unwrap().0.as_ref().unwrap().is_closed() { let (sender, receiver) = unbounded_channel(); guard.replace((Some(sender), Some(receiver))); } @@ -440,14 +442,16 @@ new_hash_map.insert( binary, }; let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock().unwrap(); + if guard.is_none() { + let (sender, receiver) = unbounded_channel(); + guard.replace((Some(sender), Some(receiver))); + } #[cfg(debug_assertions)] { // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - let pair = guard.as_ref().unwrap(); - let is_closed = pair.0.as_ref().unwrap().is_closed(); - if is_closed { + if guard.as_ref().unwrap().0.as_ref().unwrap().is_closed() { let (sender, receiver) = unbounded_channel(); guard.replace((Some(sender), Some(receiver))); } From 5fa785f042c405cbadaed8d1db8d6555137678d8 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 13:07:05 +0900 Subject: [PATCH 021/128] Reduce `write_interface` macro code --- .../example/native/hub/Cargo.toml | 1 + .../template/native/hub/Cargo.toml | 2 +- rust_crate/Cargo.toml | 2 + rust_crate/src/interface.rs | 9 ++ rust_crate/src/interface_os.rs | 47 +++++- rust_crate/src/interface_web.rs | 19 +++ rust_crate/src/macros.rs | 138 +++++------------- 7 files changed, 108 insertions(+), 110 deletions(-) diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index 522c8f6a9..90741f90f 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -14,6 +14,7 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] rinf = "6.11.1" prost = "0.12.3" +# tokio = { version = "1", features = ["sync"] } wasm-bindgen = "0.2.92" # Uncomment this line to target the web tokio_with_wasm = "0.4.4" # Uncomment this line to target the web sample_crate = { path = "../sample_crate" } diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index ab480ee8c..a9f5a4695 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -14,6 +14,6 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] rinf = "6.11.1" prost = "0.12.3" -tokio = { version = "1", features = ["rt-multi-thread", "sync", "macros"] } +tokio = { version = "1", features = ["sync"] } # wasm-bindgen = "0.2.92" # Uncomment this line to target the web # tokio_with_wasm = "0.4.4" # Uncomment this line to target the web diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index af011344f..89713e869 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -15,7 +15,9 @@ protoc-prebuilt = "0.3.0" home = "0.5.9" which = "6.0.0" allo-isolate = "0.1.24" +tokio = { version = "1", features = ["rt-multi-thread"] } [target.'cfg(target_family = "wasm")'.dependencies] js-sys = "0.3.69" wasm-bindgen = "0.2.92" +wasm-bindgen-futures = "0.4.42" diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index b13a732a5..a07105e27 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -1,3 +1,5 @@ +use std::future::Future; + #[cfg(not(target_family = "wasm"))] use super::interface_os::*; #[cfg(target_family = "wasm")] @@ -16,3 +18,10 @@ pub struct DartSignal { pub fn send_rust_signal(message_id: i32, message_bytes: Vec, binary: Vec) { send_rust_signal_extern(message_id, message_bytes, binary); } + +pub fn start_rust_logic(main_future: F) +where + F: Future + Send + 'static, +{ + start_rust_logic_extern(main_future); +} diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 57c66f71b..19a2804f1 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -1,8 +1,12 @@ -use allo_isolate::IntoDart; -use allo_isolate::Isolate; -use allo_isolate::ZeroCopyBuffer; +use crate::debug_print; +use allo_isolate::{IntoDart, Isolate, ZeroCopyBuffer}; +use backtrace::Backtrace; +use os_thread_local::ThreadLocal; +use std::cell::RefCell; +use std::future::Future; use std::panic::catch_unwind; -use std::sync::Mutex; +use std::sync::{Mutex, OnceLock}; +use tokio::runtime::{Builder, Runtime}; static DART_ISOLATE: Mutex> = Mutex::new(None); @@ -15,6 +19,41 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { }); } +// We use `os_thread_local` so that when the program fails +// and the main thread exits unexpectedly, +// the whole async tokio runtime can disappear as well. +// Without this solution, zombie threads inside the runtime +// might outlive the app. +type TokioRuntime = OnceLock>>>; +static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); + +pub fn start_rust_logic_extern(main_future: F) +where + F: Future + Send + 'static, +{ + // Enable backtrace output for panics. + #[cfg(debug_assertions)] + { + std::panic::set_hook(Box::new(|panic_info| { + let backtrace = Backtrace::new(); + debug_print!("A panic occurred in Rust.\n{panic_info}\n{backtrace:?}"); + })); + } + + // Run the main function. + let tokio_runtime = Builder::new_multi_thread().enable_all().build().unwrap(); + tokio_runtime.spawn(main_future); + TOKIO_RUNTIME + .get_or_init(|| ThreadLocal::new(|| RefCell::new(None))) + .with(move |cell| { + // If there was already a tokio runtime previously, + // most likely due to Dart's hot restart, + // its tasks as well as itself will be terminated, + // being replaced with the new one. + cell.replace(Some(tokio_runtime)); + }); +} + pub fn send_rust_signal_extern(message_id: i32, message_bytes: Vec, binary: Vec) { // When `DART_ISOLATE` is not initialized, do nothing. // This can happen when running test code in Rust. diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index f3179ff89..6e68d7cd0 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -1,5 +1,24 @@ +use crate::debug_print; use js_sys::Uint8Array; +use std::future::Future; use wasm_bindgen::prelude::*; +use wasm_bindgen_futures::spawn_local; + +pub fn start_rust_logic_extern(main_future: F) +where + F: Future + Send + 'static, +{ + // Add kind description for panics. + #[cfg(debug_assertions)] + { + std::panic::set_hook(Box::new(|panic_info| { + debug_print!("A panic occurred in Rust.\n{panic_info}"); + })); + } + + // Run the main function. + spawn_local(main_future); +} #[wasm_bindgen] extern "C" { diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index abcc4b807..54913f2fd 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -8,117 +8,45 @@ macro_rules! write_interface { () => { #[cfg(not(target_family = "wasm"))] - mod interface_os { - use crate::tokio; - use rinf::externs::os_thread_local::ThreadLocal; - use std::cell::RefCell; - use std::panic::catch_unwind; - use std::sync::mpsc::sync_channel; - use std::sync::mpsc::Receiver as StdReceiver; - use std::sync::{Mutex, OnceLock}; - use std::thread; - use tokio::runtime::Builder; - use tokio::runtime::Runtime; - use tokio::sync::mpsc::channel; - use tokio::sync::mpsc::{Receiver, Sender}; - - // We use `os_thread_local` so that when the program fails - // and the main thread exits unexpectedly, - // the whole async tokio runtime can disappear as well. - // Without this solution, zombie threads inside the runtime - // might outlive the app. - type TokioRuntime = OnceLock>>>; - static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); - - #[no_mangle] - pub extern "C" fn start_rust_logic_extern() { - let _ = catch_unwind(|| { - // Enable backtrace output for panics. - #[cfg(debug_assertions)] - { - use rinf::debug_print; - use rinf::externs::backtrace::Backtrace; - std::panic::set_hook(Box::new(|panic_info| { - let backtrace = Backtrace::new(); - debug_print!("A panic occurred in Rust.\n{panic_info}\n{backtrace:?}"); - })); - } - - // Run the main function. - let tokio_runtime = Builder::new_multi_thread().enable_all().build().unwrap(); - tokio_runtime.spawn(crate::main()); - TOKIO_RUNTIME - .get_or_init(|| ThreadLocal::new(|| RefCell::new(None))) - .with(move |cell| { - // If there was already a tokio runtime previously, - // most likely due to Dart's hot restart, - // its tasks as well as itself will be terminated, - // being replaced with the new one. - cell.replace(Some(tokio_runtime)); - }); - }); - } - - #[no_mangle] - pub extern "C" fn send_dart_signal_extern( - message_id: i64, - message_pointer: *const u8, - message_size: usize, - binary_pointer: *const u8, - binary_size: usize, - ) { - let _ = catch_unwind(|| { - let message_bytes = unsafe { - std::slice::from_raw_parts(message_pointer as *mut u8, message_size) - .to_vec() - }; - let binary = unsafe { - std::slice::from_raw_parts(binary_pointer as *mut u8, binary_size).to_vec() - }; - crate::messages::generated::handle_dart_signal( - message_id as i32, - message_bytes, - binary, - ); - }); - } + #[no_mangle] + pub extern "C" fn start_rust_logic_extern() { + let _ = std::panic::catch_unwind(|| $crate::start_rust_logic(main())); } #[cfg(target_family = "wasm")] - mod interface_web { - use crate::tokio; - use std::panic::catch_unwind; - use wasm_bindgen::prelude::wasm_bindgen; - - #[wasm_bindgen] - pub fn start_rust_logic_extern() { - let _ = catch_unwind(|| { - // Add kind description for panics. - #[cfg(debug_assertions)] - { - use rinf::debug_print; - std::panic::set_hook(Box::new(|panic_info| { - debug_print!("A panic occurred in Rust.\n{panic_info}"); - })); - } + #[wasm_bindgen::prelude::wasm_bindgen] + pub fn start_rust_logic_extern() { + let _ = std::panic::catch_unwind(|| $crate::start_rust_logic(main())); + } - // Run the main function. - tokio::spawn(crate::main()); - }); - } + #[cfg(not(target_family = "wasm"))] + #[no_mangle] + pub extern "C" fn send_dart_signal_extern( + message_id: i64, + message_pointer: *const u8, + message_size: usize, + binary_pointer: *const u8, + binary_size: usize, + ) { + let _ = std::panic::catch_unwind(|| { + let message_bytes = unsafe { + std::slice::from_raw_parts(message_pointer as *mut u8, message_size).to_vec() + }; + let binary = unsafe { + std::slice::from_raw_parts(binary_pointer as *mut u8, binary_size).to_vec() + }; + messages::generated::handle_dart_signal(message_id as i32, message_bytes, binary); + }); + } - #[wasm_bindgen] - pub fn send_dart_signal_extern(message_id: i32, message_bytes: &[u8], binary: &[u8]) { + #[cfg(target_family = "wasm")] + #[wasm_bindgen::prelude::wasm_bindgen] + pub fn send_dart_signal_extern(message_id: i32, message_bytes: &[u8], binary: &[u8]) { + let _ = std::panic::catch_unwind(|| { let message_bytes = message_bytes.to_vec(); let binary = binary.to_vec(); - let _ = catch_unwind(|| { - crate::messages::generated::handle_dart_signal( - message_id, - message_bytes, - binary, - ); - }); - } + messages::generated::handle_dart_signal(message_id, message_bytes, binary); + }); } }; } @@ -134,7 +62,7 @@ macro_rules! debug_print { ( $( $t:tt )* ) => { let rust_report = format!( $( $t )* ); #[cfg(debug_assertions)] - rinf::send_rust_signal( + $crate::send_rust_signal( -1, // This is a special message ID for Rust reports Vec::new(), rust_report.into_bytes(), From a28b35f36e39ab304065edf1f179dd2ce71d81ea Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 14:08:12 +0900 Subject: [PATCH 022/128] Add a debug message --- rust_crate/src/interface_os.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 19a2804f1..c3af9be1d 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -60,7 +60,10 @@ pub fn send_rust_signal_extern(message_id: i32, message_bytes: Vec, binary: let guard = DART_ISOLATE.lock().unwrap(); let dart_isolate = match guard.as_ref() { Some(inner) => inner, - None => return, + None => { + debug_print!("Dart isolate is not present."); + return; + } }; // If a `Vec` is empty, we can't just simply send it to Dart From 7cb2ad2d6557303dac826b705b927c79224f4c01 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 14:09:20 +0900 Subject: [PATCH 023/128] Clarify a comment --- rust_crate/src/interface_os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index c3af9be1d..1374a873a 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -22,7 +22,7 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { // We use `os_thread_local` so that when the program fails // and the main thread exits unexpectedly, // the whole async tokio runtime can disappear as well. -// Without this solution, zombie threads inside the runtime +// Without this solution, zombie threads inside the tokio runtime // might outlive the app. type TokioRuntime = OnceLock>>>; static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); From 9fa605b137fe4e0f41cdc363d6ba7784959bf8c3 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 14:21:15 +0900 Subject: [PATCH 024/128] Rename and organize modules --- rust_crate/src/externs.rs | 4 ---- rust_crate/src/interface.rs | 4 ++-- rust_crate/src/interface_os.rs | 4 ++-- rust_crate/src/interface_web.rs | 14 +++++--------- rust_crate/src/lib.rs | 5 ++--- 5 files changed, 11 insertions(+), 20 deletions(-) delete mode 100644 rust_crate/src/externs.rs diff --git a/rust_crate/src/externs.rs b/rust_crate/src/externs.rs deleted file mode 100644 index 9f39fa081..000000000 --- a/rust_crate/src/externs.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg(not(target_family = "wasm"))] -pub use backtrace; -#[cfg(not(target_family = "wasm"))] -pub use os_thread_local; diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index a07105e27..515fb3ac7 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -16,12 +16,12 @@ pub struct DartSignal { /// Send a signal to Dart. pub fn send_rust_signal(message_id: i32, message_bytes: Vec, binary: Vec) { - send_rust_signal_extern(message_id, message_bytes, binary); + send_rust_signal_real(message_id, message_bytes, binary); } pub fn start_rust_logic(main_future: F) where F: Future + Send + 'static, { - start_rust_logic_extern(main_future); + start_rust_logic_real(main_future); } diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 1374a873a..fa05afecb 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -27,7 +27,7 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { type TokioRuntime = OnceLock>>>; static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); -pub fn start_rust_logic_extern(main_future: F) +pub fn start_rust_logic_real(main_future: F) where F: Future + Send + 'static, { @@ -54,7 +54,7 @@ where }); } -pub fn send_rust_signal_extern(message_id: i32, message_bytes: Vec, binary: Vec) { +pub fn send_rust_signal_real(message_id: i32, message_bytes: Vec, binary: Vec) { // When `DART_ISOLATE` is not initialized, do nothing. // This can happen when running test code in Rust. let guard = DART_ISOLATE.lock().unwrap(); diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index 6e68d7cd0..ab34c49a9 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -4,7 +4,7 @@ use std::future::Future; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::spawn_local; -pub fn start_rust_logic_extern(main_future: F) +pub fn start_rust_logic_real(main_future: F) where F: Future + Send + 'static, { @@ -22,16 +22,12 @@ where #[wasm_bindgen] extern "C" { - #[wasm_bindgen(js_namespace = rinf, js_name = send_rust_signal_extern)] - pub fn send_rust_signal_extern_raw( - resource: i32, - message_bytes: Uint8Array, - binary: Uint8Array, - ); + #[wasm_bindgen(js_namespace = rinf)] + pub fn send_rust_signal_extern(resource: i32, message_bytes: Uint8Array, binary: Uint8Array); } -pub fn send_rust_signal_extern(message_id: i32, message_bytes: Vec, binary: Vec) { - send_rust_signal_extern_raw( +pub fn send_rust_signal_real(message_id: i32, message_bytes: Vec, binary: Vec) { + send_rust_signal_extern( message_id, js_sys::Uint8Array::from(message_bytes.as_slice()), js_sys::Uint8Array::from(binary.as_slice()), diff --git a/rust_crate/src/lib.rs b/rust_crate/src/lib.rs index 07b839796..cceb7e5b9 100644 --- a/rust_crate/src/lib.rs +++ b/rust_crate/src/lib.rs @@ -1,6 +1,3 @@ -pub use interface::*; - -pub mod externs; mod macros; mod interface; @@ -8,3 +5,5 @@ mod interface; mod interface_os; #[cfg(target_family = "wasm")] mod interface_web; + +pub use interface::*; From d15829eaed5152f029072da4a9d53f9e7ca2774f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 15:39:44 +0900 Subject: [PATCH 025/128] Rename internal methods --- flutter_ffi_plugin/lib/rinf.dart | 8 ++++---- flutter_ffi_plugin/lib/src/interface_os.dart | 12 ++++++------ flutter_ffi_plugin/lib/src/interface_web.dart | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/flutter_ffi_plugin/lib/rinf.dart b/flutter_ffi_plugin/lib/rinf.dart index 2697e92c8..41ae39841 100755 --- a/flutter_ffi_plugin/lib/rinf.dart +++ b/flutter_ffi_plugin/lib/rinf.dart @@ -13,18 +13,18 @@ export 'src/interface.dart' show RustSignal; /// This function might not be necessary for major platforms /// but can be useful when the app runs on embedded devices. void setCompiledLibPath(String? path) { - setCompiledLibPathExtern(path); + setCompiledLibPathReal(path); } /// Prepares the native interface /// needed to communicate with Rust. Future prepareInterface(HandleRustSignal handleRustSignal) async { - await prepareInterfaceExtern(handleRustSignal); + await prepareInterfaceReal(handleRustSignal); } /// Starts the `main` function in Rust. void startRustLogic() async { - startRustLogicExtern(); + startRustLogicReal(); } /// Sends a signal to Rust. @@ -33,7 +33,7 @@ void sendDartSignal( Uint8List messageBytes, Uint8List binary, ) async { - sendDartSignalExtern( + sendDartSignalReal( messageId, messageBytes, binary, diff --git a/flutter_ffi_plugin/lib/src/interface_os.dart b/flutter_ffi_plugin/lib/src/interface_os.dart index b3095fc58..781b19291 100644 --- a/flutter_ffi_plugin/lib/src/interface_os.dart +++ b/flutter_ffi_plugin/lib/src/interface_os.dart @@ -7,11 +7,11 @@ import 'dart:isolate'; import 'interface.dart'; import 'dart:convert'; -void setCompiledLibPathExtern(String? path) { +void setCompiledLibPathReal(String? path) { setDynamicLibPath(path); } -Future prepareInterfaceExtern( +Future prepareInterfaceReal( HandleRustSignal handleRustSignal, ) async { /// This should be called once at startup @@ -53,10 +53,10 @@ Future prepareInterfaceExtern( }); // Make Rust prepare its isolate to send data to Dart. - prepareIsolateExtern(rustSignalPort.sendPort.nativePort); + prepareIsolateReal(rustSignalPort.sendPort.nativePort); } -void startRustLogicExtern() { +void startRustLogicReal() { final rustFunction = rustLibrary.lookupFunction( 'start_rust_logic_extern', @@ -65,7 +65,7 @@ void startRustLogicExtern() { } /// Sends bytes to Rust. -Future sendDartSignalExtern( +Future sendDartSignalReal( int messageId, Uint8List messageBytes, Uint8List binary, @@ -104,7 +104,7 @@ Future sendDartSignalExtern( malloc.free(binaryMemory); } -void prepareIsolateExtern(int port) { +void prepareIsolateReal(int port) { final rustFunction = rustLibrary.lookupFunction< Void Function( IntPtr, diff --git a/flutter_ffi_plugin/lib/src/interface_web.dart b/flutter_ffi_plugin/lib/src/interface_web.dart index c6b2d551a..4e1fb016e 100644 --- a/flutter_ffi_plugin/lib/src/interface_web.dart +++ b/flutter_ffi_plugin/lib/src/interface_web.dart @@ -7,11 +7,11 @@ import 'interface.dart'; import 'dart:async'; import 'dart:convert'; -void setCompiledLibPathExtern(String? path) { +void setCompiledLibPathReal(String? path) { setJsLibPath(path); } -Future prepareInterfaceExtern( +Future prepareInterfaceReal( HandleRustSignal handleRustSignal, ) async { await loadJsFile(); @@ -33,7 +33,7 @@ Future prepareInterfaceExtern( }; } -void startRustLogicExtern() { +void startRustLogicReal() { if (wasAlreadyLoaded) { return; } @@ -41,7 +41,7 @@ void startRustLogicExtern() { jsObject.callMethod('start_rust_logic_extern', []); } -void sendDartSignalExtern( +void sendDartSignalReal( int messageId, Uint8List messageBytes, Uint8List binary, From 003bbf1fd4a2b44d6a47046d2bb877bfb0bd658c Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 15:43:23 +0900 Subject: [PATCH 026/128] Update HTML file with latest Flutter template --- flutter_ffi_plugin/example/web/index.html | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/flutter_ffi_plugin/example/web/index.html b/flutter_ffi_plugin/example/web/index.html index be820e83e..1aa025dd6 100755 --- a/flutter_ffi_plugin/example/web/index.html +++ b/flutter_ffi_plugin/example/web/index.html @@ -31,29 +31,8 @@ example - - - - - + From 79d87c8f0dc492d501b91736191ae1ce72c887df Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 15:50:42 +0900 Subject: [PATCH 027/128] Improve template code --- flutter_ffi_plugin/template/native/hub/src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/flutter_ffi_plugin/template/native/hub/src/lib.rs b/flutter_ffi_plugin/template/native/hub/src/lib.rs index 0a88a5ec1..95dad9a99 100644 --- a/flutter_ffi_plugin/template/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/template/native/hub/src/lib.rs @@ -19,9 +19,8 @@ async fn main() { SmallNumber { number: 7 }.send_signal_to_dart(); // Get receivers that listen to Dart signals like below. let receiver = SmallText::get_dart_signal_receiver(); - tokio::spawn(async { - while let Some(dart_signal) = receiver.recv().await { - rinf::debug_print!("{dart_signal:?}"); - } - }); + while let Some(dart_signal) = receiver.recv().await { + let message: SmallText = dart_signal.message; + rinf::debug_print!("{message:?}"); + } } From f52b2924828f081cce50ee1126663d5b456a2d3a Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 15:52:38 +0900 Subject: [PATCH 028/128] Fix a small bug --- flutter_ffi_plugin/template/native/hub/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/template/native/hub/src/lib.rs b/flutter_ffi_plugin/template/native/hub/src/lib.rs index 95dad9a99..e1a12658b 100644 --- a/flutter_ffi_plugin/template/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/template/native/hub/src/lib.rs @@ -18,7 +18,7 @@ async fn main() { // Send signals to Dart like below. SmallNumber { number: 7 }.send_signal_to_dart(); // Get receivers that listen to Dart signals like below. - let receiver = SmallText::get_dart_signal_receiver(); + let mut receiver = SmallText::get_dart_signal_receiver(); while let Some(dart_signal) = receiver.recv().await { let message: SmallText = dart_signal.message; rinf::debug_print!("{message:?}"); From eb86199c0de3a1948dfd6124544782e26a5b1aac Mon Sep 17 00:00:00 2001 From: Kim Dong-Hyun Date: Sat, 8 Jun 2024 15:58:37 +0900 Subject: [PATCH 029/128] Update Apple config files --- flutter_ffi_plugin/example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../example/macos/Runner.xcodeproj/project.pbxproj | 2 +- .../Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/flutter_ffi_plugin/example/ios/Runner.xcodeproj/project.pbxproj b/flutter_ffi_plugin/example/ios/Runner.xcodeproj/project.pbxproj index c4f6c96cd..573d57482 100755 --- a/flutter_ffi_plugin/example/ios/Runner.xcodeproj/project.pbxproj +++ b/flutter_ffi_plugin/example/ios/Runner.xcodeproj/project.pbxproj @@ -215,7 +215,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C8080294A63A400263BE5 = { diff --git a/flutter_ffi_plugin/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_ffi_plugin/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 87131a09b..8e3ca5dfe 100755 --- a/flutter_ffi_plugin/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/flutter_ffi_plugin/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Sat, 8 Jun 2024 16:05:27 +0900 Subject: [PATCH 030/128] Remove unneeded cast --- rust_crate/src/macros.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 54913f2fd..dc2060d8c 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -29,12 +29,10 @@ macro_rules! write_interface { binary_size: usize, ) { let _ = std::panic::catch_unwind(|| { - let message_bytes = unsafe { - std::slice::from_raw_parts(message_pointer as *mut u8, message_size).to_vec() - }; - let binary = unsafe { - std::slice::from_raw_parts(binary_pointer as *mut u8, binary_size).to_vec() - }; + let message_bytes = + unsafe { std::slice::from_raw_parts(message_pointer, message_size).to_vec() }; + let binary = + unsafe { std::slice::from_raw_parts(binary_pointer, binary_size).to_vec() }; messages::generated::handle_dart_signal(message_id as i32, message_bytes, binary); }); } From 17c00f3bca0442f1dcaadc8640b48b359632ad3a Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 16:07:12 +0900 Subject: [PATCH 031/128] Add a comment --- rust_crate/src/interface.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index 515fb3ac7..27ba04207 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -19,6 +19,7 @@ pub fn send_rust_signal(message_id: i32, message_bytes: Vec, binary: Vec send_rust_signal_real(message_id, message_bytes, binary); } +/// Runs the main function in Rust. pub fn start_rust_logic(main_future: F) where F: Future + Send + 'static, From 16bf4d6aa7ebb1d847fae8ea8bae2e9d4ca4520f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 16:16:23 +0900 Subject: [PATCH 032/128] Remove unused imports from generated code --- flutter_ffi_plugin/bin/src/message.dart | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 321c5c58b..0acaef5d7 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -248,12 +248,9 @@ import 'package:rinf/rinf.dart'; use crate::tokio; use prost::Message; -use rinf::send_rust_signal; -use rinf::DartSignal; +use rinf::{send_rust_signal, DartSignal}; use std::sync::Mutex; -use tokio::sync::mpsc::unbounded_channel; -use tokio::sync::mpsc::UnboundedReceiver; -use tokio::sync::mpsc::UnboundedSender; +use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; ''', atFront: true, ); @@ -394,7 +391,6 @@ impl ${normalizePascal(messageName)} { use crate::tokio; use prost::Message; -use rinf::debug_print; use rinf::DartSignal; use std::collections::HashMap; use std::sync::OnceLock; From a9a844eb9ca75d1347eb91fbfd6f935ec7043081 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 16:24:23 +0900 Subject: [PATCH 033/128] Improve a debugging message --- rust_crate/src/interface_os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index fa05afecb..395143ee1 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -61,7 +61,7 @@ pub fn send_rust_signal_real(message_id: i32, message_bytes: Vec, binary: Ve let dart_isolate = match guard.as_ref() { Some(inner) => inner, None => { - debug_print!("Dart isolate is not present."); + debug_print!("Dart isolate for sending Rust signals is not present."); return; } }; From 74d5ef6645c9223b519d0885a969a471e11cb53f Mon Sep 17 00:00:00 2001 From: Kim Dong-Hyun Date: Sat, 8 Jun 2024 19:13:14 +0900 Subject: [PATCH 034/128] Apply latest Flutter Android config without `Math.max` --- flutter_ffi_plugin/android/build.gradle | 75 ++++++++++++------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/flutter_ffi_plugin/android/build.gradle b/flutter_ffi_plugin/android/build.gradle index cc1414680..123deb834 100755 --- a/flutter_ffi_plugin/android/build.gradle +++ b/flutter_ffi_plugin/android/build.gradle @@ -1,70 +1,69 @@ -// The Android Gradle Plugin builds the native code with the Android NDK. - -group 'com.cunarist.rinf' -version '1.0' +group = "com.cunarist.rinf" +version = "1.0-SNAPSHOT" buildscript { + ext.kotlin_version = "1.7.10" repositories { google() mavenCentral() } dependencies { - // The Android Gradle Plugin knows how to build native code with the NDK. - classpath 'com.android.tools.build:gradle:7.3.0' + classpath("com.android.tools.build:gradle:7.3.0") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() } } -apply plugin: 'com.android.library' - -// SDK Version 34 is the LTS as of now, till Flutter upgrades -// There are also deprecated attributes, this takes all of them into account -def compileSdkVersion = Math.max(android.compileSdkVersion, android.compileSdk, 31).toInteger() -// Defaults to the 16 if nothing is specified, or else overrides from the parent -def minSdkVersion = Math.max(android.minSdkVersion, android.minSdk, 16).toInteger() +apply plugin: "com.android.library" +apply plugin: "kotlin-android" android { if (project.android.hasProperty("namespace")) { - namespace 'com.cunarist.rinf' + namespace = "com.cunarist.rinf" } - // Bumping the plugin compileSdkVersion requires all clients of this plugin - // to bump the version in their app. - compileSdkVersion compileSdkVersion + compileSdk = 34 - // Simply use the `android.ndkVersion` - // declared in the `./android/app/build.gradle` file of the Flutter project. - ndkVersion android.ndkVersion - - // Invoke the shared CMake build with the Android Gradle Plugin. - externalNativeBuild { - cmake { - path "../src/CMakeLists.txt" + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } - // The default CMake version for the Android Gradle Plugin is 3.10.2. - // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake - // - // The Flutter tooling requires that developers have CMake 3.10 or later - // installed. You should not increase this version, as doing so will cause - // the plugin to fail to compile for some customers of the plugin. - // version "3.10.2" - } + kotlinOptions { + jvmTarget = "1.8" } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceSets { + main.java.srcDirs += "src/main/kotlin" + test.java.srcDirs += "src/test/kotlin" } defaultConfig { - minSdkVersion minSdkVersion + minSdk = 21 + } + + dependencies { + testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation("org.mockito:mockito-core:5.0.0") + } + + testOptions { + unitTests.all { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed", "standardOut", "standardError" + outputs.upToDateWhen {false} + showStandardStreams = true + } + } } } From 608665a9e5eff079e3e73565faef876b8f90bf6c Mon Sep 17 00:00:00 2001 From: Kim Dong-Hyun Date: Sat, 8 Jun 2024 19:13:45 +0900 Subject: [PATCH 035/128] Bump Java version in CI --- .github/workflows/example_app.yaml | 2 +- .github/workflows/test_app.yaml | 2 +- .github/workflows/user_app.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/example_app.yaml b/.github/workflows/example_app.yaml index 482471feb..f6083d0ee 100644 --- a/.github/workflows/example_app.yaml +++ b/.github/workflows/example_app.yaml @@ -69,7 +69,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: "11" + java-version: "17" - name: Setup Python uses: actions/setup-python@v5 diff --git a/.github/workflows/test_app.yaml b/.github/workflows/test_app.yaml index 97d5668fb..d1f8a519c 100644 --- a/.github/workflows/test_app.yaml +++ b/.github/workflows/test_app.yaml @@ -70,7 +70,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: "11" + java-version: "17" - name: Setup Python uses: actions/setup-python@v5 diff --git a/.github/workflows/user_app.yaml b/.github/workflows/user_app.yaml index ba023c7da..d21926565 100644 --- a/.github/workflows/user_app.yaml +++ b/.github/workflows/user_app.yaml @@ -53,7 +53,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: "11" + java-version: "17" - name: Setup Python uses: actions/setup-python@v5 From ae1ce8af37b0b4cdfafbafdce63db4ef176c7210 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 19:22:36 +0900 Subject: [PATCH 036/128] Update docs about graceful shutdown --- documentation/docs/graceful-shutdown.md | 84 +++++++++++++------------ 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/documentation/docs/graceful-shutdown.md b/documentation/docs/graceful-shutdown.md index 950adb541..085b32a78 100644 --- a/documentation/docs/graceful-shutdown.md +++ b/documentation/docs/graceful-shutdown.md @@ -1,41 +1,43 @@ -# Graceful Shutdown - -When the Flutter app is closed, the entire `tokio` runtime on the Rust side will be terminated automatically. However, you might need to run some finalization code in Rust before the app closes. This might involve saving files or disposing of resources. To achieve this, you can call `finalizeRust()` in Dart to terminate all Rust tasks before closing the Flutter app. - -```dart title="lib/main.dart" -import 'dart:ui'; -import 'package:flutter/material.dart'; -import './messages/generated.dart'; -... -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final _appLifecycleListener = AppLifecycleListener( - onExitRequested: () async { - // Terminate Rust tasks before closing the Flutter app. - await finalizeRust(); - return AppExitResponse.exit; - }, - ); - - @override - void dispose() { - _appLifecycleListener.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Some App', - home: MyHomePage(), - ); - } -} -... -``` +# Graceful Shutdown + +When the Flutter app is closed, the entire `tokio` async runtime on the Rust side will be terminated automatically. + +When using Rinf, the lifetime of the `tokio` runtime follows that of the Dart runtime. This behavior is different from typical `tokio` executables where its async runtime lives throughout the `main()` function of Rust. + +In some cases, you might need to run some finalization code in Rust before the app closes. This might involve saving files or disposing of resources. To achieve this, you can use Flutter's `AppLifecycleListener` to run something or to get user confirmation before closing the Flutter app. + +```dart title="lib/main.dart" +import 'dart:ui'; +import 'package:flutter/material.dart'; +... +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + final _appLifecycleListener = AppLifecycleListener( + onExitRequested: () async { + // Do something here before the app is exited. + return AppExitResponse.exit; + }, + ); + + @override + void dispose() { + _appLifecycleListener.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Some App', + home: MyHomePage(), + ); + } +} +... +``` From 3cdddf39a0e207088512f9d40d4effe108e8d762 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 19:45:17 +0900 Subject: [PATCH 037/128] Add details about tokio drop and rapid shutdown --- documentation/docs/graceful-shutdown.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/documentation/docs/graceful-shutdown.md b/documentation/docs/graceful-shutdown.md index 085b32a78..295bab7b5 100644 --- a/documentation/docs/graceful-shutdown.md +++ b/documentation/docs/graceful-shutdown.md @@ -1,8 +1,8 @@ # Graceful Shutdown -When the Flutter app is closed, the entire `tokio` async runtime on the Rust side will be terminated automatically. +When the Flutter app is closed, the entire `tokio` async runtime on the Rust side will be terminated automatically. Even if the app is force-closed, the `tokio` async runtime will be properly dropped. -When using Rinf, the lifetime of the `tokio` runtime follows that of the Dart runtime. This behavior is different from typical `tokio` executables where its async runtime lives throughout the `main()` function of Rust. +When using Rinf, the lifetime of the `tokio` runtime follows that of the Dart runtime. This behavior is different from typical `tokio` executables where its async runtime lives throughout the async `main()` function of Rust. In some cases, you might need to run some finalization code in Rust before the app closes. This might involve saving files or disposing of resources. To achieve this, you can use Flutter's `AppLifecycleListener` to run something or to get user confirmation before closing the Flutter app. @@ -41,3 +41,7 @@ class _MyAppState extends State { } ... ``` + +It's worth noting that `AppLifecycleListener` or `dispose` cannot always be relied upon for app closings. Below is a text snippet quoted from the official [Flutter docs](https://api.flutter.dev/flutter/widgets/State/dispose.html): + +> There is no way to predict when application shutdown will happen. For example, a user's battery could catch fire, or the user could drop the device into a swimming pool, or the operating system could unilaterally terminate the application process due to memory pressure. Applications are responsible for ensuring they behave well even in the face of rapid, unscheduled termination. From a5a2a1657eec143c4061fbae543ea3ce82f3399a Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 8 Jun 2024 19:46:34 +0900 Subject: [PATCH 038/128] Change linefeed --- documentation/docs/graceful-shutdown.md | 94 ++++++++++++------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/documentation/docs/graceful-shutdown.md b/documentation/docs/graceful-shutdown.md index 295bab7b5..c969946a9 100644 --- a/documentation/docs/graceful-shutdown.md +++ b/documentation/docs/graceful-shutdown.md @@ -1,47 +1,47 @@ -# Graceful Shutdown - -When the Flutter app is closed, the entire `tokio` async runtime on the Rust side will be terminated automatically. Even if the app is force-closed, the `tokio` async runtime will be properly dropped. - -When using Rinf, the lifetime of the `tokio` runtime follows that of the Dart runtime. This behavior is different from typical `tokio` executables where its async runtime lives throughout the async `main()` function of Rust. - -In some cases, you might need to run some finalization code in Rust before the app closes. This might involve saving files or disposing of resources. To achieve this, you can use Flutter's `AppLifecycleListener` to run something or to get user confirmation before closing the Flutter app. - -```dart title="lib/main.dart" -import 'dart:ui'; -import 'package:flutter/material.dart'; -... -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - final _appLifecycleListener = AppLifecycleListener( - onExitRequested: () async { - // Do something here before the app is exited. - return AppExitResponse.exit; - }, - ); - - @override - void dispose() { - _appLifecycleListener.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Some App', - home: MyHomePage(), - ); - } -} -... -``` - -It's worth noting that `AppLifecycleListener` or `dispose` cannot always be relied upon for app closings. Below is a text snippet quoted from the official [Flutter docs](https://api.flutter.dev/flutter/widgets/State/dispose.html): - -> There is no way to predict when application shutdown will happen. For example, a user's battery could catch fire, or the user could drop the device into a swimming pool, or the operating system could unilaterally terminate the application process due to memory pressure. Applications are responsible for ensuring they behave well even in the face of rapid, unscheduled termination. +# Graceful Shutdown + +When the Flutter app is closed, the entire `tokio` async runtime on the Rust side will be terminated automatically. Even if the app is force-closed, the `tokio` async runtime will be properly dropped. + +When using Rinf, the lifetime of the `tokio` runtime follows that of the Dart runtime. This behavior is different from typical `tokio` executables where its async runtime lives throughout the async `main()` function of Rust. + +In some cases, you might need to run some finalization code in Rust before the app closes. This might involve saving files or disposing of resources. To achieve this, you can use Flutter's `AppLifecycleListener` to run something or to get user confirmation before closing the Flutter app. + +```dart title="lib/main.dart" +import 'dart:ui'; +import 'package:flutter/material.dart'; +... +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + final _appLifecycleListener = AppLifecycleListener( + onExitRequested: () async { + // Do something here before the app is exited. + return AppExitResponse.exit; + }, + ); + + @override + void dispose() { + _appLifecycleListener.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Some App', + home: MyHomePage(), + ); + } +} +... +``` + +It's worth noting that `AppLifecycleListener` or `dispose` cannot always be relied upon for app closings. Below is a text snippet quoted from the official [Flutter docs](https://api.flutter.dev/flutter/widgets/State/dispose.html): + +> There is no way to predict when application shutdown will happen. For example, a user's battery could catch fire, or the user could drop the device into a swimming pool, or the operating system could unilaterally terminate the application process due to memory pressure. Applications are responsible for ensuring they behave well even in the face of rapid, unscheduled termination. From 34a61ec2b7b12e5a962dbe1b01eed16bb5661ebd Mon Sep 17 00:00:00 2001 From: Kim Dong-Hyun Date: Sat, 8 Jun 2024 20:08:26 +0900 Subject: [PATCH 039/128] Do not make the user app use local crate --- automate/__main__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/automate/__main__.py b/automate/__main__.py index 20d4e3a06..d0fa5d425 100644 --- a/automate/__main__.py +++ b/automate/__main__.py @@ -130,6 +130,11 @@ def replace_text_in_file(filepath: str, change_from: str, change_to: str): "flutter_ffi_plugin/example/native/*", "user_app/native/*", ) + replace_text_in_file( + "Cargo.toml", + 'rinf = { path = "./rust_crate" }', + "", + ) elif sys.argv[1] == "prepare-example-app": os.chdir("./flutter_ffi_plugin/example") From a63d13abe737bdfc2588fd45503c6fd6700b1125 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 00:08:39 +0900 Subject: [PATCH 040/128] Version 6.12.0 --- CHANGELOG.md | 1602 +++++++++-------- flutter_ffi_plugin/CHANGELOG.md | 1602 +++++++++-------- .../example/native/hub/Cargo.toml | 2 +- flutter_ffi_plugin/pubspec.yaml | 164 +- .../template/native/hub/Cargo.toml | 38 +- rust_crate/Cargo.toml | 46 +- 6 files changed, 1735 insertions(+), 1719 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02453321e..ffe147e0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,797 +1,805 @@ -## 6.11.1 - -- Fixed a bug with Dart's extension methods in the generated message code. - -## 6.11.0 - -- Now it's possible to set the dynamic library's path. -- Now `rinf message` generates more memory-efficient and cleaner code. - -## 6.10.0 - -- Early Dart signals are now stored in the tokio channel instead of being ignored. Their performance is also slightly better. -- Excessive sample code is not included in the template from the `rinf template` command anymore. -- Now `tokio` is enabled by default in the template, not `tokio_with_wasm`. -- A configuration option, `rinf.message.rust_serde`, was added to make generated Rust message files compatible with `serde`. Thanks @NeoVance! - -## 6.9.2 - -- Early Dart signals have become more stable. - -## 6.9.1 - -- Now the memory allocation and drop is done in each language. - -## 6.9.0 - -- This version supports Flutter 3.22 -- The new version of Flutter has a little different way of resolving paths. This release adapts to this change. - -## 6.8.0 - -- Now `sendSignalToRust` and `send_signal_to_dart` methods no longer require `null` or `None`, making the API much cleaner. To make them include binary data, write `[RINF:DART-SIGNAL-BINARY]` or `[RINF:RUST-SIGNAL-BINARY]` in Protobuf files. -- The problem of panicking from null pointers that arise from empty signal data has been fixed. - -## 6.7.0 - -- Allowed `enum` and `oneof` statements to work in Protobuf message files. Thanks @yeoupooh! - -## 6.6.3 - -- Fixed a linting issue. Thanks @romanseo1! - -## 6.6.2 - -- Updated `tokio_with_wasm` to a newer version that addresses performance issues with `spawn_blocking`. -- Added example code that shows how to use global state in `sample_functions.rs` file. - -## 6.6.1 - -- Added support for some Linux distributions where patching Flutter SDK is not possible. -- Fixed a problem with the web sector not working. To use this new version, it's recommended to discard all Git changes in Flutter SDK's directory, or simply run `flutter upgrade --force`. -- Fixed a problem with `cd` error on Windows. Thanks @H2Sxxa! -- Fixed `pub.dev` package score. - -## 6.6.0 - -- Now early Rust signals on startup works properly, even if the widgets are not built yet. `rustSignalStream` will remember Rust signals that were received before widgets were built, and give them to the first listener. - -## 6.5.0 - -- Now the native library file is loaded as dynamic library, not static library, on iOS and macOS, like other platforms. This reduces the possibility of potential conflicts of native symbols. -- Now `rinf template` checks `pubspec.yaml` instead of `lib/main.dart` to ensure that the current folder is a Flutter project. - -## 6.4.0 - -- The start and stop mechanism of Rust has become more stable. - -## 6.3.1 - -- Fixed a small glitch with codegen. - -## 6.3.0 - -- The interface code has been organized. Now the `bridge` Rust module is gone and the API makes more sense. Please refer to the example code to upgrade. - -## 6.2.0 - -- Now custom installation of `protoc` works. This is useful when you don't have full access to GitHub APIs, which is needed for automatic `protoc` installation. Thanks @TENX-S! -- Signal handling has become more efficient. - -## 6.1.0 - -- Now `rustSignalStream`s `listen` can be called multiple times. Thanks @rabbitson87! - -## 6.0.1 - -- Improved CLI output texts. -- `js` Dart package was removed. - -## 6.0.0 - -- You need to run `rinf template`, `cargo install rinf` again to use this new version. -- Now the communication between Dart and Rust is much simpler. You can mark messages in `.proto` files so that Rinf's code generator can generate channels in-between. This new system is not compatible with older Rinf versions, so please check the docs before you upgrade. -- Added the ability to customize Rinf's behaviors by writing fields inside `pubspec.yaml` file. Thanks @thlorenz! -- Allowed users to check when the documentation page was made and edited. Thanks @VictorieeMan! -- Now it's possible to quit `rinf message --watch` by pressing `q` on your keyboard. -- Internal code has been organized. - -## 6.0.0-beta - -- This is a beta version. - -## 6.0.0-alpha - -- This is an alpha version. - -## 5.4.0 - -- Now users do not have to manually install `protoc` binary executable anymore. Protobuf compiler is now automatically installed. Note that you need to run `cargo install rinf` again to use this new version. - -## 5.3.1 - -- Fixed a bug with `rinf message` that omits `mod.rs` inside a folder without any message. - -## 5.3.0 - -- Now it is possible to use `import` statements in `.proto` files. -- Now you can properly use Flutter's hot restart while developing. -- Tutorials and guides are improved. -- Fixed a bug with `rinf message`, that might fail if some of the folders are empty. - -## 5.2.0 - -- Unnecessary memory copy is now avoided. - -## 5.1.3 - -- Fixed introductions. - -## 5.1.2 - -- Fixed a bug with memory freeing. - -## 5.1.1 - -- The codebase was organized further. -- Fixed a problem with Dart analysis. - -## 5.1.0 - -- All the code from `flutter_rust_bridge` was removed. This was due to criticisms about Rinf from the community and FRB devs. Also, internal bridge and FFI code is now much smaller. User API remains unchanged. - -## 5.0.0 - -- Now `requestToRust` Dart function will return `null` when the handler function in Rust cannot respond or has panicked. This is a breaking change, so when you upgrade to this version, you need to run `rinf template --bridge` in the terminal and refactor some of the code where IDE warns you about mismatches. You also need to modify `lib.rs` and `with_request.rs` modules of the `hub` crate. Also, the `timeout` parameter was removed from the `requestToRust` function because Dart will always get some return value from Rust in all cases. Please refer to the example code and documentation tutorials if you need detailed information. - -## 4.20.0 - -- Added support for Android Gradle Plugin 8. - -## 4.19.1 - -- Switched to the new official website `rinf.cunarist.com`. - -## 4.19.0 - -- The mechanism for awaiting Rust's responses from Dart has become much more efficient. - -## 4.18.0 - -- Now `null` can be provided to the `timeout` parameter in the `requestToRust()` Dart function. This enables awaiting a Rust response forever, but it should be used cautiously because it may potentially lead to resource leaks. - -## 4.17.1 - -- Now `rinf message --watch` works on all platforms. Thanks @bookshiyi! - -## 4.17.0 - -- New command `rinf message --watch` for automatic message code generation. Thanks @bookshiyi! - -## 4.16.3 - -- Updated package descriptions. - -## 4.16.2 - -- Improved guides to avoid misconceptions about the communication system. Rinf only uses FFI without any web server. - -## 4.16.1 - -- Fixed the broken `rinf template --bridge` command - -## 4.16.0 - -- Vastly organized files, dependencies, and code readability. Now the `hub` crate is much cleaner than before. If you already have an app using older Rinf versions, it is recommended to run `rinf template --bridge` and add `rinf = "4.16.0"` to `Cargo.toml` of the `hub` crate. - -## 4.15.2 - -- Now the web API fetching example uses `http` instead of `https` in the example app. - -## 4.15.1 - -- Now the `reqwest` crate will be disabled when compiling the example app for Android. - -## 4.15.0 - -- Allowed setting custom timeout when using `requestToRust()`. Thanks @cipherchabon! - -## 4.14.0 - -- Added a web API fetching example to the template. -- Fixed various things such as template comments, code linting issues. - -## 4.13.2 - -- Fixed small things. - -## 4.13.1 - -- Fixed formatting issues in Dart code. - -## 4.13.0 - -- Improved the template code by disabling CPU-intensive tasks and removing unneeded dependency features. -- Improved CLI outputs from `rinf wasm`. -- Improved various guides and template comments. - -## 4.12.5 - -- Automated publication. - -## 4.12.4 - -- Fixed permission related problems with build script files. - -## 4.12.3 - -- Fixed permission related problems with build script files. - -## 4.12.2 - -- Fixed guide badges. - -## 4.12.1 - -- Fixed publishing issues. - -## 4.12.0 - -- Renamed the framework to Rinf. - -## 4.11.8 - -- Improved first guides. - -## 4.11.7 - -- Improved the example app's code and guides. - -## 4.11.6 - -- Improved the shorthand command crate. - -## 4.11.5 - -- Improved the shorthand command crate. - -## 4.11.4 - -- Improved the first preview image and some comments. - -## 4.11.3 - -- Improved the example app's code. - -## 4.11.2 - -- Fixed a problem with compilation on macOS. - -## 4.11.1 - -- Fixed a problem with compilation on macOS. - -## 4.11.0 - -- New Dart function `ensureFinalized()`. This function ensures that all Rust tasks are terminated. Take a look at the example code to understand how to run this function before closing the Flutter app. Note that you have to run `rifs template --bridge` again to use this function. - -## 4.10.0 - -- New default web alias `spawn_blocking()`. CPU-intensive blocking tasks are better to be executed on a separate thread pool. -- Improved the example app's performance and debug tests. - -## 4.9.0 - -- New default web alias `yield_now()`. Inside a long-running code, calling this will help you avoid blocking the whole async event loop, by giving the flow back to other async tasks. -- Vastly improved comments inside the `web_alias` Rust module. -- Now Rust panics on the web will be printed to the CLI too. -- Improved the example app's performance and debug tests. - -## 4.8.2 - -- Improved guide sentences. - -## 4.8.1 - -- Improved the readability of the example code. -- Organized and clarified first guides. - -## 4.8.0 - -- Now by running `rifs template --bridge`, you can apply and update only the `bridge` module inside the `hub` crate. This is useful when you've upgraded RIF but do not need to apply the whole template again. -- Improved `rifs --help` output. - -## 4.7.0 - -- Now Rust stacktrace will be printed to the CLI when a panic occurs. The changes are mostly included in the template, so make sure you've run `rifs template` on this new version. - -## 4.6.2 - -- Polished various aspects. - -## 4.6.1 - -- Stabilized `debug_print!` logic. - -## 4.6.0 - -- New `debug_print!` macro that works on all environments, including web and mobile emulators, with the power of Flutter debuggers. To use this, you need to run `rifs template` again. -- Now panic information in Rust will be properly printed to the CLI. Note that Rust panics don't crash the app and do not hinder stability. -- Improved docs. There are also more guides about well-known types in Protobuf. Thanks @LucaCoduriV! - -## 4.5.0 - -- Added support for external symbols on iOS and macOS. This is needed for some Rust crates that depend on Apple's system frameworks. - -## 4.4.2 - -- Updated docs and demo links. - -## 4.4.1 - -- Updated docs and demo links. - -## 4.4.0 - -- Improved various guides and comments. -- Fixed a bug that made the app crash when passing in an empty `Vec`. -- Fixed the formatting of Rust files. - -## 4.3.0 - -- Now `flutter run` will use `require-corp` value for `cross-origin-embedder-policy` HTTP header that works on all web browsers. - -## 4.2.1 - -- Fixed a bug with `RustResponse::default()`. - -## 4.2.0 - -- New command `rifs --help`. Thanks @bookshiyi! - -## 4.1.4 - -- Fixed a sentence in the guides. - -## 4.1.3 - -- Made `rifs message` command read `PUB_CACHE` enviornment variable if present. Thanks @rabbitson87! - -## 4.1.2 - -- Fixed `rifs template` command. - -## 4.1.1 - -- Added some guides to the shorthand crate. -- Removed an unneeded dependency from the shorthand crate. - -## 4.1.0 - -- Fixed `sleep()` on the web. -- Added demo link in the guides. - -## 4.0.3 - -- Fixed bugs with `rifs template` on Windows. -- Fixed outdated comments. -- Organized sample code. - -## 4.0.2 - -- Eliminated an unnecessary Dart dependency. - -## 4.0.1 - -- Eliminated an unnecessary Dart dependency. - -## 4.0.0 - -- Added support for sending large binaries between Dart and Rust. This is now possible by using the `blob` field in `RustRequest`, `RustResponse`, and `RustSignal`. Please make sure you've run `rifs template` before using this new version because the template has changed a little. -- Added support for nested message folders. -- Added support for Rust nightly. -- Eliminated unnecessary Dart dependencies. - -## 3.7.4 - -- Updated `cargokit`, the build connector between Flutter and Rust. - -## 3.7.3 - -- Fixed a bug with cargo. - -## 3.7.2 - -- Fixed a bug with cargo. - -## 3.7.1 - -- Organized descriptions and files. - -## 3.7.0 - -- Now this framework provides a shorthand command `rifs ...` which is equivalent to `dart run rust_in_flutter ...`. - -## 3.6.0 - -- Fixed a bug that prevents the app from running on Linux. -- Improved various texts exposed to developers for clarity. - -## 3.5.1 - -- Bumped `prost` version to avoid snake case related warnings. - -## 3.5.0 - -- Shortend some names that were unnecessarily long. - -## 3.4.5 - -- Import statements became shorter in Dart. - -## 3.4.4 - -- Cleaned up outdated dependencies in `Cargo.toml`. - -## 3.4.3 - -- Now `syntax` and `package` statements in `.proto` files should be handled automatically. - -## 3.4.2 - -- Now running `dart run rust_in_flutter message` verifies `package` statement in `.proto` files and mistakes are fixed automatically. - -## 3.4.1 - -- Now match statement is used for handling requests. This improves code readability. - -## 3.4.0 - -- Now each `.proto` file is treated as a Rust resource, which essentially becomes an API endpoint. - -## 3.3.0 - -- `RustResource` enum has been added to `interaction.proto`. Now the list of available Rust resources are managed by Protobuf, which makes the project less error-prone. This new system also has less runtime overhead because interactions are distinguished by simple integers, not strings. - -## 3.2.3 - -- Improved guides. - -## 3.2.2 - -- Organized guides. - -## 3.2.1 - -- Matched first guides with the docs. - -## 3.2.0 - -- Now when applying the Rust template with `dart run rust_in_flutter template`, `README.md` file will get a new section explaining about this framework. - -## 3.1.1 - -- Updated docs link. - -## 3.1.0 - -- Now there's a new Dart command `message`. Developers can now generate Dart and Rust message code from `.proto` files with `dart run rust_in_flutter message`. `build.rs` file that used to do this is removed. - -## 3.0.9 - -- Fixed a problem with pub.dev score. - -## 3.0.8 - -- Fixed a problem with pub.dev score. - -## 3.0.7 - -- Fixed a problem with pub.dev score. - -## 3.0.6 - -- Fixed a problem with pub.dev score. - -## 3.0.5 - -- Moved documentation to a dedicated website. -- Now `build.rs` will automatically modify PATH for `protoc-gen-dart`. -- Fixed an error appearing in Rust-analyzer's webassembly mode. - -## 3.0.4 - -- Polished template code. - -## 3.0.3 - -- Polished template code. - -## 3.0.2 - -- Polished guides, comments and template code. - -## 3.0.1 - -- Fixed and organized tutorials and comments. - -## 3.0.0 - -- Adopted Protobuf for message serialization. Now communication between Dart and Rust is much more type-safe and faster than before. Because the template has now changed, you need to run `dart run rust_in_flutter template` again when migrating from version 2. Thanks @wheregmis` and @bookshiyi! - -## 2.9.0 - -- Removed `corrosion`. Now this package solely relies on `cargokit` and is much more slimmer. Thanks @bookshiyi! -- Removed unneeded files from pub.dev publication. - -## 2.8.5 - -- Fixed a problem with pub.dev score. - -## 2.8.4 - -- Fixed a problem with pub.dev score. - -## 2.8.3 - -- Wrote new catchphrase. - -## 2.8.2 - -- Updated links. - -## 2.8.1 - -- Updated links. - -## 2.8.0 - -- Removed unneeded dependencies. - -## 2.7.4 - -- Fixed CI badge showing rate limit error. - -## 2.7.3 - -- Fixed wrong guides. - -## 2.7.2 - -- Organized guides. - -## 2.7.1 - -- Organized guides. Thanks @bookshiyi! - -## 2.7.0 - -- Stabilized web-related Rust toolchain's auto-installation. Thanks @bookshiyi! - -## 2.6.0 - -- Applied continuous integration for checking builds and improving project stability. Thanks @bookshiyi! - -## 2.5.6 - -- Updated Cargokit. Thanks @bookshiyi! - -## 2.5.5 - -- Improved guides about HTTP headers. - -## 2.5.4 - -- Updated example code. - -## 2.5.3 - -- Improved guides and CLI messages. - -## 2.5.2 - -- Optimized web binary size. - -## 2.5.1 - -- Optimized web performance. - -## 2.5.0 - -- Now Rust logic will be restarted upon Dart's hot restart on the web too. -- CLI commands are shortened. - -## 2.4.0 - -- Fixed the problem with dangling threads from the `tokio` runtime remaining after closing the Flutter app. Even after the app window was closed, `tokio` threads were still running, resulting in becoming a background process without a window. Now the `tokio` runtime will properly be shut down. - -## 2.3.2 - -- Re-publishing due to `pub.dev`'s `[UNKNOWN PLATFORMS]` error. - -## 2.3.1 - -- Restored the benefits section in the first guide. - -## 2.3.0 - -- Improved Dart's hot restart process on native platforms. - -## 2.2.0 - -- Improved the procedure of building for the web. -- Simplfied unneeded complexities. - -## 2.1.2 - -- Improved web alias module. -- Fixed small things. - -## 2.1.1 - -- Optimized the bridge thread on native platforms. -- Updated many minor errors in the guides. -- Fixed a problem with import statement not being written in `./lib/main.dart` when applying Rust template. - -## 2.1.0 - -- Merged `frb_engine` crate into `hub`. -- Removed unneeded intermediate worker pools. -- Added `time` web alias import. -- Added many guides and comments. - -## 2.0.1 - -- Improved guides. -- Added `print!` web alias macro. -- Organized exposed Dart APIs. - -## 2.0.0 - -- Added web support. - -## 1.6.6 - -- Improved guides. -- Now, the template application command will check if the current directory is a Flutter project first. - -## 1.6.5 - -- Improved guides. - -## 1.6.4 - -- Organized guide sections. - -## 1.6.3 - -- Organized guide sections. - -## 1.6.2 - -- Filled in missing translations. - -## 1.6.1 - -- Slightly improved guide sections. - -## 1.6.0 - -- Added step-by-step guides. - -## 1.5.3 - -- Fixed some example app code. - -## 1.5.2 - -- Improved the readability of example app code. - -## 1.5.1 - -- Added Japanese translation. -- Fixed some sentences in Korean guides. - -## 1.5.0 - -- Now the Android NDK version that the Flutter SDK expects will be used, not the version specified by this package. -- Fixed a bug saying `IntoDart` trait is not implemented. - -## 1.4.1 - -- Improved various guides. - -## 1.4.0 - -- Filled in various guides to help developers understand the structure more easily. - -## 1.3.2 - -- Added Chinese guides. Thanks @moluopro! -- Added Korean guides. -- Added guides about build tool version issues. -- Added guides about library bundling. - -## 1.3.1 - -- Fixed a problem with Rust crate path detection on Android. - -## 1.3.0 - -- Changed the name of an exposed enum. Now `Operation` has changed to `RustOperation` so that it won't make confusions with other operations. All developers should update their code to match this new name, probably using the batch replace function in various IDEs. -- Updated code snippets. - -## 1.2.8 - -- Fixed small things. - -## 1.2.7 - -- Stabilized `main.dart` modifcation upon `dart run rust_in_flutter:apply_template`. - -## 1.2.6 - -- Hid the information regarding the compilation of connector crates to avoid confusion with actual crates. - -## 1.2.5 - -- Updated the guide about Android NDK version. - -## 1.2.4 - -- Updated many outdated comments and guides. -- Decreased the time spent on `ensureInitialized`. Also, `ensureInitialized()` is automatically inserted in `main.dart` when doing `dart run rust_in_flutter:apply_template` from now on. -- Various code improvements were applied. - -## 1.2.3 - -- Clarified template structure in guides. - -## 1.2.2 - -- Hide more Dart APIs that are not meant to be used outside. - -## 1.2.1 - -- Updated many comments. -- Fine-tuned the visibility of Dart APIs. -- Organized guides. - -## 1.2.0 - -- Made the Rust request handler more future-proof, taking potential web support into account. - -## 1.1.1 - -- Improved various guides to help understanding the features of this package. - -## 1.1.0 - -- Now this package is a Flutter FFI plugin without dummy native code. -- Improved guides - -## 1.0.4 - -- Fixed a problem with library bundling on Linux. -- Added comments. -- Added guides. -- Improved template application. - -## 1.0.3 - -- Included code snippets in guides. - -## 1.0.2 - -- Fixed typos. -- Organized inner code. - -## 1.0.1 - -- Enforced bundling on macOS and iOS. -- Improved pub score. -- Make `apply_rust` modify `.gitignore`. - -## 1.0.0 - -- Previously `flutter_rust_app_template`, now this is a small convenient framework that can be applied to existing Flutter projects. +## 6.12.0 + +- Generated message channels are now more efficient. +- Minimum Android SDK version increased from 16 to 21. Thanks @debanjanbasu! +- The `finalizeRust()` function in Dart has been removed. The `tokio` async runtime, which holds Rust logic, still drops automatically when the app ends. +- Bumped `prost` version to 0.12.6. Thanks @yeoupooh! +- Internal code has been organized. + +## 6.11.1 + +- Fixed a bug with Dart's extension methods in the generated message code. + +## 6.11.0 + +- Now it's possible to set the dynamic library's path. +- Now `rinf message` generates more memory-efficient and cleaner code. + +## 6.10.0 + +- Early Dart signals are now stored in the tokio channel instead of being ignored. Their performance is also slightly better. +- Excessive sample code is not included in the template from the `rinf template` command anymore. +- Now `tokio` is enabled by default in the template, not `tokio_with_wasm`. +- A configuration option, `rinf.message.rust_serde`, was added to make generated Rust message files compatible with `serde`. Thanks @NeoVance! + +## 6.9.2 + +- Early Dart signals have become more stable. + +## 6.9.1 + +- Now the memory allocation and drop is done in each language. + +## 6.9.0 + +- This version supports Flutter 3.22 +- The new version of Flutter has a little different way of resolving paths. This release adapts to this change. + +## 6.8.0 + +- Now `sendSignalToRust` and `send_signal_to_dart` methods no longer require `null` or `None`, making the API much cleaner. To make them include binary data, write `[RINF:DART-SIGNAL-BINARY]` or `[RINF:RUST-SIGNAL-BINARY]` in Protobuf files. +- The problem of panicking from null pointers that arise from empty signal data has been fixed. + +## 6.7.0 + +- Allowed `enum` and `oneof` statements to work in Protobuf message files. Thanks @yeoupooh! + +## 6.6.3 + +- Fixed a linting issue. Thanks @romanseo1! + +## 6.6.2 + +- Updated `tokio_with_wasm` to a newer version that addresses performance issues with `spawn_blocking`. +- Added example code that shows how to use global state in `sample_functions.rs` file. + +## 6.6.1 + +- Added support for some Linux distributions where patching Flutter SDK is not possible. +- Fixed a problem with the web sector not working. To use this new version, it's recommended to discard all Git changes in Flutter SDK's directory, or simply run `flutter upgrade --force`. +- Fixed a problem with `cd` error on Windows. Thanks @H2Sxxa! +- Fixed `pub.dev` package score. + +## 6.6.0 + +- Now early Rust signals on startup works properly, even if the widgets are not built yet. `rustSignalStream` will remember Rust signals that were received before widgets were built, and give them to the first listener. + +## 6.5.0 + +- Now the native library file is loaded as dynamic library, not static library, on iOS and macOS, like other platforms. This reduces the possibility of potential conflicts of native symbols. +- Now `rinf template` checks `pubspec.yaml` instead of `lib/main.dart` to ensure that the current folder is a Flutter project. + +## 6.4.0 + +- The start and stop mechanism of Rust has become more stable. + +## 6.3.1 + +- Fixed a small glitch with codegen. + +## 6.3.0 + +- The interface code has been organized. Now the `bridge` Rust module is gone and the API makes more sense. Please refer to the example code to upgrade. + +## 6.2.0 + +- Now custom installation of `protoc` works. This is useful when you don't have full access to GitHub APIs, which is needed for automatic `protoc` installation. Thanks @TENX-S! +- Signal handling has become more efficient. + +## 6.1.0 + +- Now `rustSignalStream`s `listen` can be called multiple times. Thanks @rabbitson87! + +## 6.0.1 + +- Improved CLI output texts. +- `js` Dart package was removed. + +## 6.0.0 + +- You need to run `rinf template`, `cargo install rinf` again to use this new version. +- Now the communication between Dart and Rust is much simpler. You can mark messages in `.proto` files so that Rinf's code generator can generate channels in-between. This new system is not compatible with older Rinf versions, so please check the docs before you upgrade. +- Added the ability to customize Rinf's behaviors by writing fields inside `pubspec.yaml` file. Thanks @thlorenz! +- Allowed users to check when the documentation page was made and edited. Thanks @VictorieeMan! +- Now it's possible to quit `rinf message --watch` by pressing `q` on your keyboard. +- Internal code has been organized. + +## 6.0.0-beta + +- This is a beta version. + +## 6.0.0-alpha + +- This is an alpha version. + +## 5.4.0 + +- Now users do not have to manually install `protoc` binary executable anymore. Protobuf compiler is now automatically installed. Note that you need to run `cargo install rinf` again to use this new version. + +## 5.3.1 + +- Fixed a bug with `rinf message` that omits `mod.rs` inside a folder without any message. + +## 5.3.0 + +- Now it is possible to use `import` statements in `.proto` files. +- Now you can properly use Flutter's hot restart while developing. +- Tutorials and guides are improved. +- Fixed a bug with `rinf message`, that might fail if some of the folders are empty. + +## 5.2.0 + +- Unnecessary memory copy is now avoided. + +## 5.1.3 + +- Fixed introductions. + +## 5.1.2 + +- Fixed a bug with memory freeing. + +## 5.1.1 + +- The codebase was organized further. +- Fixed a problem with Dart analysis. + +## 5.1.0 + +- All the code from `flutter_rust_bridge` was removed. This was due to criticisms about Rinf from the community and FRB devs. Also, internal bridge and FFI code is now much smaller. User API remains unchanged. + +## 5.0.0 + +- Now `requestToRust` Dart function will return `null` when the handler function in Rust cannot respond or has panicked. This is a breaking change, so when you upgrade to this version, you need to run `rinf template --bridge` in the terminal and refactor some of the code where IDE warns you about mismatches. You also need to modify `lib.rs` and `with_request.rs` modules of the `hub` crate. Also, the `timeout` parameter was removed from the `requestToRust` function because Dart will always get some return value from Rust in all cases. Please refer to the example code and documentation tutorials if you need detailed information. + +## 4.20.0 + +- Added support for Android Gradle Plugin 8. + +## 4.19.1 + +- Switched to the new official website `rinf.cunarist.com`. + +## 4.19.0 + +- The mechanism for awaiting Rust's responses from Dart has become much more efficient. + +## 4.18.0 + +- Now `null` can be provided to the `timeout` parameter in the `requestToRust()` Dart function. This enables awaiting a Rust response forever, but it should be used cautiously because it may potentially lead to resource leaks. + +## 4.17.1 + +- Now `rinf message --watch` works on all platforms. Thanks @bookshiyi! + +## 4.17.0 + +- New command `rinf message --watch` for automatic message code generation. Thanks @bookshiyi! + +## 4.16.3 + +- Updated package descriptions. + +## 4.16.2 + +- Improved guides to avoid misconceptions about the communication system. Rinf only uses FFI without any web server. + +## 4.16.1 + +- Fixed the broken `rinf template --bridge` command + +## 4.16.0 + +- Vastly organized files, dependencies, and code readability. Now the `hub` crate is much cleaner than before. If you already have an app using older Rinf versions, it is recommended to run `rinf template --bridge` and add `rinf = "4.16.0"` to `Cargo.toml` of the `hub` crate. + +## 4.15.2 + +- Now the web API fetching example uses `http` instead of `https` in the example app. + +## 4.15.1 + +- Now the `reqwest` crate will be disabled when compiling the example app for Android. + +## 4.15.0 + +- Allowed setting custom timeout when using `requestToRust()`. Thanks @cipherchabon! + +## 4.14.0 + +- Added a web API fetching example to the template. +- Fixed various things such as template comments, code linting issues. + +## 4.13.2 + +- Fixed small things. + +## 4.13.1 + +- Fixed formatting issues in Dart code. + +## 4.13.0 + +- Improved the template code by disabling CPU-intensive tasks and removing unneeded dependency features. +- Improved CLI outputs from `rinf wasm`. +- Improved various guides and template comments. + +## 4.12.5 + +- Automated publication. + +## 4.12.4 + +- Fixed permission related problems with build script files. + +## 4.12.3 + +- Fixed permission related problems with build script files. + +## 4.12.2 + +- Fixed guide badges. + +## 4.12.1 + +- Fixed publishing issues. + +## 4.12.0 + +- Renamed the framework to Rinf. + +## 4.11.8 + +- Improved first guides. + +## 4.11.7 + +- Improved the example app's code and guides. + +## 4.11.6 + +- Improved the shorthand command crate. + +## 4.11.5 + +- Improved the shorthand command crate. + +## 4.11.4 + +- Improved the first preview image and some comments. + +## 4.11.3 + +- Improved the example app's code. + +## 4.11.2 + +- Fixed a problem with compilation on macOS. + +## 4.11.1 + +- Fixed a problem with compilation on macOS. + +## 4.11.0 + +- New Dart function `ensureFinalized()`. This function ensures that all Rust tasks are terminated. Take a look at the example code to understand how to run this function before closing the Flutter app. Note that you have to run `rifs template --bridge` again to use this function. + +## 4.10.0 + +- New default web alias `spawn_blocking()`. CPU-intensive blocking tasks are better to be executed on a separate thread pool. +- Improved the example app's performance and debug tests. + +## 4.9.0 + +- New default web alias `yield_now()`. Inside a long-running code, calling this will help you avoid blocking the whole async event loop, by giving the flow back to other async tasks. +- Vastly improved comments inside the `web_alias` Rust module. +- Now Rust panics on the web will be printed to the CLI too. +- Improved the example app's performance and debug tests. + +## 4.8.2 + +- Improved guide sentences. + +## 4.8.1 + +- Improved the readability of the example code. +- Organized and clarified first guides. + +## 4.8.0 + +- Now by running `rifs template --bridge`, you can apply and update only the `bridge` module inside the `hub` crate. This is useful when you've upgraded RIF but do not need to apply the whole template again. +- Improved `rifs --help` output. + +## 4.7.0 + +- Now Rust stacktrace will be printed to the CLI when a panic occurs. The changes are mostly included in the template, so make sure you've run `rifs template` on this new version. + +## 4.6.2 + +- Polished various aspects. + +## 4.6.1 + +- Stabilized `debug_print!` logic. + +## 4.6.0 + +- New `debug_print!` macro that works on all environments, including web and mobile emulators, with the power of Flutter debuggers. To use this, you need to run `rifs template` again. +- Now panic information in Rust will be properly printed to the CLI. Note that Rust panics don't crash the app and do not hinder stability. +- Improved docs. There are also more guides about well-known types in Protobuf. Thanks @LucaCoduriV! + +## 4.5.0 + +- Added support for external symbols on iOS and macOS. This is needed for some Rust crates that depend on Apple's system frameworks. + +## 4.4.2 + +- Updated docs and demo links. + +## 4.4.1 + +- Updated docs and demo links. + +## 4.4.0 + +- Improved various guides and comments. +- Fixed a bug that made the app crash when passing in an empty `Vec`. +- Fixed the formatting of Rust files. + +## 4.3.0 + +- Now `flutter run` will use `require-corp` value for `cross-origin-embedder-policy` HTTP header that works on all web browsers. + +## 4.2.1 + +- Fixed a bug with `RustResponse::default()`. + +## 4.2.0 + +- New command `rifs --help`. Thanks @bookshiyi! + +## 4.1.4 + +- Fixed a sentence in the guides. + +## 4.1.3 + +- Made `rifs message` command read `PUB_CACHE` enviornment variable if present. Thanks @rabbitson87! + +## 4.1.2 + +- Fixed `rifs template` command. + +## 4.1.1 + +- Added some guides to the shorthand crate. +- Removed an unneeded dependency from the shorthand crate. + +## 4.1.0 + +- Fixed `sleep()` on the web. +- Added demo link in the guides. + +## 4.0.3 + +- Fixed bugs with `rifs template` on Windows. +- Fixed outdated comments. +- Organized sample code. + +## 4.0.2 + +- Eliminated an unnecessary Dart dependency. + +## 4.0.1 + +- Eliminated an unnecessary Dart dependency. + +## 4.0.0 + +- Added support for sending large binaries between Dart and Rust. This is now possible by using the `blob` field in `RustRequest`, `RustResponse`, and `RustSignal`. Please make sure you've run `rifs template` before using this new version because the template has changed a little. +- Added support for nested message folders. +- Added support for Rust nightly. +- Eliminated unnecessary Dart dependencies. + +## 3.7.4 + +- Updated `cargokit`, the build connector between Flutter and Rust. + +## 3.7.3 + +- Fixed a bug with cargo. + +## 3.7.2 + +- Fixed a bug with cargo. + +## 3.7.1 + +- Organized descriptions and files. + +## 3.7.0 + +- Now this framework provides a shorthand command `rifs ...` which is equivalent to `dart run rust_in_flutter ...`. + +## 3.6.0 + +- Fixed a bug that prevents the app from running on Linux. +- Improved various texts exposed to developers for clarity. + +## 3.5.1 + +- Bumped `prost` version to avoid snake case related warnings. + +## 3.5.0 + +- Shortend some names that were unnecessarily long. + +## 3.4.5 + +- Import statements became shorter in Dart. + +## 3.4.4 + +- Cleaned up outdated dependencies in `Cargo.toml`. + +## 3.4.3 + +- Now `syntax` and `package` statements in `.proto` files should be handled automatically. + +## 3.4.2 + +- Now running `dart run rust_in_flutter message` verifies `package` statement in `.proto` files and mistakes are fixed automatically. + +## 3.4.1 + +- Now match statement is used for handling requests. This improves code readability. + +## 3.4.0 + +- Now each `.proto` file is treated as a Rust resource, which essentially becomes an API endpoint. + +## 3.3.0 + +- `RustResource` enum has been added to `interaction.proto`. Now the list of available Rust resources are managed by Protobuf, which makes the project less error-prone. This new system also has less runtime overhead because interactions are distinguished by simple integers, not strings. + +## 3.2.3 + +- Improved guides. + +## 3.2.2 + +- Organized guides. + +## 3.2.1 + +- Matched first guides with the docs. + +## 3.2.0 + +- Now when applying the Rust template with `dart run rust_in_flutter template`, `README.md` file will get a new section explaining about this framework. + +## 3.1.1 + +- Updated docs link. + +## 3.1.0 + +- Now there's a new Dart command `message`. Developers can now generate Dart and Rust message code from `.proto` files with `dart run rust_in_flutter message`. `build.rs` file that used to do this is removed. + +## 3.0.9 + +- Fixed a problem with pub.dev score. + +## 3.0.8 + +- Fixed a problem with pub.dev score. + +## 3.0.7 + +- Fixed a problem with pub.dev score. + +## 3.0.6 + +- Fixed a problem with pub.dev score. + +## 3.0.5 + +- Moved documentation to a dedicated website. +- Now `build.rs` will automatically modify PATH for `protoc-gen-dart`. +- Fixed an error appearing in Rust-analyzer's webassembly mode. + +## 3.0.4 + +- Polished template code. + +## 3.0.3 + +- Polished template code. + +## 3.0.2 + +- Polished guides, comments and template code. + +## 3.0.1 + +- Fixed and organized tutorials and comments. + +## 3.0.0 + +- Adopted Protobuf for message serialization. Now communication between Dart and Rust is much more type-safe and faster than before. Because the template has now changed, you need to run `dart run rust_in_flutter template` again when migrating from version 2. Thanks @wheregmis` and @bookshiyi! + +## 2.9.0 + +- Removed `corrosion`. Now this package solely relies on `cargokit` and is much more slimmer. Thanks @bookshiyi! +- Removed unneeded files from pub.dev publication. + +## 2.8.5 + +- Fixed a problem with pub.dev score. + +## 2.8.4 + +- Fixed a problem with pub.dev score. + +## 2.8.3 + +- Wrote new catchphrase. + +## 2.8.2 + +- Updated links. + +## 2.8.1 + +- Updated links. + +## 2.8.0 + +- Removed unneeded dependencies. + +## 2.7.4 + +- Fixed CI badge showing rate limit error. + +## 2.7.3 + +- Fixed wrong guides. + +## 2.7.2 + +- Organized guides. + +## 2.7.1 + +- Organized guides. Thanks @bookshiyi! + +## 2.7.0 + +- Stabilized web-related Rust toolchain's auto-installation. Thanks @bookshiyi! + +## 2.6.0 + +- Applied continuous integration for checking builds and improving project stability. Thanks @bookshiyi! + +## 2.5.6 + +- Updated Cargokit. Thanks @bookshiyi! + +## 2.5.5 + +- Improved guides about HTTP headers. + +## 2.5.4 + +- Updated example code. + +## 2.5.3 + +- Improved guides and CLI messages. + +## 2.5.2 + +- Optimized web binary size. + +## 2.5.1 + +- Optimized web performance. + +## 2.5.0 + +- Now Rust logic will be restarted upon Dart's hot restart on the web too. +- CLI commands are shortened. + +## 2.4.0 + +- Fixed the problem with dangling threads from the `tokio` runtime remaining after closing the Flutter app. Even after the app window was closed, `tokio` threads were still running, resulting in becoming a background process without a window. Now the `tokio` runtime will properly be shut down. + +## 2.3.2 + +- Re-publishing due to `pub.dev`'s `[UNKNOWN PLATFORMS]` error. + +## 2.3.1 + +- Restored the benefits section in the first guide. + +## 2.3.0 + +- Improved Dart's hot restart process on native platforms. + +## 2.2.0 + +- Improved the procedure of building for the web. +- Simplfied unneeded complexities. + +## 2.1.2 + +- Improved web alias module. +- Fixed small things. + +## 2.1.1 + +- Optimized the bridge thread on native platforms. +- Updated many minor errors in the guides. +- Fixed a problem with import statement not being written in `./lib/main.dart` when applying Rust template. + +## 2.1.0 + +- Merged `frb_engine` crate into `hub`. +- Removed unneeded intermediate worker pools. +- Added `time` web alias import. +- Added many guides and comments. + +## 2.0.1 + +- Improved guides. +- Added `print!` web alias macro. +- Organized exposed Dart APIs. + +## 2.0.0 + +- Added web support. + +## 1.6.6 + +- Improved guides. +- Now, the template application command will check if the current directory is a Flutter project first. + +## 1.6.5 + +- Improved guides. + +## 1.6.4 + +- Organized guide sections. + +## 1.6.3 + +- Organized guide sections. + +## 1.6.2 + +- Filled in missing translations. + +## 1.6.1 + +- Slightly improved guide sections. + +## 1.6.0 + +- Added step-by-step guides. + +## 1.5.3 + +- Fixed some example app code. + +## 1.5.2 + +- Improved the readability of example app code. + +## 1.5.1 + +- Added Japanese translation. +- Fixed some sentences in Korean guides. + +## 1.5.0 + +- Now the Android NDK version that the Flutter SDK expects will be used, not the version specified by this package. +- Fixed a bug saying `IntoDart` trait is not implemented. + +## 1.4.1 + +- Improved various guides. + +## 1.4.0 + +- Filled in various guides to help developers understand the structure more easily. + +## 1.3.2 + +- Added Chinese guides. Thanks @moluopro! +- Added Korean guides. +- Added guides about build tool version issues. +- Added guides about library bundling. + +## 1.3.1 + +- Fixed a problem with Rust crate path detection on Android. + +## 1.3.0 + +- Changed the name of an exposed enum. Now `Operation` has changed to `RustOperation` so that it won't make confusions with other operations. All developers should update their code to match this new name, probably using the batch replace function in various IDEs. +- Updated code snippets. + +## 1.2.8 + +- Fixed small things. + +## 1.2.7 + +- Stabilized `main.dart` modifcation upon `dart run rust_in_flutter:apply_template`. + +## 1.2.6 + +- Hid the information regarding the compilation of connector crates to avoid confusion with actual crates. + +## 1.2.5 + +- Updated the guide about Android NDK version. + +## 1.2.4 + +- Updated many outdated comments and guides. +- Decreased the time spent on `ensureInitialized`. Also, `ensureInitialized()` is automatically inserted in `main.dart` when doing `dart run rust_in_flutter:apply_template` from now on. +- Various code improvements were applied. + +## 1.2.3 + +- Clarified template structure in guides. + +## 1.2.2 + +- Hide more Dart APIs that are not meant to be used outside. + +## 1.2.1 + +- Updated many comments. +- Fine-tuned the visibility of Dart APIs. +- Organized guides. + +## 1.2.0 + +- Made the Rust request handler more future-proof, taking potential web support into account. + +## 1.1.1 + +- Improved various guides to help understanding the features of this package. + +## 1.1.0 + +- Now this package is a Flutter FFI plugin without dummy native code. +- Improved guides + +## 1.0.4 + +- Fixed a problem with library bundling on Linux. +- Added comments. +- Added guides. +- Improved template application. + +## 1.0.3 + +- Included code snippets in guides. + +## 1.0.2 + +- Fixed typos. +- Organized inner code. + +## 1.0.1 + +- Enforced bundling on macOS and iOS. +- Improved pub score. +- Make `apply_rust` modify `.gitignore`. + +## 1.0.0 + +- Previously `flutter_rust_app_template`, now this is a small convenient framework that can be applied to existing Flutter projects. diff --git a/flutter_ffi_plugin/CHANGELOG.md b/flutter_ffi_plugin/CHANGELOG.md index d56b916d4..8400b3c06 100644 --- a/flutter_ffi_plugin/CHANGELOG.md +++ b/flutter_ffi_plugin/CHANGELOG.md @@ -1,797 +1,805 @@ -## 6.11.1 - -- Fixed a bug with Dart's extension methods in the generated message code. - -## 6.11.0 - -- Now it's possible to set the dynamic library's path. -- Now `rinf message` generates more memory-efficient and cleaner code. - -## 6.10.0 - -- Early Dart signals are now stored in the tokio channel instead of being ignored. Their performance is also slightly better. -- Excessive sample code is not included in the template from the `rinf template` command anymore. -- Now `tokio` is enabled by default in the template, not `tokio_with_wasm`. -- A configuration option, `rinf.message.rust_serde`, was added to make generated Rust message files compatible with `serde`. Thanks @NeoVance! - -## 6.9.2 - -- Early Dart signals have become more stable. - -## 6.9.1 - -- Now the memory allocation and drop is done in each language. - -## 6.9.0 - -- This version supports Flutter 3.22. -- The new version of Flutter has a little different way of resolving paths. This release adapts to this change. - -## 6.8.0 - -- Now `sendSignalToRust` and `send_signal_to_dart` methods no longer require `null` or `None`, making the API much cleaner. To make them include binary data, write `[RINF:DART-SIGNAL-BINARY]` or `[RINF:RUST-SIGNAL-BINARY]` in Protobuf files. -- The problem of panicking from null pointers that arise from empty signal data has been fixed. - -## 6.7.0 - -- Allowed `enum` and `oneof` statements to work in Protobuf message files. Thanks @yeoupooh! - -## 6.6.3 - -- Fixed a linting issue. Thanks @romanseo1! - -## 6.6.2 - -- Updated `tokio_with_wasm` to a newer version that addresses performance issues with `spawn_blocking`. -- Added example code that shows how to use global state in `sample_functions.rs` file. - -## 6.6.1 - -- Added support for some Linux distributions where patching Flutter SDK is not possible. -- Fixed a problem with the web sector not working. To use this new version, it's recommended to discard all Git changes in Flutter SDK's directory, or simply run `flutter upgrade --force`. -- Fixed a problem with `cd` error on Windows. Thanks @H2Sxxa! -- Fixed `pub.dev` package score. - -## 6.6.0 - -- Now early Rust signals on startup works properly, even if the widgets are not built yet. `rustSignalStream` will remember Rust signals that were received before widgets were built, and give them to the first listener. - -## 6.5.0 - -- Now the native library file is loaded as dynamic library, not static library, on iOS and macOS, like other platforms. This reduces the possibility of potential conflicts of native symbols. -- Now `rinf template` checks `pubspec.yaml` instead of `lib/main.dart` to ensure that the current folder is a Flutter project. - -## 6.4.0 - -- The start and stop mechanism of Rust has become more stable. - -## 6.3.1 - -- Fixed a small glitch with codegen. - -## 6.3.0 - -- The interface code has been organized. Now the `bridge` Rust module is gone and the API makes more sense. Please refer to the example code to upgrade. - -## 6.2.0 - -- Now custom installation of `protoc` works. This is useful when you don't have full access to GitHub APIs, which is needed for automatic `protoc` installation. Thanks @TENX-S! -- Signal handling has become more efficient. - -## 6.1.0 - -- Now `rustSignalStream`s `listen` can be called multiple times. Thanks @rabbitson87! - -## 6.0.1 - -- Improved CLI output texts. -- `js` Dart package was removed. - -## 6.0.0 - -- You need to run `rinf template`, `cargo install rinf` again to use this new version. -- Now the communication between Dart and Rust is much simpler. You can mark messages in `.proto` files so that Rinf's code generator can generate channels in-between. This new system is not compatible with older Rinf versions, so please check the docs before you upgrade. -- Added the ability to customize Rinf's behaviors by writing fields inside `pubspec.yaml` file. Thanks @thlorenz! -- Allowed users to check when the documentation page was made and edited. Thanks @VictorieeMan! -- Now it's possible to quit `rinf message --watch` by pressing `q` on your keyboard. -- Internal code has been organized. - -## 6.0.0-beta - -- This is a beta version. - -## 6.0.0-alpha - -- This is an alpha version. - -## 5.4.0 - -- Now users do not have to manually install `protoc` binary executable anymore. Protobuf compiler is now automatically installed. Note that you need to run `cargo install rinf` again to use this new version. - -## 5.3.1 - -- Fixed a bug with `rinf message` that omits `mod.rs` inside a folder without any message. - -## 5.3.0 - -- Now it is possible to use `import` statements in `.proto` files. -- Now you can properly use Flutter's hot restart while developing. -- Tutorials and guides are improved. -- Fixed a bug with `rinf message`, that might fail if some of the folders are empty. - -## 5.2.0 - -- Unnecessary memory copy is now avoided. - -## 5.1.3 - -- Fixed introductions. - -## 5.1.2 - -- Fixed a bug with memory freeing. - -## 5.1.1 - -- The codebase was organized further. -- Fixed a problem with Dart analysis. - -## 5.1.0 - -- All the code from `flutter_rust_bridge` was removed. This was due to criticisms about Rinf from the community and FRB devs. Also, internal bridge and FFI code is now much smaller. User API remains unchanged. - -## 5.0.0 - -- Now `requestToRust` Dart function will return `null` when the handler function in Rust cannot respond or has panicked. This is a breaking change, so when you upgrade to this version, you need to run `rinf template --bridge` in the terminal and refactor some of the code where IDE warns you about mismatches. You also need to modify `lib.rs` and `with_request.rs` modules of the `hub` crate. Also, the `timeout` parameter was removed from the `requestToRust` function because Dart will always get some return value from Rust in all cases. Please refer to the example code and documentation tutorials if you need detailed information. - -## 4.20.0 - -- Added support for Android Gradle Plugin 8. - -## 4.19.1 - -- Switched to the new official website `rinf.cunarist.com`. - -## 4.19.0 - -- The mechanism for awaiting Rust's responses from Dart has become much more efficient. - -## 4.18.0 - -- Now `null` can be provided to the `timeout` parameter in the `requestToRust()` Dart function. This enables awaiting a Rust response forever, but it should be used cautiously because it may potentially lead to resource leaks. - -## 4.17.1 - -- Now `rinf message --watch` works on all platforms. Thanks @bookshiyi! - -## 4.17.0 - -- New command `rinf message --watch` for automatic message code generation. Thanks @bookshiyi! - -## 4.16.3 - -- Updated package descriptions. - -## 4.16.2 - -- Improved guides to avoid misconceptions about the communication system. Rinf only uses FFI without any web server. - -## 4.16.1 - -- Fixed the broken `rinf template --bridge` command - -## 4.16.0 - -- Vastly organized files, dependencies, and code readability. Now the `hub` crate is much cleaner than before. If you already have an app using older Rinf versions, it is recommended to run `rinf template --bridge` and add `rinf = "4.16.0"` to `Cargo.toml` of the `hub` crate. - -## 4.15.2 - -- Now the web API fetching example uses `http` instead of `https` in the example app. - -## 4.15.1 - -- Now the `reqwest` crate will be disabled when compiling the example app for Android. - -## 4.15.0 - -- Allowed setting custom timeout when using `requestToRust()`. Thanks @cipherchabon! - -## 4.14.0 - -- Added a web API fetching example to the template. -- Fixed various things such as template comments, code linting issues. - -## 4.13.2 - -- Fixed small things. - -## 4.13.1 - -- Fixed formatting issues in Dart code. - -## 4.13.0 - -- Improved the template code by disabling CPU-intensive tasks and removing unneeded dependency features. -- Improved CLI outputs from `rinf wasm`. -- Improved various guides and template comments. - -## 4.12.5 - -- Automated publication. - -## 4.12.4 - -- Fixed permission related problems with build script files. - -## 4.12.3 - -- Fixed permission related problems with build script files. - -## 4.12.2 - -- Fixed guide badges. - -## 4.12.1 - -- Fixed publishing issues. - -## 4.12.0 - -- Renamed the framework to Rinf. - -## 4.11.8 - -- Improved first guides. - -## 4.11.7 - -- Improved the example app's code and guides. - -## 4.11.6 - -- Improved the shorthand command crate. - -## 4.11.5 - -- Improved the shorthand command crate. - -## 4.11.4 - -- Improved the first preview image and some comments. - -## 4.11.3 - -- Improved the example app's code. - -## 4.11.2 - -- Fixed a problem with compilation on macOS. - -## 4.11.1 - -- Fixed a problem with compilation on macOS. - -## 4.11.0 - -- New Dart function `ensureFinalized()`. This function ensures that all Rust tasks are terminated. Take a look at the example code to understand how to run this function before closing the Flutter app. Note that you have to run `rifs template --bridge` again to use this function. - -## 4.10.0 - -- New default web alias `spawn_blocking()`. CPU-intensive blocking tasks are better to be executed on a separate thread pool. -- Improved the example app's performance and debug tests. - -## 4.9.0 - -- New default web alias `yield_now()`. Inside a long-running code, calling this will help you avoid blocking the whole async event loop, by giving the flow back to other async tasks. -- Vastly improved comments inside the `web_alias` Rust module. -- Now Rust panics on the web will be printed to the CLI too. -- Improved the example app's performance and debug tests. - -## 4.8.2 - -- Improved guide sentences. - -## 4.8.1 - -- Improved the readability of the example code. -- Organized and clarified first guides. - -## 4.8.0 - -- Now by running `rifs template --bridge`, you can apply and update only the `bridge` module inside the `hub` crate. This is useful when you've upgraded RIF but do not need to apply the whole template again. -- Improved `rifs --help` output. - -## 4.7.0 - -- Now Rust stacktrace will be printed to the CLI when a panic occurs. The changes are mostly included in the template, so make sure you've run `rifs template` on this new version. - -## 4.6.2 - -- Polished various aspects. - -## 4.6.1 - -- Stabilized `debug_print!` logic. - -## 4.6.0 - -- New `debug_print!` macro that works on all environments, including web and mobile emulators, with the power of Flutter debuggers. To use this, you need to run `rifs template` again. -- Now panic information in Rust will be properly printed to the CLI. Note that Rust panics don't crash the app and do not hinder stability. -- Improved docs. There are also more guides about well-known types in Protobuf. Thanks @LucaCoduriV! - -## 4.5.0 - -- Added support for external symbols on iOS and macOS. This is needed for some Rust crates that depend on Apple's system frameworks. - -## 4.4.2 - -- Updated docs and demo links. - -## 4.4.1 - -- Updated docs and demo links. - -## 4.4.0 - -- Improved various guides and comments. -- Fixed a bug that made the app crash when passing in an empty `Vec`. -- Fixed the formatting of Rust files. - -## 4.3.0 - -- Now `flutter run` will use `require-corp` value for `cross-origin-embedder-policy` HTTP header that works on all web browsers. - -## 4.2.1 - -- Fixed a bug with `RustResponse::default()`. - -## 4.2.0 - -- New command `rifs --help`. Thanks @bookshiyi! - -## 4.1.4 - -- Fixed a sentence in the guides. - -## 4.1.3 - -- Made `rifs message` command read `PUB_CACHE` enviornment variable if present. Thanks @rabbitson87! - -## 4.1.2 - -- Fixed `rifs template` command. - -## 4.1.1 - -- Added some guides to the shorthand crate. -- Removed an unneeded dependency from the shorthand crate. - -## 4.1.0 - -- Fixed `sleep()` on the web. -- Added demo link in the guides. - -## 4.0.3 - -- Fixed bugs with `rifs template` on Windows. -- Fixed outdated comments. -- Organized sample code. - -## 4.0.2 - -- Eliminated an unnecessary Dart dependency. - -## 4.0.1 - -- Eliminated an unnecessary Dart dependency. - -## 4.0.0 - -- Added support for sending large binaries between Dart and Rust. This is now possible by using the `blob` field in `RustRequest`, `RustResponse`, and `RustSignal`. Please make sure you've run `rifs template` before using this new version because the template has changed a little. -- Added support for nested message folders. -- Added support for Rust nightly. -- Eliminated unnecessary Dart dependencies. - -## 3.7.4 - -- Updated `cargokit`, the build connector between Flutter and Rust. - -## 3.7.3 - -- Fixed a bug with cargo. - -## 3.7.2 - -- Fixed a bug with cargo. - -## 3.7.1 - -- Organized descriptions and files. - -## 3.7.0 - -- Now this framework provides a shorthand command `rifs ...` which is equivalent to `dart run rust_in_flutter ...`. - -## 3.6.0 - -- Fixed a bug that prevents the app from running on Linux. -- Improved various texts exposed to developers for clarity. - -## 3.5.1 - -- Bumped `prost` version to avoid snake case related warnings. - -## 3.5.0 - -- Shortend some names that were unnecessarily long. - -## 3.4.5 - -- Import statements became shorter in Dart. - -## 3.4.4 - -- Cleaned up outdated dependencies in `Cargo.toml`. - -## 3.4.3 - -- Now `syntax` and `package` statements in `.proto` files should be handled automatically. - -## 3.4.2 - -- Now running `dart run rust_in_flutter message` verifies `package` statement in `.proto` files and mistakes are fixed automatically. - -## 3.4.1 - -- Now match statement is used for handling requests. This improves code readability. - -## 3.4.0 - -- Now each `.proto` file is treated as a Rust resource, which essentially becomes an API endpoint. - -## 3.3.0 - -- `RustResource` enum has been added to `interaction.proto`. Now the list of available Rust resources are managed by Protobuf, which makes the project less error-prone. This new system also has less runtime overhead because interactions are distinguished by simple integers, not strings. - -## 3.2.3 - -- Improved guides. - -## 3.2.2 - -- Organized guides. - -## 3.2.1 - -- Matched first guides with the docs. - -## 3.2.0 - -- Now when applying the Rust template with `dart run rust_in_flutter template`, `README.md` file will get a new section explaining about this framework. - -## 3.1.1 - -- Updated docs link. - -## 3.1.0 - -- Now there's a new Dart command `message`. Developers can now generate Dart and Rust message code from `.proto` files with `dart run rust_in_flutter message`. `build.rs` file that used to do this is removed. - -## 3.0.9 - -- Fixed a problem with pub.dev score. - -## 3.0.8 - -- Fixed a problem with pub.dev score. - -## 3.0.7 - -- Fixed a problem with pub.dev score. - -## 3.0.6 - -- Fixed a problem with pub.dev score. - -## 3.0.5 - -- Moved documentation to a dedicated website. -- Now `build.rs` will automatically modify PATH for `protoc-gen-dart`. -- Fixed an error appearing in Rust-analyzer's webassembly mode. - -## 3.0.4 - -- Polished template code. - -## 3.0.3 - -- Polished template code. - -## 3.0.2 - -- Polished guides, comments and template code. - -## 3.0.1 - -- Fixed and organized tutorials and comments. - -## 3.0.0 - -- Adopted Protobuf for message serialization. Now communication between Dart and Rust is much more type-safe and faster than before. Because the template has now changed, you need to run `dart run rust_in_flutter template` again when migrating from version 2. Thanks @wheregmis` and @bookshiyi! - -## 2.9.0 - -- Removed `corrosion`. Now this package solely relies on `cargokit` and is much more slimmer. Thanks @bookshiyi! -- Removed unneeded files from pub.dev publication. - -## 2.8.5 - -- Fixed a problem with pub.dev score. - -## 2.8.4 - -- Fixed a problem with pub.dev score. - -## 2.8.3 - -- Wrote new catchphrase. - -## 2.8.2 - -- Updated links. - -## 2.8.1 - -- Updated links. - -## 2.8.0 - -- Removed unneeded dependencies. - -## 2.7.4 - -- Fixed CI badge showing rate limit error. - -## 2.7.3 - -- Fixed wrong guides. - -## 2.7.2 - -- Organized guides. - -## 2.7.1 - -- Organized guides. Thanks @bookshiyi! - -## 2.7.0 - -- Stabilized web-related Rust toolchain's auto-installation. Thanks @bookshiyi! - -## 2.6.0 - -- Applied continuous integration for checking builds and improving project stability. Thanks @bookshiyi! - -## 2.5.6 - -- Updated Cargokit. Thanks @bookshiyi! - -## 2.5.5 - -- Improved guides about HTTP headers. - -## 2.5.4 - -- Updated example code. - -## 2.5.3 - -- Improved guides and CLI messages. - -## 2.5.2 - -- Optimized web binary size. - -## 2.5.1 - -- Optimized web performance. - -## 2.5.0 - -- Now Rust logic will be restarted upon Dart's hot restart on the web too. -- CLI commands are shortened. - -## 2.4.0 - -- Fixed the problem with dangling threads from the `tokio` runtime remaining after closing the Flutter app. Even after the app window was closed, `tokio` threads were still running, resulting in becoming a background process without a window. Now the `tokio` runtime will properly be shut down. - -## 2.3.2 - -- Re-publishing due to `pub.dev`'s `[UNKNOWN PLATFORMS]` error. - -## 2.3.1 - -- Restored the benefits section in the first guide. - -## 2.3.0 - -- Improved Dart's hot restart process on native platforms. - -## 2.2.0 - -- Improved the procedure of building for the web. -- Simplfied unneeded complexities. - -## 2.1.2 - -- Improved web alias module. -- Fixed small things. - -## 2.1.1 - -- Optimized the bridge thread on native platforms. -- Updated many minor errors in the guides. -- Fixed a problem with import statement not being written in `./lib/main.dart` when applying Rust template. - -## 2.1.0 - -- Merged `frb_engine` crate into `hub`. -- Removed unneeded intermediate worker pools. -- Added `time` web alias import. -- Added many guides and comments. - -## 2.0.1 - -- Improved guides. -- Added `print!` web alias macro. -- Organized exposed Dart APIs. - -## 2.0.0 - -- Added web support. - -## 1.6.6 - -- Improved guides. -- Now, the template application command will check if the current directory is a Flutter project first. - -## 1.6.5 - -- Improved guides. - -## 1.6.4 - -- Organized guide sections. - -## 1.6.3 - -- Organized guide sections. - -## 1.6.2 - -- Filled in missing translations. - -## 1.6.1 - -- Slightly improved guide sections. - -## 1.6.0 - -- Added step-by-step guides. - -## 1.5.3 - -- Fixed some example app code. - -## 1.5.2 - -- Improved the readability of example app code. - -## 1.5.1 - -- Added Japanese translation. -- Fixed some sentences in Korean guides. - -## 1.5.0 - -- Now the Android NDK version that the Flutter SDK expects will be used, not the version specified by this package. -- Fixed a bug saying `IntoDart` trait is not implemented. - -## 1.4.1 - -- Improved various guides. - -## 1.4.0 - -- Filled in various guides to help developers understand the structure more easily. - -## 1.3.2 - -- Added Chinese guides. Thanks @moluopro! -- Added Korean guides. -- Added guides about build tool version issues. -- Added guides about library bundling. - -## 1.3.1 - -- Fixed a problem with Rust crate path detection on Android. - -## 1.3.0 - -- Changed the name of an exposed enum. Now `Operation` has changed to `RustOperation` so that it won't make confusions with other operations. All developers should update their code to match this new name, probably using the batch replace function in various IDEs. -- Updated code snippets. - -## 1.2.8 - -- Fixed small things. - -## 1.2.7 - -- Stabilized `main.dart` modifcation upon `dart run rust_in_flutter:apply_template`. - -## 1.2.6 - -- Hid the information regarding the compilation of connector crates to avoid confusion with actual crates. - -## 1.2.5 - -- Updated the guide about Android NDK version. - -## 1.2.4 - -- Updated many outdated comments and guides. -- Decreased the time spent on `ensureInitialized`. Also, `ensureInitialized()` is automatically inserted in `main.dart` when doing `dart run rust_in_flutter:apply_template` from now on. -- Various code improvements were applied. - -## 1.2.3 - -- Clarified template structure in guides. - -## 1.2.2 - -- Hide more Dart APIs that are not meant to be used outside. - -## 1.2.1 - -- Updated many comments. -- Fine-tuned the visibility of Dart APIs. -- Organized guides. - -## 1.2.0 - -- Made the Rust request handler more future-proof, taking potential web support into account. - -## 1.1.1 - -- Improved various guides to help understanding the features of this package. - -## 1.1.0 - -- Now this package is a Flutter FFI plugin without dummy native code. -- Improved guides - -## 1.0.4 - -- Fixed a problem with library bundling on Linux. -- Added comments. -- Added guides. -- Improved template application. - -## 1.0.3 - -- Included code snippets in guides. - -## 1.0.2 - -- Fixed typos. -- Organized inner code. - -## 1.0.1 - -- Enforced bundling on macOS and iOS. -- Improved pub score. -- Make `apply_rust` modify `.gitignore`. - -## 1.0.0 - -- Previously `flutter_rust_app_template`, now this is a small convenient framework that can be applied to existing Flutter projects. +## 6.12.0 + +- Generated message channels are now more efficient. +- Minimum Android SDK version increased from 16 to 21. Thanks @debanjanbasu! +- The `finalizeRust()` function in Dart has been removed. The `tokio` async runtime, which holds Rust logic, still drops automatically when the app ends. +- Bumped `prost` version to 0.12.6. Thanks @yeoupooh! +- Internal code has been organized. + +## 6.11.1 + +- Fixed a bug with Dart's extension methods in the generated message code. + +## 6.11.0 + +- Now it's possible to set the dynamic library's path. +- Now `rinf message` generates more memory-efficient and cleaner code. + +## 6.10.0 + +- Early Dart signals are now stored in the tokio channel instead of being ignored. Their performance is also slightly better. +- Excessive sample code is not included in the template from the `rinf template` command anymore. +- Now `tokio` is enabled by default in the template, not `tokio_with_wasm`. +- A configuration option, `rinf.message.rust_serde`, was added to make generated Rust message files compatible with `serde`. Thanks @NeoVance! + +## 6.9.2 + +- Early Dart signals have become more stable. + +## 6.9.1 + +- Now the memory allocation and drop is done in each language. + +## 6.9.0 + +- This version supports Flutter 3.22. +- The new version of Flutter has a little different way of resolving paths. This release adapts to this change. + +## 6.8.0 + +- Now `sendSignalToRust` and `send_signal_to_dart` methods no longer require `null` or `None`, making the API much cleaner. To make them include binary data, write `[RINF:DART-SIGNAL-BINARY]` or `[RINF:RUST-SIGNAL-BINARY]` in Protobuf files. +- The problem of panicking from null pointers that arise from empty signal data has been fixed. + +## 6.7.0 + +- Allowed `enum` and `oneof` statements to work in Protobuf message files. Thanks @yeoupooh! + +## 6.6.3 + +- Fixed a linting issue. Thanks @romanseo1! + +## 6.6.2 + +- Updated `tokio_with_wasm` to a newer version that addresses performance issues with `spawn_blocking`. +- Added example code that shows how to use global state in `sample_functions.rs` file. + +## 6.6.1 + +- Added support for some Linux distributions where patching Flutter SDK is not possible. +- Fixed a problem with the web sector not working. To use this new version, it's recommended to discard all Git changes in Flutter SDK's directory, or simply run `flutter upgrade --force`. +- Fixed a problem with `cd` error on Windows. Thanks @H2Sxxa! +- Fixed `pub.dev` package score. + +## 6.6.0 + +- Now early Rust signals on startup works properly, even if the widgets are not built yet. `rustSignalStream` will remember Rust signals that were received before widgets were built, and give them to the first listener. + +## 6.5.0 + +- Now the native library file is loaded as dynamic library, not static library, on iOS and macOS, like other platforms. This reduces the possibility of potential conflicts of native symbols. +- Now `rinf template` checks `pubspec.yaml` instead of `lib/main.dart` to ensure that the current folder is a Flutter project. + +## 6.4.0 + +- The start and stop mechanism of Rust has become more stable. + +## 6.3.1 + +- Fixed a small glitch with codegen. + +## 6.3.0 + +- The interface code has been organized. Now the `bridge` Rust module is gone and the API makes more sense. Please refer to the example code to upgrade. + +## 6.2.0 + +- Now custom installation of `protoc` works. This is useful when you don't have full access to GitHub APIs, which is needed for automatic `protoc` installation. Thanks @TENX-S! +- Signal handling has become more efficient. + +## 6.1.0 + +- Now `rustSignalStream`s `listen` can be called multiple times. Thanks @rabbitson87! + +## 6.0.1 + +- Improved CLI output texts. +- `js` Dart package was removed. + +## 6.0.0 + +- You need to run `rinf template`, `cargo install rinf` again to use this new version. +- Now the communication between Dart and Rust is much simpler. You can mark messages in `.proto` files so that Rinf's code generator can generate channels in-between. This new system is not compatible with older Rinf versions, so please check the docs before you upgrade. +- Added the ability to customize Rinf's behaviors by writing fields inside `pubspec.yaml` file. Thanks @thlorenz! +- Allowed users to check when the documentation page was made and edited. Thanks @VictorieeMan! +- Now it's possible to quit `rinf message --watch` by pressing `q` on your keyboard. +- Internal code has been organized. + +## 6.0.0-beta + +- This is a beta version. + +## 6.0.0-alpha + +- This is an alpha version. + +## 5.4.0 + +- Now users do not have to manually install `protoc` binary executable anymore. Protobuf compiler is now automatically installed. Note that you need to run `cargo install rinf` again to use this new version. + +## 5.3.1 + +- Fixed a bug with `rinf message` that omits `mod.rs` inside a folder without any message. + +## 5.3.0 + +- Now it is possible to use `import` statements in `.proto` files. +- Now you can properly use Flutter's hot restart while developing. +- Tutorials and guides are improved. +- Fixed a bug with `rinf message`, that might fail if some of the folders are empty. + +## 5.2.0 + +- Unnecessary memory copy is now avoided. + +## 5.1.3 + +- Fixed introductions. + +## 5.1.2 + +- Fixed a bug with memory freeing. + +## 5.1.1 + +- The codebase was organized further. +- Fixed a problem with Dart analysis. + +## 5.1.0 + +- All the code from `flutter_rust_bridge` was removed. This was due to criticisms about Rinf from the community and FRB devs. Also, internal bridge and FFI code is now much smaller. User API remains unchanged. + +## 5.0.0 + +- Now `requestToRust` Dart function will return `null` when the handler function in Rust cannot respond or has panicked. This is a breaking change, so when you upgrade to this version, you need to run `rinf template --bridge` in the terminal and refactor some of the code where IDE warns you about mismatches. You also need to modify `lib.rs` and `with_request.rs` modules of the `hub` crate. Also, the `timeout` parameter was removed from the `requestToRust` function because Dart will always get some return value from Rust in all cases. Please refer to the example code and documentation tutorials if you need detailed information. + +## 4.20.0 + +- Added support for Android Gradle Plugin 8. + +## 4.19.1 + +- Switched to the new official website `rinf.cunarist.com`. + +## 4.19.0 + +- The mechanism for awaiting Rust's responses from Dart has become much more efficient. + +## 4.18.0 + +- Now `null` can be provided to the `timeout` parameter in the `requestToRust()` Dart function. This enables awaiting a Rust response forever, but it should be used cautiously because it may potentially lead to resource leaks. + +## 4.17.1 + +- Now `rinf message --watch` works on all platforms. Thanks @bookshiyi! + +## 4.17.0 + +- New command `rinf message --watch` for automatic message code generation. Thanks @bookshiyi! + +## 4.16.3 + +- Updated package descriptions. + +## 4.16.2 + +- Improved guides to avoid misconceptions about the communication system. Rinf only uses FFI without any web server. + +## 4.16.1 + +- Fixed the broken `rinf template --bridge` command + +## 4.16.0 + +- Vastly organized files, dependencies, and code readability. Now the `hub` crate is much cleaner than before. If you already have an app using older Rinf versions, it is recommended to run `rinf template --bridge` and add `rinf = "4.16.0"` to `Cargo.toml` of the `hub` crate. + +## 4.15.2 + +- Now the web API fetching example uses `http` instead of `https` in the example app. + +## 4.15.1 + +- Now the `reqwest` crate will be disabled when compiling the example app for Android. + +## 4.15.0 + +- Allowed setting custom timeout when using `requestToRust()`. Thanks @cipherchabon! + +## 4.14.0 + +- Added a web API fetching example to the template. +- Fixed various things such as template comments, code linting issues. + +## 4.13.2 + +- Fixed small things. + +## 4.13.1 + +- Fixed formatting issues in Dart code. + +## 4.13.0 + +- Improved the template code by disabling CPU-intensive tasks and removing unneeded dependency features. +- Improved CLI outputs from `rinf wasm`. +- Improved various guides and template comments. + +## 4.12.5 + +- Automated publication. + +## 4.12.4 + +- Fixed permission related problems with build script files. + +## 4.12.3 + +- Fixed permission related problems with build script files. + +## 4.12.2 + +- Fixed guide badges. + +## 4.12.1 + +- Fixed publishing issues. + +## 4.12.0 + +- Renamed the framework to Rinf. + +## 4.11.8 + +- Improved first guides. + +## 4.11.7 + +- Improved the example app's code and guides. + +## 4.11.6 + +- Improved the shorthand command crate. + +## 4.11.5 + +- Improved the shorthand command crate. + +## 4.11.4 + +- Improved the first preview image and some comments. + +## 4.11.3 + +- Improved the example app's code. + +## 4.11.2 + +- Fixed a problem with compilation on macOS. + +## 4.11.1 + +- Fixed a problem with compilation on macOS. + +## 4.11.0 + +- New Dart function `ensureFinalized()`. This function ensures that all Rust tasks are terminated. Take a look at the example code to understand how to run this function before closing the Flutter app. Note that you have to run `rifs template --bridge` again to use this function. + +## 4.10.0 + +- New default web alias `spawn_blocking()`. CPU-intensive blocking tasks are better to be executed on a separate thread pool. +- Improved the example app's performance and debug tests. + +## 4.9.0 + +- New default web alias `yield_now()`. Inside a long-running code, calling this will help you avoid blocking the whole async event loop, by giving the flow back to other async tasks. +- Vastly improved comments inside the `web_alias` Rust module. +- Now Rust panics on the web will be printed to the CLI too. +- Improved the example app's performance and debug tests. + +## 4.8.2 + +- Improved guide sentences. + +## 4.8.1 + +- Improved the readability of the example code. +- Organized and clarified first guides. + +## 4.8.0 + +- Now by running `rifs template --bridge`, you can apply and update only the `bridge` module inside the `hub` crate. This is useful when you've upgraded RIF but do not need to apply the whole template again. +- Improved `rifs --help` output. + +## 4.7.0 + +- Now Rust stacktrace will be printed to the CLI when a panic occurs. The changes are mostly included in the template, so make sure you've run `rifs template` on this new version. + +## 4.6.2 + +- Polished various aspects. + +## 4.6.1 + +- Stabilized `debug_print!` logic. + +## 4.6.0 + +- New `debug_print!` macro that works on all environments, including web and mobile emulators, with the power of Flutter debuggers. To use this, you need to run `rifs template` again. +- Now panic information in Rust will be properly printed to the CLI. Note that Rust panics don't crash the app and do not hinder stability. +- Improved docs. There are also more guides about well-known types in Protobuf. Thanks @LucaCoduriV! + +## 4.5.0 + +- Added support for external symbols on iOS and macOS. This is needed for some Rust crates that depend on Apple's system frameworks. + +## 4.4.2 + +- Updated docs and demo links. + +## 4.4.1 + +- Updated docs and demo links. + +## 4.4.0 + +- Improved various guides and comments. +- Fixed a bug that made the app crash when passing in an empty `Vec`. +- Fixed the formatting of Rust files. + +## 4.3.0 + +- Now `flutter run` will use `require-corp` value for `cross-origin-embedder-policy` HTTP header that works on all web browsers. + +## 4.2.1 + +- Fixed a bug with `RustResponse::default()`. + +## 4.2.0 + +- New command `rifs --help`. Thanks @bookshiyi! + +## 4.1.4 + +- Fixed a sentence in the guides. + +## 4.1.3 + +- Made `rifs message` command read `PUB_CACHE` enviornment variable if present. Thanks @rabbitson87! + +## 4.1.2 + +- Fixed `rifs template` command. + +## 4.1.1 + +- Added some guides to the shorthand crate. +- Removed an unneeded dependency from the shorthand crate. + +## 4.1.0 + +- Fixed `sleep()` on the web. +- Added demo link in the guides. + +## 4.0.3 + +- Fixed bugs with `rifs template` on Windows. +- Fixed outdated comments. +- Organized sample code. + +## 4.0.2 + +- Eliminated an unnecessary Dart dependency. + +## 4.0.1 + +- Eliminated an unnecessary Dart dependency. + +## 4.0.0 + +- Added support for sending large binaries between Dart and Rust. This is now possible by using the `blob` field in `RustRequest`, `RustResponse`, and `RustSignal`. Please make sure you've run `rifs template` before using this new version because the template has changed a little. +- Added support for nested message folders. +- Added support for Rust nightly. +- Eliminated unnecessary Dart dependencies. + +## 3.7.4 + +- Updated `cargokit`, the build connector between Flutter and Rust. + +## 3.7.3 + +- Fixed a bug with cargo. + +## 3.7.2 + +- Fixed a bug with cargo. + +## 3.7.1 + +- Organized descriptions and files. + +## 3.7.0 + +- Now this framework provides a shorthand command `rifs ...` which is equivalent to `dart run rust_in_flutter ...`. + +## 3.6.0 + +- Fixed a bug that prevents the app from running on Linux. +- Improved various texts exposed to developers for clarity. + +## 3.5.1 + +- Bumped `prost` version to avoid snake case related warnings. + +## 3.5.0 + +- Shortend some names that were unnecessarily long. + +## 3.4.5 + +- Import statements became shorter in Dart. + +## 3.4.4 + +- Cleaned up outdated dependencies in `Cargo.toml`. + +## 3.4.3 + +- Now `syntax` and `package` statements in `.proto` files should be handled automatically. + +## 3.4.2 + +- Now running `dart run rust_in_flutter message` verifies `package` statement in `.proto` files and mistakes are fixed automatically. + +## 3.4.1 + +- Now match statement is used for handling requests. This improves code readability. + +## 3.4.0 + +- Now each `.proto` file is treated as a Rust resource, which essentially becomes an API endpoint. + +## 3.3.0 + +- `RustResource` enum has been added to `interaction.proto`. Now the list of available Rust resources are managed by Protobuf, which makes the project less error-prone. This new system also has less runtime overhead because interactions are distinguished by simple integers, not strings. + +## 3.2.3 + +- Improved guides. + +## 3.2.2 + +- Organized guides. + +## 3.2.1 + +- Matched first guides with the docs. + +## 3.2.0 + +- Now when applying the Rust template with `dart run rust_in_flutter template`, `README.md` file will get a new section explaining about this framework. + +## 3.1.1 + +- Updated docs link. + +## 3.1.0 + +- Now there's a new Dart command `message`. Developers can now generate Dart and Rust message code from `.proto` files with `dart run rust_in_flutter message`. `build.rs` file that used to do this is removed. + +## 3.0.9 + +- Fixed a problem with pub.dev score. + +## 3.0.8 + +- Fixed a problem with pub.dev score. + +## 3.0.7 + +- Fixed a problem with pub.dev score. + +## 3.0.6 + +- Fixed a problem with pub.dev score. + +## 3.0.5 + +- Moved documentation to a dedicated website. +- Now `build.rs` will automatically modify PATH for `protoc-gen-dart`. +- Fixed an error appearing in Rust-analyzer's webassembly mode. + +## 3.0.4 + +- Polished template code. + +## 3.0.3 + +- Polished template code. + +## 3.0.2 + +- Polished guides, comments and template code. + +## 3.0.1 + +- Fixed and organized tutorials and comments. + +## 3.0.0 + +- Adopted Protobuf for message serialization. Now communication between Dart and Rust is much more type-safe and faster than before. Because the template has now changed, you need to run `dart run rust_in_flutter template` again when migrating from version 2. Thanks @wheregmis` and @bookshiyi! + +## 2.9.0 + +- Removed `corrosion`. Now this package solely relies on `cargokit` and is much more slimmer. Thanks @bookshiyi! +- Removed unneeded files from pub.dev publication. + +## 2.8.5 + +- Fixed a problem with pub.dev score. + +## 2.8.4 + +- Fixed a problem with pub.dev score. + +## 2.8.3 + +- Wrote new catchphrase. + +## 2.8.2 + +- Updated links. + +## 2.8.1 + +- Updated links. + +## 2.8.0 + +- Removed unneeded dependencies. + +## 2.7.4 + +- Fixed CI badge showing rate limit error. + +## 2.7.3 + +- Fixed wrong guides. + +## 2.7.2 + +- Organized guides. + +## 2.7.1 + +- Organized guides. Thanks @bookshiyi! + +## 2.7.0 + +- Stabilized web-related Rust toolchain's auto-installation. Thanks @bookshiyi! + +## 2.6.0 + +- Applied continuous integration for checking builds and improving project stability. Thanks @bookshiyi! + +## 2.5.6 + +- Updated Cargokit. Thanks @bookshiyi! + +## 2.5.5 + +- Improved guides about HTTP headers. + +## 2.5.4 + +- Updated example code. + +## 2.5.3 + +- Improved guides and CLI messages. + +## 2.5.2 + +- Optimized web binary size. + +## 2.5.1 + +- Optimized web performance. + +## 2.5.0 + +- Now Rust logic will be restarted upon Dart's hot restart on the web too. +- CLI commands are shortened. + +## 2.4.0 + +- Fixed the problem with dangling threads from the `tokio` runtime remaining after closing the Flutter app. Even after the app window was closed, `tokio` threads were still running, resulting in becoming a background process without a window. Now the `tokio` runtime will properly be shut down. + +## 2.3.2 + +- Re-publishing due to `pub.dev`'s `[UNKNOWN PLATFORMS]` error. + +## 2.3.1 + +- Restored the benefits section in the first guide. + +## 2.3.0 + +- Improved Dart's hot restart process on native platforms. + +## 2.2.0 + +- Improved the procedure of building for the web. +- Simplfied unneeded complexities. + +## 2.1.2 + +- Improved web alias module. +- Fixed small things. + +## 2.1.1 + +- Optimized the bridge thread on native platforms. +- Updated many minor errors in the guides. +- Fixed a problem with import statement not being written in `./lib/main.dart` when applying Rust template. + +## 2.1.0 + +- Merged `frb_engine` crate into `hub`. +- Removed unneeded intermediate worker pools. +- Added `time` web alias import. +- Added many guides and comments. + +## 2.0.1 + +- Improved guides. +- Added `print!` web alias macro. +- Organized exposed Dart APIs. + +## 2.0.0 + +- Added web support. + +## 1.6.6 + +- Improved guides. +- Now, the template application command will check if the current directory is a Flutter project first. + +## 1.6.5 + +- Improved guides. + +## 1.6.4 + +- Organized guide sections. + +## 1.6.3 + +- Organized guide sections. + +## 1.6.2 + +- Filled in missing translations. + +## 1.6.1 + +- Slightly improved guide sections. + +## 1.6.0 + +- Added step-by-step guides. + +## 1.5.3 + +- Fixed some example app code. + +## 1.5.2 + +- Improved the readability of example app code. + +## 1.5.1 + +- Added Japanese translation. +- Fixed some sentences in Korean guides. + +## 1.5.0 + +- Now the Android NDK version that the Flutter SDK expects will be used, not the version specified by this package. +- Fixed a bug saying `IntoDart` trait is not implemented. + +## 1.4.1 + +- Improved various guides. + +## 1.4.0 + +- Filled in various guides to help developers understand the structure more easily. + +## 1.3.2 + +- Added Chinese guides. Thanks @moluopro! +- Added Korean guides. +- Added guides about build tool version issues. +- Added guides about library bundling. + +## 1.3.1 + +- Fixed a problem with Rust crate path detection on Android. + +## 1.3.0 + +- Changed the name of an exposed enum. Now `Operation` has changed to `RustOperation` so that it won't make confusions with other operations. All developers should update their code to match this new name, probably using the batch replace function in various IDEs. +- Updated code snippets. + +## 1.2.8 + +- Fixed small things. + +## 1.2.7 + +- Stabilized `main.dart` modifcation upon `dart run rust_in_flutter:apply_template`. + +## 1.2.6 + +- Hid the information regarding the compilation of connector crates to avoid confusion with actual crates. + +## 1.2.5 + +- Updated the guide about Android NDK version. + +## 1.2.4 + +- Updated many outdated comments and guides. +- Decreased the time spent on `ensureInitialized`. Also, `ensureInitialized()` is automatically inserted in `main.dart` when doing `dart run rust_in_flutter:apply_template` from now on. +- Various code improvements were applied. + +## 1.2.3 + +- Clarified template structure in guides. + +## 1.2.2 + +- Hide more Dart APIs that are not meant to be used outside. + +## 1.2.1 + +- Updated many comments. +- Fine-tuned the visibility of Dart APIs. +- Organized guides. + +## 1.2.0 + +- Made the Rust request handler more future-proof, taking potential web support into account. + +## 1.1.1 + +- Improved various guides to help understanding the features of this package. + +## 1.1.0 + +- Now this package is a Flutter FFI plugin without dummy native code. +- Improved guides + +## 1.0.4 + +- Fixed a problem with library bundling on Linux. +- Added comments. +- Added guides. +- Improved template application. + +## 1.0.3 + +- Included code snippets in guides. + +## 1.0.2 + +- Fixed typos. +- Organized inner code. + +## 1.0.1 + +- Enforced bundling on macOS and iOS. +- Improved pub score. +- Make `apply_rust` modify `.gitignore`. + +## 1.0.0 + +- Previously `flutter_rust_app_template`, now this is a small convenient framework that can be applied to existing Flutter projects. diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index d51fbbd68..a8e0c456c 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" crate-type = ["lib", "cdylib", "staticlib"] [dependencies] -rinf = "6.11.1" +rinf = "6.12.0" prost = "0.12.6" # tokio = { version = "1", features = ["sync"] } wasm-bindgen = "0.2.92" # Uncomment this line to target the web diff --git a/flutter_ffi_plugin/pubspec.yaml b/flutter_ffi_plugin/pubspec.yaml index 2a04a432b..44ef2ded6 100644 --- a/flutter_ffi_plugin/pubspec.yaml +++ b/flutter_ffi_plugin/pubspec.yaml @@ -1,82 +1,82 @@ -name: rinf -description: Rust for native business logic, Flutter for flexible and beautiful GUI -version: 6.11.1 -repository: https://github.com/cunarist/rinf - -environment: - sdk: ">=3.0.5 <4.0.0" - flutter: ">=3.3.0" - -dependencies: - flutter: - sdk: flutter - package_config: ^2.1.0 - path: ^1.8.3 - watcher: ^1.1.0 - ffi: ^2.1.0 - yaml: ^3.1.2 - -dev_dependencies: - lints: ">=3.0.0 <5.0.0" - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - # This section identifies this Flutter project as a plugin project. - # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) - # which should be registered in the plugin registry. This is required for - # using method channels. - # The Android 'package' specifies package in which the registered class is. - # This is required for using method channels on Android. - # The 'ffiPlugin' specifies that native code should be built and bundled. - # This is required for using `dart:ffi`. - # All these are used by the tooling to maintain consistency when - # adding or updating assets for this project. - # - # Please refer to README.md for a detailed explanation. - plugin: - platforms: - android: - ffiPlugin: true - ios: - ffiPlugin: true - linux: - ffiPlugin: true - macos: - ffiPlugin: true - windows: - ffiPlugin: true - web: - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages +name: rinf +description: Rust for native business logic, Flutter for flexible and beautiful GUI +version: 6.12.0 +repository: https://github.com/cunarist/rinf + +environment: + sdk: ">=3.0.5 <4.0.0" + flutter: ">=3.3.0" + +dependencies: + flutter: + sdk: flutter + package_config: ^2.1.0 + path: ^1.8.3 + watcher: ^1.1.0 + ffi: ^2.1.0 + yaml: ^3.1.2 + +dev_dependencies: + lints: ">=3.0.0 <5.0.0" + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) + # which should be registered in the plugin registry. This is required for + # using method channels. + # The Android 'package' specifies package in which the registered class is. + # This is required for using method channels on Android. + # The 'ffiPlugin' specifies that native code should be built and bundled. + # This is required for using `dart:ffi`. + # All these are used by the tooling to maintain consistency when + # adding or updating assets for this project. + # + # Please refer to README.md for a detailed explanation. + plugin: + platforms: + android: + ffiPlugin: true + ios: + ffiPlugin: true + linux: + ffiPlugin: true + macos: + ffiPlugin: true + windows: + ffiPlugin: true + web: + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index 50eb7b496..341223574 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -1,19 +1,19 @@ -[package] -# Do not change the name of this crate. -name = "hub" -version = "0.1.0" -edition = "2021" - -[lib] -# `lib` is required for non-library targets, -# such as tests and benchmarks. -# `cdylib` is for Linux, Android, Windows, and web. -# `staticlib` is for iOS and macOS. -crate-type = ["lib", "cdylib", "staticlib"] - -[dependencies] -rinf = "6.11.1" -prost = "0.12.6" -tokio = { version = "1", features = ["sync"] } -# wasm-bindgen = "0.2.92" # Uncomment this line to target the web -# tokio_with_wasm = "0.4.4" # Uncomment this line to target the web +[package] +# Do not change the name of this crate. +name = "hub" +version = "0.1.0" +edition = "2021" + +[lib] +# `lib` is required for non-library targets, +# such as tests and benchmarks. +# `cdylib` is for Linux, Android, Windows, and web. +# `staticlib` is for iOS and macOS. +crate-type = ["lib", "cdylib", "staticlib"] + +[dependencies] +rinf = "6.12.0" +prost = "0.12.6" +tokio = { version = "1", features = ["sync"] } +# wasm-bindgen = "0.2.92" # Uncomment this line to target the web +# tokio_with_wasm = "0.4.4" # Uncomment this line to target the web diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index 89713e869..77db03570 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -1,23 +1,23 @@ -[package] -name = "rinf" -version = "6.11.1" -edition = "2021" -license = "MIT" -description = "Rust for native business logic, Flutter for flexible and beautiful GUI" -repository = "https://github.com/cunarist/rinf" -documentation = "https://rinf.cunarist.com" -rust-version = "1.70" - -[target.'cfg(not(target_family = "wasm"))'.dependencies] -os-thread-local = "0.1.3" -backtrace = "0.3.69" -protoc-prebuilt = "0.3.0" -home = "0.5.9" -which = "6.0.0" -allo-isolate = "0.1.24" -tokio = { version = "1", features = ["rt-multi-thread"] } - -[target.'cfg(target_family = "wasm")'.dependencies] -js-sys = "0.3.69" -wasm-bindgen = "0.2.92" -wasm-bindgen-futures = "0.4.42" +[package] +name = "rinf" +version = "6.12.0" +edition = "2021" +license = "MIT" +description = "Rust for native business logic, Flutter for flexible and beautiful GUI" +repository = "https://github.com/cunarist/rinf" +documentation = "https://rinf.cunarist.com" +rust-version = "1.70" + +[target.'cfg(not(target_family = "wasm"))'.dependencies] +os-thread-local = "0.1.3" +backtrace = "0.3.69" +protoc-prebuilt = "0.3.0" +home = "0.5.9" +which = "6.0.0" +allo-isolate = "0.1.24" +tokio = { version = "1", features = ["rt-multi-thread"] } + +[target.'cfg(target_family = "wasm")'.dependencies] +js-sys = "0.3.69" +wasm-bindgen = "0.2.92" +wasm-bindgen-futures = "0.4.42" From f474fdb27b22b6d29cdfe1c16f2f5ecbb1e81c5e Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 00:14:39 +0900 Subject: [PATCH 041/128] Change linefeed to LF for some files --- CHANGELOG.md | 1610 ++++++++--------- flutter_ffi_plugin/CHANGELOG.md | 1610 ++++++++--------- flutter_ffi_plugin/pubspec.yaml | 164 +- .../template/native/hub/Cargo.toml | 38 +- rust_crate/Cargo.toml | 46 +- 5 files changed, 1734 insertions(+), 1734 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffe147e0c..8bac09b83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,805 +1,805 @@ -## 6.12.0 - -- Generated message channels are now more efficient. -- Minimum Android SDK version increased from 16 to 21. Thanks @debanjanbasu! -- The `finalizeRust()` function in Dart has been removed. The `tokio` async runtime, which holds Rust logic, still drops automatically when the app ends. -- Bumped `prost` version to 0.12.6. Thanks @yeoupooh! -- Internal code has been organized. - -## 6.11.1 - -- Fixed a bug with Dart's extension methods in the generated message code. - -## 6.11.0 - -- Now it's possible to set the dynamic library's path. -- Now `rinf message` generates more memory-efficient and cleaner code. - -## 6.10.0 - -- Early Dart signals are now stored in the tokio channel instead of being ignored. Their performance is also slightly better. -- Excessive sample code is not included in the template from the `rinf template` command anymore. -- Now `tokio` is enabled by default in the template, not `tokio_with_wasm`. -- A configuration option, `rinf.message.rust_serde`, was added to make generated Rust message files compatible with `serde`. Thanks @NeoVance! - -## 6.9.2 - -- Early Dart signals have become more stable. - -## 6.9.1 - -- Now the memory allocation and drop is done in each language. - -## 6.9.0 - -- This version supports Flutter 3.22 -- The new version of Flutter has a little different way of resolving paths. This release adapts to this change. - -## 6.8.0 - -- Now `sendSignalToRust` and `send_signal_to_dart` methods no longer require `null` or `None`, making the API much cleaner. To make them include binary data, write `[RINF:DART-SIGNAL-BINARY]` or `[RINF:RUST-SIGNAL-BINARY]` in Protobuf files. -- The problem of panicking from null pointers that arise from empty signal data has been fixed. - -## 6.7.0 - -- Allowed `enum` and `oneof` statements to work in Protobuf message files. Thanks @yeoupooh! - -## 6.6.3 - -- Fixed a linting issue. Thanks @romanseo1! - -## 6.6.2 - -- Updated `tokio_with_wasm` to a newer version that addresses performance issues with `spawn_blocking`. -- Added example code that shows how to use global state in `sample_functions.rs` file. - -## 6.6.1 - -- Added support for some Linux distributions where patching Flutter SDK is not possible. -- Fixed a problem with the web sector not working. To use this new version, it's recommended to discard all Git changes in Flutter SDK's directory, or simply run `flutter upgrade --force`. -- Fixed a problem with `cd` error on Windows. Thanks @H2Sxxa! -- Fixed `pub.dev` package score. - -## 6.6.0 - -- Now early Rust signals on startup works properly, even if the widgets are not built yet. `rustSignalStream` will remember Rust signals that were received before widgets were built, and give them to the first listener. - -## 6.5.0 - -- Now the native library file is loaded as dynamic library, not static library, on iOS and macOS, like other platforms. This reduces the possibility of potential conflicts of native symbols. -- Now `rinf template` checks `pubspec.yaml` instead of `lib/main.dart` to ensure that the current folder is a Flutter project. - -## 6.4.0 - -- The start and stop mechanism of Rust has become more stable. - -## 6.3.1 - -- Fixed a small glitch with codegen. - -## 6.3.0 - -- The interface code has been organized. Now the `bridge` Rust module is gone and the API makes more sense. Please refer to the example code to upgrade. - -## 6.2.0 - -- Now custom installation of `protoc` works. This is useful when you don't have full access to GitHub APIs, which is needed for automatic `protoc` installation. Thanks @TENX-S! -- Signal handling has become more efficient. - -## 6.1.0 - -- Now `rustSignalStream`s `listen` can be called multiple times. Thanks @rabbitson87! - -## 6.0.1 - -- Improved CLI output texts. -- `js` Dart package was removed. - -## 6.0.0 - -- You need to run `rinf template`, `cargo install rinf` again to use this new version. -- Now the communication between Dart and Rust is much simpler. You can mark messages in `.proto` files so that Rinf's code generator can generate channels in-between. This new system is not compatible with older Rinf versions, so please check the docs before you upgrade. -- Added the ability to customize Rinf's behaviors by writing fields inside `pubspec.yaml` file. Thanks @thlorenz! -- Allowed users to check when the documentation page was made and edited. Thanks @VictorieeMan! -- Now it's possible to quit `rinf message --watch` by pressing `q` on your keyboard. -- Internal code has been organized. - -## 6.0.0-beta - -- This is a beta version. - -## 6.0.0-alpha - -- This is an alpha version. - -## 5.4.0 - -- Now users do not have to manually install `protoc` binary executable anymore. Protobuf compiler is now automatically installed. Note that you need to run `cargo install rinf` again to use this new version. - -## 5.3.1 - -- Fixed a bug with `rinf message` that omits `mod.rs` inside a folder without any message. - -## 5.3.0 - -- Now it is possible to use `import` statements in `.proto` files. -- Now you can properly use Flutter's hot restart while developing. -- Tutorials and guides are improved. -- Fixed a bug with `rinf message`, that might fail if some of the folders are empty. - -## 5.2.0 - -- Unnecessary memory copy is now avoided. - -## 5.1.3 - -- Fixed introductions. - -## 5.1.2 - -- Fixed a bug with memory freeing. - -## 5.1.1 - -- The codebase was organized further. -- Fixed a problem with Dart analysis. - -## 5.1.0 - -- All the code from `flutter_rust_bridge` was removed. This was due to criticisms about Rinf from the community and FRB devs. Also, internal bridge and FFI code is now much smaller. User API remains unchanged. - -## 5.0.0 - -- Now `requestToRust` Dart function will return `null` when the handler function in Rust cannot respond or has panicked. This is a breaking change, so when you upgrade to this version, you need to run `rinf template --bridge` in the terminal and refactor some of the code where IDE warns you about mismatches. You also need to modify `lib.rs` and `with_request.rs` modules of the `hub` crate. Also, the `timeout` parameter was removed from the `requestToRust` function because Dart will always get some return value from Rust in all cases. Please refer to the example code and documentation tutorials if you need detailed information. - -## 4.20.0 - -- Added support for Android Gradle Plugin 8. - -## 4.19.1 - -- Switched to the new official website `rinf.cunarist.com`. - -## 4.19.0 - -- The mechanism for awaiting Rust's responses from Dart has become much more efficient. - -## 4.18.0 - -- Now `null` can be provided to the `timeout` parameter in the `requestToRust()` Dart function. This enables awaiting a Rust response forever, but it should be used cautiously because it may potentially lead to resource leaks. - -## 4.17.1 - -- Now `rinf message --watch` works on all platforms. Thanks @bookshiyi! - -## 4.17.0 - -- New command `rinf message --watch` for automatic message code generation. Thanks @bookshiyi! - -## 4.16.3 - -- Updated package descriptions. - -## 4.16.2 - -- Improved guides to avoid misconceptions about the communication system. Rinf only uses FFI without any web server. - -## 4.16.1 - -- Fixed the broken `rinf template --bridge` command - -## 4.16.0 - -- Vastly organized files, dependencies, and code readability. Now the `hub` crate is much cleaner than before. If you already have an app using older Rinf versions, it is recommended to run `rinf template --bridge` and add `rinf = "4.16.0"` to `Cargo.toml` of the `hub` crate. - -## 4.15.2 - -- Now the web API fetching example uses `http` instead of `https` in the example app. - -## 4.15.1 - -- Now the `reqwest` crate will be disabled when compiling the example app for Android. - -## 4.15.0 - -- Allowed setting custom timeout when using `requestToRust()`. Thanks @cipherchabon! - -## 4.14.0 - -- Added a web API fetching example to the template. -- Fixed various things such as template comments, code linting issues. - -## 4.13.2 - -- Fixed small things. - -## 4.13.1 - -- Fixed formatting issues in Dart code. - -## 4.13.0 - -- Improved the template code by disabling CPU-intensive tasks and removing unneeded dependency features. -- Improved CLI outputs from `rinf wasm`. -- Improved various guides and template comments. - -## 4.12.5 - -- Automated publication. - -## 4.12.4 - -- Fixed permission related problems with build script files. - -## 4.12.3 - -- Fixed permission related problems with build script files. - -## 4.12.2 - -- Fixed guide badges. - -## 4.12.1 - -- Fixed publishing issues. - -## 4.12.0 - -- Renamed the framework to Rinf. - -## 4.11.8 - -- Improved first guides. - -## 4.11.7 - -- Improved the example app's code and guides. - -## 4.11.6 - -- Improved the shorthand command crate. - -## 4.11.5 - -- Improved the shorthand command crate. - -## 4.11.4 - -- Improved the first preview image and some comments. - -## 4.11.3 - -- Improved the example app's code. - -## 4.11.2 - -- Fixed a problem with compilation on macOS. - -## 4.11.1 - -- Fixed a problem with compilation on macOS. - -## 4.11.0 - -- New Dart function `ensureFinalized()`. This function ensures that all Rust tasks are terminated. Take a look at the example code to understand how to run this function before closing the Flutter app. Note that you have to run `rifs template --bridge` again to use this function. - -## 4.10.0 - -- New default web alias `spawn_blocking()`. CPU-intensive blocking tasks are better to be executed on a separate thread pool. -- Improved the example app's performance and debug tests. - -## 4.9.0 - -- New default web alias `yield_now()`. Inside a long-running code, calling this will help you avoid blocking the whole async event loop, by giving the flow back to other async tasks. -- Vastly improved comments inside the `web_alias` Rust module. -- Now Rust panics on the web will be printed to the CLI too. -- Improved the example app's performance and debug tests. - -## 4.8.2 - -- Improved guide sentences. - -## 4.8.1 - -- Improved the readability of the example code. -- Organized and clarified first guides. - -## 4.8.0 - -- Now by running `rifs template --bridge`, you can apply and update only the `bridge` module inside the `hub` crate. This is useful when you've upgraded RIF but do not need to apply the whole template again. -- Improved `rifs --help` output. - -## 4.7.0 - -- Now Rust stacktrace will be printed to the CLI when a panic occurs. The changes are mostly included in the template, so make sure you've run `rifs template` on this new version. - -## 4.6.2 - -- Polished various aspects. - -## 4.6.1 - -- Stabilized `debug_print!` logic. - -## 4.6.0 - -- New `debug_print!` macro that works on all environments, including web and mobile emulators, with the power of Flutter debuggers. To use this, you need to run `rifs template` again. -- Now panic information in Rust will be properly printed to the CLI. Note that Rust panics don't crash the app and do not hinder stability. -- Improved docs. There are also more guides about well-known types in Protobuf. Thanks @LucaCoduriV! - -## 4.5.0 - -- Added support for external symbols on iOS and macOS. This is needed for some Rust crates that depend on Apple's system frameworks. - -## 4.4.2 - -- Updated docs and demo links. - -## 4.4.1 - -- Updated docs and demo links. - -## 4.4.0 - -- Improved various guides and comments. -- Fixed a bug that made the app crash when passing in an empty `Vec`. -- Fixed the formatting of Rust files. - -## 4.3.0 - -- Now `flutter run` will use `require-corp` value for `cross-origin-embedder-policy` HTTP header that works on all web browsers. - -## 4.2.1 - -- Fixed a bug with `RustResponse::default()`. - -## 4.2.0 - -- New command `rifs --help`. Thanks @bookshiyi! - -## 4.1.4 - -- Fixed a sentence in the guides. - -## 4.1.3 - -- Made `rifs message` command read `PUB_CACHE` enviornment variable if present. Thanks @rabbitson87! - -## 4.1.2 - -- Fixed `rifs template` command. - -## 4.1.1 - -- Added some guides to the shorthand crate. -- Removed an unneeded dependency from the shorthand crate. - -## 4.1.0 - -- Fixed `sleep()` on the web. -- Added demo link in the guides. - -## 4.0.3 - -- Fixed bugs with `rifs template` on Windows. -- Fixed outdated comments. -- Organized sample code. - -## 4.0.2 - -- Eliminated an unnecessary Dart dependency. - -## 4.0.1 - -- Eliminated an unnecessary Dart dependency. - -## 4.0.0 - -- Added support for sending large binaries between Dart and Rust. This is now possible by using the `blob` field in `RustRequest`, `RustResponse`, and `RustSignal`. Please make sure you've run `rifs template` before using this new version because the template has changed a little. -- Added support for nested message folders. -- Added support for Rust nightly. -- Eliminated unnecessary Dart dependencies. - -## 3.7.4 - -- Updated `cargokit`, the build connector between Flutter and Rust. - -## 3.7.3 - -- Fixed a bug with cargo. - -## 3.7.2 - -- Fixed a bug with cargo. - -## 3.7.1 - -- Organized descriptions and files. - -## 3.7.0 - -- Now this framework provides a shorthand command `rifs ...` which is equivalent to `dart run rust_in_flutter ...`. - -## 3.6.0 - -- Fixed a bug that prevents the app from running on Linux. -- Improved various texts exposed to developers for clarity. - -## 3.5.1 - -- Bumped `prost` version to avoid snake case related warnings. - -## 3.5.0 - -- Shortend some names that were unnecessarily long. - -## 3.4.5 - -- Import statements became shorter in Dart. - -## 3.4.4 - -- Cleaned up outdated dependencies in `Cargo.toml`. - -## 3.4.3 - -- Now `syntax` and `package` statements in `.proto` files should be handled automatically. - -## 3.4.2 - -- Now running `dart run rust_in_flutter message` verifies `package` statement in `.proto` files and mistakes are fixed automatically. - -## 3.4.1 - -- Now match statement is used for handling requests. This improves code readability. - -## 3.4.0 - -- Now each `.proto` file is treated as a Rust resource, which essentially becomes an API endpoint. - -## 3.3.0 - -- `RustResource` enum has been added to `interaction.proto`. Now the list of available Rust resources are managed by Protobuf, which makes the project less error-prone. This new system also has less runtime overhead because interactions are distinguished by simple integers, not strings. - -## 3.2.3 - -- Improved guides. - -## 3.2.2 - -- Organized guides. - -## 3.2.1 - -- Matched first guides with the docs. - -## 3.2.0 - -- Now when applying the Rust template with `dart run rust_in_flutter template`, `README.md` file will get a new section explaining about this framework. - -## 3.1.1 - -- Updated docs link. - -## 3.1.0 - -- Now there's a new Dart command `message`. Developers can now generate Dart and Rust message code from `.proto` files with `dart run rust_in_flutter message`. `build.rs` file that used to do this is removed. - -## 3.0.9 - -- Fixed a problem with pub.dev score. - -## 3.0.8 - -- Fixed a problem with pub.dev score. - -## 3.0.7 - -- Fixed a problem with pub.dev score. - -## 3.0.6 - -- Fixed a problem with pub.dev score. - -## 3.0.5 - -- Moved documentation to a dedicated website. -- Now `build.rs` will automatically modify PATH for `protoc-gen-dart`. -- Fixed an error appearing in Rust-analyzer's webassembly mode. - -## 3.0.4 - -- Polished template code. - -## 3.0.3 - -- Polished template code. - -## 3.0.2 - -- Polished guides, comments and template code. - -## 3.0.1 - -- Fixed and organized tutorials and comments. - -## 3.0.0 - -- Adopted Protobuf for message serialization. Now communication between Dart and Rust is much more type-safe and faster than before. Because the template has now changed, you need to run `dart run rust_in_flutter template` again when migrating from version 2. Thanks @wheregmis` and @bookshiyi! - -## 2.9.0 - -- Removed `corrosion`. Now this package solely relies on `cargokit` and is much more slimmer. Thanks @bookshiyi! -- Removed unneeded files from pub.dev publication. - -## 2.8.5 - -- Fixed a problem with pub.dev score. - -## 2.8.4 - -- Fixed a problem with pub.dev score. - -## 2.8.3 - -- Wrote new catchphrase. - -## 2.8.2 - -- Updated links. - -## 2.8.1 - -- Updated links. - -## 2.8.0 - -- Removed unneeded dependencies. - -## 2.7.4 - -- Fixed CI badge showing rate limit error. - -## 2.7.3 - -- Fixed wrong guides. - -## 2.7.2 - -- Organized guides. - -## 2.7.1 - -- Organized guides. Thanks @bookshiyi! - -## 2.7.0 - -- Stabilized web-related Rust toolchain's auto-installation. Thanks @bookshiyi! - -## 2.6.0 - -- Applied continuous integration for checking builds and improving project stability. Thanks @bookshiyi! - -## 2.5.6 - -- Updated Cargokit. Thanks @bookshiyi! - -## 2.5.5 - -- Improved guides about HTTP headers. - -## 2.5.4 - -- Updated example code. - -## 2.5.3 - -- Improved guides and CLI messages. - -## 2.5.2 - -- Optimized web binary size. - -## 2.5.1 - -- Optimized web performance. - -## 2.5.0 - -- Now Rust logic will be restarted upon Dart's hot restart on the web too. -- CLI commands are shortened. - -## 2.4.0 - -- Fixed the problem with dangling threads from the `tokio` runtime remaining after closing the Flutter app. Even after the app window was closed, `tokio` threads were still running, resulting in becoming a background process without a window. Now the `tokio` runtime will properly be shut down. - -## 2.3.2 - -- Re-publishing due to `pub.dev`'s `[UNKNOWN PLATFORMS]` error. - -## 2.3.1 - -- Restored the benefits section in the first guide. - -## 2.3.0 - -- Improved Dart's hot restart process on native platforms. - -## 2.2.0 - -- Improved the procedure of building for the web. -- Simplfied unneeded complexities. - -## 2.1.2 - -- Improved web alias module. -- Fixed small things. - -## 2.1.1 - -- Optimized the bridge thread on native platforms. -- Updated many minor errors in the guides. -- Fixed a problem with import statement not being written in `./lib/main.dart` when applying Rust template. - -## 2.1.0 - -- Merged `frb_engine` crate into `hub`. -- Removed unneeded intermediate worker pools. -- Added `time` web alias import. -- Added many guides and comments. - -## 2.0.1 - -- Improved guides. -- Added `print!` web alias macro. -- Organized exposed Dart APIs. - -## 2.0.0 - -- Added web support. - -## 1.6.6 - -- Improved guides. -- Now, the template application command will check if the current directory is a Flutter project first. - -## 1.6.5 - -- Improved guides. - -## 1.6.4 - -- Organized guide sections. - -## 1.6.3 - -- Organized guide sections. - -## 1.6.2 - -- Filled in missing translations. - -## 1.6.1 - -- Slightly improved guide sections. - -## 1.6.0 - -- Added step-by-step guides. - -## 1.5.3 - -- Fixed some example app code. - -## 1.5.2 - -- Improved the readability of example app code. - -## 1.5.1 - -- Added Japanese translation. -- Fixed some sentences in Korean guides. - -## 1.5.0 - -- Now the Android NDK version that the Flutter SDK expects will be used, not the version specified by this package. -- Fixed a bug saying `IntoDart` trait is not implemented. - -## 1.4.1 - -- Improved various guides. - -## 1.4.0 - -- Filled in various guides to help developers understand the structure more easily. - -## 1.3.2 - -- Added Chinese guides. Thanks @moluopro! -- Added Korean guides. -- Added guides about build tool version issues. -- Added guides about library bundling. - -## 1.3.1 - -- Fixed a problem with Rust crate path detection on Android. - -## 1.3.0 - -- Changed the name of an exposed enum. Now `Operation` has changed to `RustOperation` so that it won't make confusions with other operations. All developers should update their code to match this new name, probably using the batch replace function in various IDEs. -- Updated code snippets. - -## 1.2.8 - -- Fixed small things. - -## 1.2.7 - -- Stabilized `main.dart` modifcation upon `dart run rust_in_flutter:apply_template`. - -## 1.2.6 - -- Hid the information regarding the compilation of connector crates to avoid confusion with actual crates. - -## 1.2.5 - -- Updated the guide about Android NDK version. - -## 1.2.4 - -- Updated many outdated comments and guides. -- Decreased the time spent on `ensureInitialized`. Also, `ensureInitialized()` is automatically inserted in `main.dart` when doing `dart run rust_in_flutter:apply_template` from now on. -- Various code improvements were applied. - -## 1.2.3 - -- Clarified template structure in guides. - -## 1.2.2 - -- Hide more Dart APIs that are not meant to be used outside. - -## 1.2.1 - -- Updated many comments. -- Fine-tuned the visibility of Dart APIs. -- Organized guides. - -## 1.2.0 - -- Made the Rust request handler more future-proof, taking potential web support into account. - -## 1.1.1 - -- Improved various guides to help understanding the features of this package. - -## 1.1.0 - -- Now this package is a Flutter FFI plugin without dummy native code. -- Improved guides - -## 1.0.4 - -- Fixed a problem with library bundling on Linux. -- Added comments. -- Added guides. -- Improved template application. - -## 1.0.3 - -- Included code snippets in guides. - -## 1.0.2 - -- Fixed typos. -- Organized inner code. - -## 1.0.1 - -- Enforced bundling on macOS and iOS. -- Improved pub score. -- Make `apply_rust` modify `.gitignore`. - -## 1.0.0 - -- Previously `flutter_rust_app_template`, now this is a small convenient framework that can be applied to existing Flutter projects. +## 6.12.0 + +- Generated message channels are now more efficient. +- Minimum Android SDK version increased from 16 to 21. Thanks @debanjanbasu! +- The `finalizeRust()` function in Dart has been removed. The `tokio` async runtime, which holds Rust logic, still drops automatically when the app ends. +- Bumped `prost` version to 0.12.6. Thanks @yeoupooh! +- Internal code has been organized. + +## 6.11.1 + +- Fixed a bug with Dart's extension methods in the generated message code. + +## 6.11.0 + +- Now it's possible to set the dynamic library's path. +- Now `rinf message` generates more memory-efficient and cleaner code. + +## 6.10.0 + +- Early Dart signals are now stored in the tokio channel instead of being ignored. Their performance is also slightly better. +- Excessive sample code is not included in the template from the `rinf template` command anymore. +- Now `tokio` is enabled by default in the template, not `tokio_with_wasm`. +- A configuration option, `rinf.message.rust_serde`, was added to make generated Rust message files compatible with `serde`. Thanks @NeoVance! + +## 6.9.2 + +- Early Dart signals have become more stable. + +## 6.9.1 + +- Now the memory allocation and drop is done in each language. + +## 6.9.0 + +- This version supports Flutter 3.22 +- The new version of Flutter has a little different way of resolving paths. This release adapts to this change. + +## 6.8.0 + +- Now `sendSignalToRust` and `send_signal_to_dart` methods no longer require `null` or `None`, making the API much cleaner. To make them include binary data, write `[RINF:DART-SIGNAL-BINARY]` or `[RINF:RUST-SIGNAL-BINARY]` in Protobuf files. +- The problem of panicking from null pointers that arise from empty signal data has been fixed. + +## 6.7.0 + +- Allowed `enum` and `oneof` statements to work in Protobuf message files. Thanks @yeoupooh! + +## 6.6.3 + +- Fixed a linting issue. Thanks @romanseo1! + +## 6.6.2 + +- Updated `tokio_with_wasm` to a newer version that addresses performance issues with `spawn_blocking`. +- Added example code that shows how to use global state in `sample_functions.rs` file. + +## 6.6.1 + +- Added support for some Linux distributions where patching Flutter SDK is not possible. +- Fixed a problem with the web sector not working. To use this new version, it's recommended to discard all Git changes in Flutter SDK's directory, or simply run `flutter upgrade --force`. +- Fixed a problem with `cd` error on Windows. Thanks @H2Sxxa! +- Fixed `pub.dev` package score. + +## 6.6.0 + +- Now early Rust signals on startup works properly, even if the widgets are not built yet. `rustSignalStream` will remember Rust signals that were received before widgets were built, and give them to the first listener. + +## 6.5.0 + +- Now the native library file is loaded as dynamic library, not static library, on iOS and macOS, like other platforms. This reduces the possibility of potential conflicts of native symbols. +- Now `rinf template` checks `pubspec.yaml` instead of `lib/main.dart` to ensure that the current folder is a Flutter project. + +## 6.4.0 + +- The start and stop mechanism of Rust has become more stable. + +## 6.3.1 + +- Fixed a small glitch with codegen. + +## 6.3.0 + +- The interface code has been organized. Now the `bridge` Rust module is gone and the API makes more sense. Please refer to the example code to upgrade. + +## 6.2.0 + +- Now custom installation of `protoc` works. This is useful when you don't have full access to GitHub APIs, which is needed for automatic `protoc` installation. Thanks @TENX-S! +- Signal handling has become more efficient. + +## 6.1.0 + +- Now `rustSignalStream`s `listen` can be called multiple times. Thanks @rabbitson87! + +## 6.0.1 + +- Improved CLI output texts. +- `js` Dart package was removed. + +## 6.0.0 + +- You need to run `rinf template`, `cargo install rinf` again to use this new version. +- Now the communication between Dart and Rust is much simpler. You can mark messages in `.proto` files so that Rinf's code generator can generate channels in-between. This new system is not compatible with older Rinf versions, so please check the docs before you upgrade. +- Added the ability to customize Rinf's behaviors by writing fields inside `pubspec.yaml` file. Thanks @thlorenz! +- Allowed users to check when the documentation page was made and edited. Thanks @VictorieeMan! +- Now it's possible to quit `rinf message --watch` by pressing `q` on your keyboard. +- Internal code has been organized. + +## 6.0.0-beta + +- This is a beta version. + +## 6.0.0-alpha + +- This is an alpha version. + +## 5.4.0 + +- Now users do not have to manually install `protoc` binary executable anymore. Protobuf compiler is now automatically installed. Note that you need to run `cargo install rinf` again to use this new version. + +## 5.3.1 + +- Fixed a bug with `rinf message` that omits `mod.rs` inside a folder without any message. + +## 5.3.0 + +- Now it is possible to use `import` statements in `.proto` files. +- Now you can properly use Flutter's hot restart while developing. +- Tutorials and guides are improved. +- Fixed a bug with `rinf message`, that might fail if some of the folders are empty. + +## 5.2.0 + +- Unnecessary memory copy is now avoided. + +## 5.1.3 + +- Fixed introductions. + +## 5.1.2 + +- Fixed a bug with memory freeing. + +## 5.1.1 + +- The codebase was organized further. +- Fixed a problem with Dart analysis. + +## 5.1.0 + +- All the code from `flutter_rust_bridge` was removed. This was due to criticisms about Rinf from the community and FRB devs. Also, internal bridge and FFI code is now much smaller. User API remains unchanged. + +## 5.0.0 + +- Now `requestToRust` Dart function will return `null` when the handler function in Rust cannot respond or has panicked. This is a breaking change, so when you upgrade to this version, you need to run `rinf template --bridge` in the terminal and refactor some of the code where IDE warns you about mismatches. You also need to modify `lib.rs` and `with_request.rs` modules of the `hub` crate. Also, the `timeout` parameter was removed from the `requestToRust` function because Dart will always get some return value from Rust in all cases. Please refer to the example code and documentation tutorials if you need detailed information. + +## 4.20.0 + +- Added support for Android Gradle Plugin 8. + +## 4.19.1 + +- Switched to the new official website `rinf.cunarist.com`. + +## 4.19.0 + +- The mechanism for awaiting Rust's responses from Dart has become much more efficient. + +## 4.18.0 + +- Now `null` can be provided to the `timeout` parameter in the `requestToRust()` Dart function. This enables awaiting a Rust response forever, but it should be used cautiously because it may potentially lead to resource leaks. + +## 4.17.1 + +- Now `rinf message --watch` works on all platforms. Thanks @bookshiyi! + +## 4.17.0 + +- New command `rinf message --watch` for automatic message code generation. Thanks @bookshiyi! + +## 4.16.3 + +- Updated package descriptions. + +## 4.16.2 + +- Improved guides to avoid misconceptions about the communication system. Rinf only uses FFI without any web server. + +## 4.16.1 + +- Fixed the broken `rinf template --bridge` command + +## 4.16.0 + +- Vastly organized files, dependencies, and code readability. Now the `hub` crate is much cleaner than before. If you already have an app using older Rinf versions, it is recommended to run `rinf template --bridge` and add `rinf = "4.16.0"` to `Cargo.toml` of the `hub` crate. + +## 4.15.2 + +- Now the web API fetching example uses `http` instead of `https` in the example app. + +## 4.15.1 + +- Now the `reqwest` crate will be disabled when compiling the example app for Android. + +## 4.15.0 + +- Allowed setting custom timeout when using `requestToRust()`. Thanks @cipherchabon! + +## 4.14.0 + +- Added a web API fetching example to the template. +- Fixed various things such as template comments, code linting issues. + +## 4.13.2 + +- Fixed small things. + +## 4.13.1 + +- Fixed formatting issues in Dart code. + +## 4.13.0 + +- Improved the template code by disabling CPU-intensive tasks and removing unneeded dependency features. +- Improved CLI outputs from `rinf wasm`. +- Improved various guides and template comments. + +## 4.12.5 + +- Automated publication. + +## 4.12.4 + +- Fixed permission related problems with build script files. + +## 4.12.3 + +- Fixed permission related problems with build script files. + +## 4.12.2 + +- Fixed guide badges. + +## 4.12.1 + +- Fixed publishing issues. + +## 4.12.0 + +- Renamed the framework to Rinf. + +## 4.11.8 + +- Improved first guides. + +## 4.11.7 + +- Improved the example app's code and guides. + +## 4.11.6 + +- Improved the shorthand command crate. + +## 4.11.5 + +- Improved the shorthand command crate. + +## 4.11.4 + +- Improved the first preview image and some comments. + +## 4.11.3 + +- Improved the example app's code. + +## 4.11.2 + +- Fixed a problem with compilation on macOS. + +## 4.11.1 + +- Fixed a problem with compilation on macOS. + +## 4.11.0 + +- New Dart function `ensureFinalized()`. This function ensures that all Rust tasks are terminated. Take a look at the example code to understand how to run this function before closing the Flutter app. Note that you have to run `rifs template --bridge` again to use this function. + +## 4.10.0 + +- New default web alias `spawn_blocking()`. CPU-intensive blocking tasks are better to be executed on a separate thread pool. +- Improved the example app's performance and debug tests. + +## 4.9.0 + +- New default web alias `yield_now()`. Inside a long-running code, calling this will help you avoid blocking the whole async event loop, by giving the flow back to other async tasks. +- Vastly improved comments inside the `web_alias` Rust module. +- Now Rust panics on the web will be printed to the CLI too. +- Improved the example app's performance and debug tests. + +## 4.8.2 + +- Improved guide sentences. + +## 4.8.1 + +- Improved the readability of the example code. +- Organized and clarified first guides. + +## 4.8.0 + +- Now by running `rifs template --bridge`, you can apply and update only the `bridge` module inside the `hub` crate. This is useful when you've upgraded RIF but do not need to apply the whole template again. +- Improved `rifs --help` output. + +## 4.7.0 + +- Now Rust stacktrace will be printed to the CLI when a panic occurs. The changes are mostly included in the template, so make sure you've run `rifs template` on this new version. + +## 4.6.2 + +- Polished various aspects. + +## 4.6.1 + +- Stabilized `debug_print!` logic. + +## 4.6.0 + +- New `debug_print!` macro that works on all environments, including web and mobile emulators, with the power of Flutter debuggers. To use this, you need to run `rifs template` again. +- Now panic information in Rust will be properly printed to the CLI. Note that Rust panics don't crash the app and do not hinder stability. +- Improved docs. There are also more guides about well-known types in Protobuf. Thanks @LucaCoduriV! + +## 4.5.0 + +- Added support for external symbols on iOS and macOS. This is needed for some Rust crates that depend on Apple's system frameworks. + +## 4.4.2 + +- Updated docs and demo links. + +## 4.4.1 + +- Updated docs and demo links. + +## 4.4.0 + +- Improved various guides and comments. +- Fixed a bug that made the app crash when passing in an empty `Vec`. +- Fixed the formatting of Rust files. + +## 4.3.0 + +- Now `flutter run` will use `require-corp` value for `cross-origin-embedder-policy` HTTP header that works on all web browsers. + +## 4.2.1 + +- Fixed a bug with `RustResponse::default()`. + +## 4.2.0 + +- New command `rifs --help`. Thanks @bookshiyi! + +## 4.1.4 + +- Fixed a sentence in the guides. + +## 4.1.3 + +- Made `rifs message` command read `PUB_CACHE` enviornment variable if present. Thanks @rabbitson87! + +## 4.1.2 + +- Fixed `rifs template` command. + +## 4.1.1 + +- Added some guides to the shorthand crate. +- Removed an unneeded dependency from the shorthand crate. + +## 4.1.0 + +- Fixed `sleep()` on the web. +- Added demo link in the guides. + +## 4.0.3 + +- Fixed bugs with `rifs template` on Windows. +- Fixed outdated comments. +- Organized sample code. + +## 4.0.2 + +- Eliminated an unnecessary Dart dependency. + +## 4.0.1 + +- Eliminated an unnecessary Dart dependency. + +## 4.0.0 + +- Added support for sending large binaries between Dart and Rust. This is now possible by using the `blob` field in `RustRequest`, `RustResponse`, and `RustSignal`. Please make sure you've run `rifs template` before using this new version because the template has changed a little. +- Added support for nested message folders. +- Added support for Rust nightly. +- Eliminated unnecessary Dart dependencies. + +## 3.7.4 + +- Updated `cargokit`, the build connector between Flutter and Rust. + +## 3.7.3 + +- Fixed a bug with cargo. + +## 3.7.2 + +- Fixed a bug with cargo. + +## 3.7.1 + +- Organized descriptions and files. + +## 3.7.0 + +- Now this framework provides a shorthand command `rifs ...` which is equivalent to `dart run rust_in_flutter ...`. + +## 3.6.0 + +- Fixed a bug that prevents the app from running on Linux. +- Improved various texts exposed to developers for clarity. + +## 3.5.1 + +- Bumped `prost` version to avoid snake case related warnings. + +## 3.5.0 + +- Shortend some names that were unnecessarily long. + +## 3.4.5 + +- Import statements became shorter in Dart. + +## 3.4.4 + +- Cleaned up outdated dependencies in `Cargo.toml`. + +## 3.4.3 + +- Now `syntax` and `package` statements in `.proto` files should be handled automatically. + +## 3.4.2 + +- Now running `dart run rust_in_flutter message` verifies `package` statement in `.proto` files and mistakes are fixed automatically. + +## 3.4.1 + +- Now match statement is used for handling requests. This improves code readability. + +## 3.4.0 + +- Now each `.proto` file is treated as a Rust resource, which essentially becomes an API endpoint. + +## 3.3.0 + +- `RustResource` enum has been added to `interaction.proto`. Now the list of available Rust resources are managed by Protobuf, which makes the project less error-prone. This new system also has less runtime overhead because interactions are distinguished by simple integers, not strings. + +## 3.2.3 + +- Improved guides. + +## 3.2.2 + +- Organized guides. + +## 3.2.1 + +- Matched first guides with the docs. + +## 3.2.0 + +- Now when applying the Rust template with `dart run rust_in_flutter template`, `README.md` file will get a new section explaining about this framework. + +## 3.1.1 + +- Updated docs link. + +## 3.1.0 + +- Now there's a new Dart command `message`. Developers can now generate Dart and Rust message code from `.proto` files with `dart run rust_in_flutter message`. `build.rs` file that used to do this is removed. + +## 3.0.9 + +- Fixed a problem with pub.dev score. + +## 3.0.8 + +- Fixed a problem with pub.dev score. + +## 3.0.7 + +- Fixed a problem with pub.dev score. + +## 3.0.6 + +- Fixed a problem with pub.dev score. + +## 3.0.5 + +- Moved documentation to a dedicated website. +- Now `build.rs` will automatically modify PATH for `protoc-gen-dart`. +- Fixed an error appearing in Rust-analyzer's webassembly mode. + +## 3.0.4 + +- Polished template code. + +## 3.0.3 + +- Polished template code. + +## 3.0.2 + +- Polished guides, comments and template code. + +## 3.0.1 + +- Fixed and organized tutorials and comments. + +## 3.0.0 + +- Adopted Protobuf for message serialization. Now communication between Dart and Rust is much more type-safe and faster than before. Because the template has now changed, you need to run `dart run rust_in_flutter template` again when migrating from version 2. Thanks @wheregmis` and @bookshiyi! + +## 2.9.0 + +- Removed `corrosion`. Now this package solely relies on `cargokit` and is much more slimmer. Thanks @bookshiyi! +- Removed unneeded files from pub.dev publication. + +## 2.8.5 + +- Fixed a problem with pub.dev score. + +## 2.8.4 + +- Fixed a problem with pub.dev score. + +## 2.8.3 + +- Wrote new catchphrase. + +## 2.8.2 + +- Updated links. + +## 2.8.1 + +- Updated links. + +## 2.8.0 + +- Removed unneeded dependencies. + +## 2.7.4 + +- Fixed CI badge showing rate limit error. + +## 2.7.3 + +- Fixed wrong guides. + +## 2.7.2 + +- Organized guides. + +## 2.7.1 + +- Organized guides. Thanks @bookshiyi! + +## 2.7.0 + +- Stabilized web-related Rust toolchain's auto-installation. Thanks @bookshiyi! + +## 2.6.0 + +- Applied continuous integration for checking builds and improving project stability. Thanks @bookshiyi! + +## 2.5.6 + +- Updated Cargokit. Thanks @bookshiyi! + +## 2.5.5 + +- Improved guides about HTTP headers. + +## 2.5.4 + +- Updated example code. + +## 2.5.3 + +- Improved guides and CLI messages. + +## 2.5.2 + +- Optimized web binary size. + +## 2.5.1 + +- Optimized web performance. + +## 2.5.0 + +- Now Rust logic will be restarted upon Dart's hot restart on the web too. +- CLI commands are shortened. + +## 2.4.0 + +- Fixed the problem with dangling threads from the `tokio` runtime remaining after closing the Flutter app. Even after the app window was closed, `tokio` threads were still running, resulting in becoming a background process without a window. Now the `tokio` runtime will properly be shut down. + +## 2.3.2 + +- Re-publishing due to `pub.dev`'s `[UNKNOWN PLATFORMS]` error. + +## 2.3.1 + +- Restored the benefits section in the first guide. + +## 2.3.0 + +- Improved Dart's hot restart process on native platforms. + +## 2.2.0 + +- Improved the procedure of building for the web. +- Simplfied unneeded complexities. + +## 2.1.2 + +- Improved web alias module. +- Fixed small things. + +## 2.1.1 + +- Optimized the bridge thread on native platforms. +- Updated many minor errors in the guides. +- Fixed a problem with import statement not being written in `./lib/main.dart` when applying Rust template. + +## 2.1.0 + +- Merged `frb_engine` crate into `hub`. +- Removed unneeded intermediate worker pools. +- Added `time` web alias import. +- Added many guides and comments. + +## 2.0.1 + +- Improved guides. +- Added `print!` web alias macro. +- Organized exposed Dart APIs. + +## 2.0.0 + +- Added web support. + +## 1.6.6 + +- Improved guides. +- Now, the template application command will check if the current directory is a Flutter project first. + +## 1.6.5 + +- Improved guides. + +## 1.6.4 + +- Organized guide sections. + +## 1.6.3 + +- Organized guide sections. + +## 1.6.2 + +- Filled in missing translations. + +## 1.6.1 + +- Slightly improved guide sections. + +## 1.6.0 + +- Added step-by-step guides. + +## 1.5.3 + +- Fixed some example app code. + +## 1.5.2 + +- Improved the readability of example app code. + +## 1.5.1 + +- Added Japanese translation. +- Fixed some sentences in Korean guides. + +## 1.5.0 + +- Now the Android NDK version that the Flutter SDK expects will be used, not the version specified by this package. +- Fixed a bug saying `IntoDart` trait is not implemented. + +## 1.4.1 + +- Improved various guides. + +## 1.4.0 + +- Filled in various guides to help developers understand the structure more easily. + +## 1.3.2 + +- Added Chinese guides. Thanks @moluopro! +- Added Korean guides. +- Added guides about build tool version issues. +- Added guides about library bundling. + +## 1.3.1 + +- Fixed a problem with Rust crate path detection on Android. + +## 1.3.0 + +- Changed the name of an exposed enum. Now `Operation` has changed to `RustOperation` so that it won't make confusions with other operations. All developers should update their code to match this new name, probably using the batch replace function in various IDEs. +- Updated code snippets. + +## 1.2.8 + +- Fixed small things. + +## 1.2.7 + +- Stabilized `main.dart` modifcation upon `dart run rust_in_flutter:apply_template`. + +## 1.2.6 + +- Hid the information regarding the compilation of connector crates to avoid confusion with actual crates. + +## 1.2.5 + +- Updated the guide about Android NDK version. + +## 1.2.4 + +- Updated many outdated comments and guides. +- Decreased the time spent on `ensureInitialized`. Also, `ensureInitialized()` is automatically inserted in `main.dart` when doing `dart run rust_in_flutter:apply_template` from now on. +- Various code improvements were applied. + +## 1.2.3 + +- Clarified template structure in guides. + +## 1.2.2 + +- Hide more Dart APIs that are not meant to be used outside. + +## 1.2.1 + +- Updated many comments. +- Fine-tuned the visibility of Dart APIs. +- Organized guides. + +## 1.2.0 + +- Made the Rust request handler more future-proof, taking potential web support into account. + +## 1.1.1 + +- Improved various guides to help understanding the features of this package. + +## 1.1.0 + +- Now this package is a Flutter FFI plugin without dummy native code. +- Improved guides + +## 1.0.4 + +- Fixed a problem with library bundling on Linux. +- Added comments. +- Added guides. +- Improved template application. + +## 1.0.3 + +- Included code snippets in guides. + +## 1.0.2 + +- Fixed typos. +- Organized inner code. + +## 1.0.1 + +- Enforced bundling on macOS and iOS. +- Improved pub score. +- Make `apply_rust` modify `.gitignore`. + +## 1.0.0 + +- Previously `flutter_rust_app_template`, now this is a small convenient framework that can be applied to existing Flutter projects. diff --git a/flutter_ffi_plugin/CHANGELOG.md b/flutter_ffi_plugin/CHANGELOG.md index 8400b3c06..621658232 100644 --- a/flutter_ffi_plugin/CHANGELOG.md +++ b/flutter_ffi_plugin/CHANGELOG.md @@ -1,805 +1,805 @@ -## 6.12.0 - -- Generated message channels are now more efficient. -- Minimum Android SDK version increased from 16 to 21. Thanks @debanjanbasu! -- The `finalizeRust()` function in Dart has been removed. The `tokio` async runtime, which holds Rust logic, still drops automatically when the app ends. -- Bumped `prost` version to 0.12.6. Thanks @yeoupooh! -- Internal code has been organized. - -## 6.11.1 - -- Fixed a bug with Dart's extension methods in the generated message code. - -## 6.11.0 - -- Now it's possible to set the dynamic library's path. -- Now `rinf message` generates more memory-efficient and cleaner code. - -## 6.10.0 - -- Early Dart signals are now stored in the tokio channel instead of being ignored. Their performance is also slightly better. -- Excessive sample code is not included in the template from the `rinf template` command anymore. -- Now `tokio` is enabled by default in the template, not `tokio_with_wasm`. -- A configuration option, `rinf.message.rust_serde`, was added to make generated Rust message files compatible with `serde`. Thanks @NeoVance! - -## 6.9.2 - -- Early Dart signals have become more stable. - -## 6.9.1 - -- Now the memory allocation and drop is done in each language. - -## 6.9.0 - -- This version supports Flutter 3.22. -- The new version of Flutter has a little different way of resolving paths. This release adapts to this change. - -## 6.8.0 - -- Now `sendSignalToRust` and `send_signal_to_dart` methods no longer require `null` or `None`, making the API much cleaner. To make them include binary data, write `[RINF:DART-SIGNAL-BINARY]` or `[RINF:RUST-SIGNAL-BINARY]` in Protobuf files. -- The problem of panicking from null pointers that arise from empty signal data has been fixed. - -## 6.7.0 - -- Allowed `enum` and `oneof` statements to work in Protobuf message files. Thanks @yeoupooh! - -## 6.6.3 - -- Fixed a linting issue. Thanks @romanseo1! - -## 6.6.2 - -- Updated `tokio_with_wasm` to a newer version that addresses performance issues with `spawn_blocking`. -- Added example code that shows how to use global state in `sample_functions.rs` file. - -## 6.6.1 - -- Added support for some Linux distributions where patching Flutter SDK is not possible. -- Fixed a problem with the web sector not working. To use this new version, it's recommended to discard all Git changes in Flutter SDK's directory, or simply run `flutter upgrade --force`. -- Fixed a problem with `cd` error on Windows. Thanks @H2Sxxa! -- Fixed `pub.dev` package score. - -## 6.6.0 - -- Now early Rust signals on startup works properly, even if the widgets are not built yet. `rustSignalStream` will remember Rust signals that were received before widgets were built, and give them to the first listener. - -## 6.5.0 - -- Now the native library file is loaded as dynamic library, not static library, on iOS and macOS, like other platforms. This reduces the possibility of potential conflicts of native symbols. -- Now `rinf template` checks `pubspec.yaml` instead of `lib/main.dart` to ensure that the current folder is a Flutter project. - -## 6.4.0 - -- The start and stop mechanism of Rust has become more stable. - -## 6.3.1 - -- Fixed a small glitch with codegen. - -## 6.3.0 - -- The interface code has been organized. Now the `bridge` Rust module is gone and the API makes more sense. Please refer to the example code to upgrade. - -## 6.2.0 - -- Now custom installation of `protoc` works. This is useful when you don't have full access to GitHub APIs, which is needed for automatic `protoc` installation. Thanks @TENX-S! -- Signal handling has become more efficient. - -## 6.1.0 - -- Now `rustSignalStream`s `listen` can be called multiple times. Thanks @rabbitson87! - -## 6.0.1 - -- Improved CLI output texts. -- `js` Dart package was removed. - -## 6.0.0 - -- You need to run `rinf template`, `cargo install rinf` again to use this new version. -- Now the communication between Dart and Rust is much simpler. You can mark messages in `.proto` files so that Rinf's code generator can generate channels in-between. This new system is not compatible with older Rinf versions, so please check the docs before you upgrade. -- Added the ability to customize Rinf's behaviors by writing fields inside `pubspec.yaml` file. Thanks @thlorenz! -- Allowed users to check when the documentation page was made and edited. Thanks @VictorieeMan! -- Now it's possible to quit `rinf message --watch` by pressing `q` on your keyboard. -- Internal code has been organized. - -## 6.0.0-beta - -- This is a beta version. - -## 6.0.0-alpha - -- This is an alpha version. - -## 5.4.0 - -- Now users do not have to manually install `protoc` binary executable anymore. Protobuf compiler is now automatically installed. Note that you need to run `cargo install rinf` again to use this new version. - -## 5.3.1 - -- Fixed a bug with `rinf message` that omits `mod.rs` inside a folder without any message. - -## 5.3.0 - -- Now it is possible to use `import` statements in `.proto` files. -- Now you can properly use Flutter's hot restart while developing. -- Tutorials and guides are improved. -- Fixed a bug with `rinf message`, that might fail if some of the folders are empty. - -## 5.2.0 - -- Unnecessary memory copy is now avoided. - -## 5.1.3 - -- Fixed introductions. - -## 5.1.2 - -- Fixed a bug with memory freeing. - -## 5.1.1 - -- The codebase was organized further. -- Fixed a problem with Dart analysis. - -## 5.1.0 - -- All the code from `flutter_rust_bridge` was removed. This was due to criticisms about Rinf from the community and FRB devs. Also, internal bridge and FFI code is now much smaller. User API remains unchanged. - -## 5.0.0 - -- Now `requestToRust` Dart function will return `null` when the handler function in Rust cannot respond or has panicked. This is a breaking change, so when you upgrade to this version, you need to run `rinf template --bridge` in the terminal and refactor some of the code where IDE warns you about mismatches. You also need to modify `lib.rs` and `with_request.rs` modules of the `hub` crate. Also, the `timeout` parameter was removed from the `requestToRust` function because Dart will always get some return value from Rust in all cases. Please refer to the example code and documentation tutorials if you need detailed information. - -## 4.20.0 - -- Added support for Android Gradle Plugin 8. - -## 4.19.1 - -- Switched to the new official website `rinf.cunarist.com`. - -## 4.19.0 - -- The mechanism for awaiting Rust's responses from Dart has become much more efficient. - -## 4.18.0 - -- Now `null` can be provided to the `timeout` parameter in the `requestToRust()` Dart function. This enables awaiting a Rust response forever, but it should be used cautiously because it may potentially lead to resource leaks. - -## 4.17.1 - -- Now `rinf message --watch` works on all platforms. Thanks @bookshiyi! - -## 4.17.0 - -- New command `rinf message --watch` for automatic message code generation. Thanks @bookshiyi! - -## 4.16.3 - -- Updated package descriptions. - -## 4.16.2 - -- Improved guides to avoid misconceptions about the communication system. Rinf only uses FFI without any web server. - -## 4.16.1 - -- Fixed the broken `rinf template --bridge` command - -## 4.16.0 - -- Vastly organized files, dependencies, and code readability. Now the `hub` crate is much cleaner than before. If you already have an app using older Rinf versions, it is recommended to run `rinf template --bridge` and add `rinf = "4.16.0"` to `Cargo.toml` of the `hub` crate. - -## 4.15.2 - -- Now the web API fetching example uses `http` instead of `https` in the example app. - -## 4.15.1 - -- Now the `reqwest` crate will be disabled when compiling the example app for Android. - -## 4.15.0 - -- Allowed setting custom timeout when using `requestToRust()`. Thanks @cipherchabon! - -## 4.14.0 - -- Added a web API fetching example to the template. -- Fixed various things such as template comments, code linting issues. - -## 4.13.2 - -- Fixed small things. - -## 4.13.1 - -- Fixed formatting issues in Dart code. - -## 4.13.0 - -- Improved the template code by disabling CPU-intensive tasks and removing unneeded dependency features. -- Improved CLI outputs from `rinf wasm`. -- Improved various guides and template comments. - -## 4.12.5 - -- Automated publication. - -## 4.12.4 - -- Fixed permission related problems with build script files. - -## 4.12.3 - -- Fixed permission related problems with build script files. - -## 4.12.2 - -- Fixed guide badges. - -## 4.12.1 - -- Fixed publishing issues. - -## 4.12.0 - -- Renamed the framework to Rinf. - -## 4.11.8 - -- Improved first guides. - -## 4.11.7 - -- Improved the example app's code and guides. - -## 4.11.6 - -- Improved the shorthand command crate. - -## 4.11.5 - -- Improved the shorthand command crate. - -## 4.11.4 - -- Improved the first preview image and some comments. - -## 4.11.3 - -- Improved the example app's code. - -## 4.11.2 - -- Fixed a problem with compilation on macOS. - -## 4.11.1 - -- Fixed a problem with compilation on macOS. - -## 4.11.0 - -- New Dart function `ensureFinalized()`. This function ensures that all Rust tasks are terminated. Take a look at the example code to understand how to run this function before closing the Flutter app. Note that you have to run `rifs template --bridge` again to use this function. - -## 4.10.0 - -- New default web alias `spawn_blocking()`. CPU-intensive blocking tasks are better to be executed on a separate thread pool. -- Improved the example app's performance and debug tests. - -## 4.9.0 - -- New default web alias `yield_now()`. Inside a long-running code, calling this will help you avoid blocking the whole async event loop, by giving the flow back to other async tasks. -- Vastly improved comments inside the `web_alias` Rust module. -- Now Rust panics on the web will be printed to the CLI too. -- Improved the example app's performance and debug tests. - -## 4.8.2 - -- Improved guide sentences. - -## 4.8.1 - -- Improved the readability of the example code. -- Organized and clarified first guides. - -## 4.8.0 - -- Now by running `rifs template --bridge`, you can apply and update only the `bridge` module inside the `hub` crate. This is useful when you've upgraded RIF but do not need to apply the whole template again. -- Improved `rifs --help` output. - -## 4.7.0 - -- Now Rust stacktrace will be printed to the CLI when a panic occurs. The changes are mostly included in the template, so make sure you've run `rifs template` on this new version. - -## 4.6.2 - -- Polished various aspects. - -## 4.6.1 - -- Stabilized `debug_print!` logic. - -## 4.6.0 - -- New `debug_print!` macro that works on all environments, including web and mobile emulators, with the power of Flutter debuggers. To use this, you need to run `rifs template` again. -- Now panic information in Rust will be properly printed to the CLI. Note that Rust panics don't crash the app and do not hinder stability. -- Improved docs. There are also more guides about well-known types in Protobuf. Thanks @LucaCoduriV! - -## 4.5.0 - -- Added support for external symbols on iOS and macOS. This is needed for some Rust crates that depend on Apple's system frameworks. - -## 4.4.2 - -- Updated docs and demo links. - -## 4.4.1 - -- Updated docs and demo links. - -## 4.4.0 - -- Improved various guides and comments. -- Fixed a bug that made the app crash when passing in an empty `Vec`. -- Fixed the formatting of Rust files. - -## 4.3.0 - -- Now `flutter run` will use `require-corp` value for `cross-origin-embedder-policy` HTTP header that works on all web browsers. - -## 4.2.1 - -- Fixed a bug with `RustResponse::default()`. - -## 4.2.0 - -- New command `rifs --help`. Thanks @bookshiyi! - -## 4.1.4 - -- Fixed a sentence in the guides. - -## 4.1.3 - -- Made `rifs message` command read `PUB_CACHE` enviornment variable if present. Thanks @rabbitson87! - -## 4.1.2 - -- Fixed `rifs template` command. - -## 4.1.1 - -- Added some guides to the shorthand crate. -- Removed an unneeded dependency from the shorthand crate. - -## 4.1.0 - -- Fixed `sleep()` on the web. -- Added demo link in the guides. - -## 4.0.3 - -- Fixed bugs with `rifs template` on Windows. -- Fixed outdated comments. -- Organized sample code. - -## 4.0.2 - -- Eliminated an unnecessary Dart dependency. - -## 4.0.1 - -- Eliminated an unnecessary Dart dependency. - -## 4.0.0 - -- Added support for sending large binaries between Dart and Rust. This is now possible by using the `blob` field in `RustRequest`, `RustResponse`, and `RustSignal`. Please make sure you've run `rifs template` before using this new version because the template has changed a little. -- Added support for nested message folders. -- Added support for Rust nightly. -- Eliminated unnecessary Dart dependencies. - -## 3.7.4 - -- Updated `cargokit`, the build connector between Flutter and Rust. - -## 3.7.3 - -- Fixed a bug with cargo. - -## 3.7.2 - -- Fixed a bug with cargo. - -## 3.7.1 - -- Organized descriptions and files. - -## 3.7.0 - -- Now this framework provides a shorthand command `rifs ...` which is equivalent to `dart run rust_in_flutter ...`. - -## 3.6.0 - -- Fixed a bug that prevents the app from running on Linux. -- Improved various texts exposed to developers for clarity. - -## 3.5.1 - -- Bumped `prost` version to avoid snake case related warnings. - -## 3.5.0 - -- Shortend some names that were unnecessarily long. - -## 3.4.5 - -- Import statements became shorter in Dart. - -## 3.4.4 - -- Cleaned up outdated dependencies in `Cargo.toml`. - -## 3.4.3 - -- Now `syntax` and `package` statements in `.proto` files should be handled automatically. - -## 3.4.2 - -- Now running `dart run rust_in_flutter message` verifies `package` statement in `.proto` files and mistakes are fixed automatically. - -## 3.4.1 - -- Now match statement is used for handling requests. This improves code readability. - -## 3.4.0 - -- Now each `.proto` file is treated as a Rust resource, which essentially becomes an API endpoint. - -## 3.3.0 - -- `RustResource` enum has been added to `interaction.proto`. Now the list of available Rust resources are managed by Protobuf, which makes the project less error-prone. This new system also has less runtime overhead because interactions are distinguished by simple integers, not strings. - -## 3.2.3 - -- Improved guides. - -## 3.2.2 - -- Organized guides. - -## 3.2.1 - -- Matched first guides with the docs. - -## 3.2.0 - -- Now when applying the Rust template with `dart run rust_in_flutter template`, `README.md` file will get a new section explaining about this framework. - -## 3.1.1 - -- Updated docs link. - -## 3.1.0 - -- Now there's a new Dart command `message`. Developers can now generate Dart and Rust message code from `.proto` files with `dart run rust_in_flutter message`. `build.rs` file that used to do this is removed. - -## 3.0.9 - -- Fixed a problem with pub.dev score. - -## 3.0.8 - -- Fixed a problem with pub.dev score. - -## 3.0.7 - -- Fixed a problem with pub.dev score. - -## 3.0.6 - -- Fixed a problem with pub.dev score. - -## 3.0.5 - -- Moved documentation to a dedicated website. -- Now `build.rs` will automatically modify PATH for `protoc-gen-dart`. -- Fixed an error appearing in Rust-analyzer's webassembly mode. - -## 3.0.4 - -- Polished template code. - -## 3.0.3 - -- Polished template code. - -## 3.0.2 - -- Polished guides, comments and template code. - -## 3.0.1 - -- Fixed and organized tutorials and comments. - -## 3.0.0 - -- Adopted Protobuf for message serialization. Now communication between Dart and Rust is much more type-safe and faster than before. Because the template has now changed, you need to run `dart run rust_in_flutter template` again when migrating from version 2. Thanks @wheregmis` and @bookshiyi! - -## 2.9.0 - -- Removed `corrosion`. Now this package solely relies on `cargokit` and is much more slimmer. Thanks @bookshiyi! -- Removed unneeded files from pub.dev publication. - -## 2.8.5 - -- Fixed a problem with pub.dev score. - -## 2.8.4 - -- Fixed a problem with pub.dev score. - -## 2.8.3 - -- Wrote new catchphrase. - -## 2.8.2 - -- Updated links. - -## 2.8.1 - -- Updated links. - -## 2.8.0 - -- Removed unneeded dependencies. - -## 2.7.4 - -- Fixed CI badge showing rate limit error. - -## 2.7.3 - -- Fixed wrong guides. - -## 2.7.2 - -- Organized guides. - -## 2.7.1 - -- Organized guides. Thanks @bookshiyi! - -## 2.7.0 - -- Stabilized web-related Rust toolchain's auto-installation. Thanks @bookshiyi! - -## 2.6.0 - -- Applied continuous integration for checking builds and improving project stability. Thanks @bookshiyi! - -## 2.5.6 - -- Updated Cargokit. Thanks @bookshiyi! - -## 2.5.5 - -- Improved guides about HTTP headers. - -## 2.5.4 - -- Updated example code. - -## 2.5.3 - -- Improved guides and CLI messages. - -## 2.5.2 - -- Optimized web binary size. - -## 2.5.1 - -- Optimized web performance. - -## 2.5.0 - -- Now Rust logic will be restarted upon Dart's hot restart on the web too. -- CLI commands are shortened. - -## 2.4.0 - -- Fixed the problem with dangling threads from the `tokio` runtime remaining after closing the Flutter app. Even after the app window was closed, `tokio` threads were still running, resulting in becoming a background process without a window. Now the `tokio` runtime will properly be shut down. - -## 2.3.2 - -- Re-publishing due to `pub.dev`'s `[UNKNOWN PLATFORMS]` error. - -## 2.3.1 - -- Restored the benefits section in the first guide. - -## 2.3.0 - -- Improved Dart's hot restart process on native platforms. - -## 2.2.0 - -- Improved the procedure of building for the web. -- Simplfied unneeded complexities. - -## 2.1.2 - -- Improved web alias module. -- Fixed small things. - -## 2.1.1 - -- Optimized the bridge thread on native platforms. -- Updated many minor errors in the guides. -- Fixed a problem with import statement not being written in `./lib/main.dart` when applying Rust template. - -## 2.1.0 - -- Merged `frb_engine` crate into `hub`. -- Removed unneeded intermediate worker pools. -- Added `time` web alias import. -- Added many guides and comments. - -## 2.0.1 - -- Improved guides. -- Added `print!` web alias macro. -- Organized exposed Dart APIs. - -## 2.0.0 - -- Added web support. - -## 1.6.6 - -- Improved guides. -- Now, the template application command will check if the current directory is a Flutter project first. - -## 1.6.5 - -- Improved guides. - -## 1.6.4 - -- Organized guide sections. - -## 1.6.3 - -- Organized guide sections. - -## 1.6.2 - -- Filled in missing translations. - -## 1.6.1 - -- Slightly improved guide sections. - -## 1.6.0 - -- Added step-by-step guides. - -## 1.5.3 - -- Fixed some example app code. - -## 1.5.2 - -- Improved the readability of example app code. - -## 1.5.1 - -- Added Japanese translation. -- Fixed some sentences in Korean guides. - -## 1.5.0 - -- Now the Android NDK version that the Flutter SDK expects will be used, not the version specified by this package. -- Fixed a bug saying `IntoDart` trait is not implemented. - -## 1.4.1 - -- Improved various guides. - -## 1.4.0 - -- Filled in various guides to help developers understand the structure more easily. - -## 1.3.2 - -- Added Chinese guides. Thanks @moluopro! -- Added Korean guides. -- Added guides about build tool version issues. -- Added guides about library bundling. - -## 1.3.1 - -- Fixed a problem with Rust crate path detection on Android. - -## 1.3.0 - -- Changed the name of an exposed enum. Now `Operation` has changed to `RustOperation` so that it won't make confusions with other operations. All developers should update their code to match this new name, probably using the batch replace function in various IDEs. -- Updated code snippets. - -## 1.2.8 - -- Fixed small things. - -## 1.2.7 - -- Stabilized `main.dart` modifcation upon `dart run rust_in_flutter:apply_template`. - -## 1.2.6 - -- Hid the information regarding the compilation of connector crates to avoid confusion with actual crates. - -## 1.2.5 - -- Updated the guide about Android NDK version. - -## 1.2.4 - -- Updated many outdated comments and guides. -- Decreased the time spent on `ensureInitialized`. Also, `ensureInitialized()` is automatically inserted in `main.dart` when doing `dart run rust_in_flutter:apply_template` from now on. -- Various code improvements were applied. - -## 1.2.3 - -- Clarified template structure in guides. - -## 1.2.2 - -- Hide more Dart APIs that are not meant to be used outside. - -## 1.2.1 - -- Updated many comments. -- Fine-tuned the visibility of Dart APIs. -- Organized guides. - -## 1.2.0 - -- Made the Rust request handler more future-proof, taking potential web support into account. - -## 1.1.1 - -- Improved various guides to help understanding the features of this package. - -## 1.1.0 - -- Now this package is a Flutter FFI plugin without dummy native code. -- Improved guides - -## 1.0.4 - -- Fixed a problem with library bundling on Linux. -- Added comments. -- Added guides. -- Improved template application. - -## 1.0.3 - -- Included code snippets in guides. - -## 1.0.2 - -- Fixed typos. -- Organized inner code. - -## 1.0.1 - -- Enforced bundling on macOS and iOS. -- Improved pub score. -- Make `apply_rust` modify `.gitignore`. - -## 1.0.0 - -- Previously `flutter_rust_app_template`, now this is a small convenient framework that can be applied to existing Flutter projects. +## 6.12.0 + +- Generated message channels are now more efficient. +- Minimum Android SDK version increased from 16 to 21. Thanks @debanjanbasu! +- The `finalizeRust()` function in Dart has been removed. The `tokio` async runtime, which holds Rust logic, still drops automatically when the app ends. +- Bumped `prost` version to 0.12.6. Thanks @yeoupooh! +- Internal code has been organized. + +## 6.11.1 + +- Fixed a bug with Dart's extension methods in the generated message code. + +## 6.11.0 + +- Now it's possible to set the dynamic library's path. +- Now `rinf message` generates more memory-efficient and cleaner code. + +## 6.10.0 + +- Early Dart signals are now stored in the tokio channel instead of being ignored. Their performance is also slightly better. +- Excessive sample code is not included in the template from the `rinf template` command anymore. +- Now `tokio` is enabled by default in the template, not `tokio_with_wasm`. +- A configuration option, `rinf.message.rust_serde`, was added to make generated Rust message files compatible with `serde`. Thanks @NeoVance! + +## 6.9.2 + +- Early Dart signals have become more stable. + +## 6.9.1 + +- Now the memory allocation and drop is done in each language. + +## 6.9.0 + +- This version supports Flutter 3.22. +- The new version of Flutter has a little different way of resolving paths. This release adapts to this change. + +## 6.8.0 + +- Now `sendSignalToRust` and `send_signal_to_dart` methods no longer require `null` or `None`, making the API much cleaner. To make them include binary data, write `[RINF:DART-SIGNAL-BINARY]` or `[RINF:RUST-SIGNAL-BINARY]` in Protobuf files. +- The problem of panicking from null pointers that arise from empty signal data has been fixed. + +## 6.7.0 + +- Allowed `enum` and `oneof` statements to work in Protobuf message files. Thanks @yeoupooh! + +## 6.6.3 + +- Fixed a linting issue. Thanks @romanseo1! + +## 6.6.2 + +- Updated `tokio_with_wasm` to a newer version that addresses performance issues with `spawn_blocking`. +- Added example code that shows how to use global state in `sample_functions.rs` file. + +## 6.6.1 + +- Added support for some Linux distributions where patching Flutter SDK is not possible. +- Fixed a problem with the web sector not working. To use this new version, it's recommended to discard all Git changes in Flutter SDK's directory, or simply run `flutter upgrade --force`. +- Fixed a problem with `cd` error on Windows. Thanks @H2Sxxa! +- Fixed `pub.dev` package score. + +## 6.6.0 + +- Now early Rust signals on startup works properly, even if the widgets are not built yet. `rustSignalStream` will remember Rust signals that were received before widgets were built, and give them to the first listener. + +## 6.5.0 + +- Now the native library file is loaded as dynamic library, not static library, on iOS and macOS, like other platforms. This reduces the possibility of potential conflicts of native symbols. +- Now `rinf template` checks `pubspec.yaml` instead of `lib/main.dart` to ensure that the current folder is a Flutter project. + +## 6.4.0 + +- The start and stop mechanism of Rust has become more stable. + +## 6.3.1 + +- Fixed a small glitch with codegen. + +## 6.3.0 + +- The interface code has been organized. Now the `bridge` Rust module is gone and the API makes more sense. Please refer to the example code to upgrade. + +## 6.2.0 + +- Now custom installation of `protoc` works. This is useful when you don't have full access to GitHub APIs, which is needed for automatic `protoc` installation. Thanks @TENX-S! +- Signal handling has become more efficient. + +## 6.1.0 + +- Now `rustSignalStream`s `listen` can be called multiple times. Thanks @rabbitson87! + +## 6.0.1 + +- Improved CLI output texts. +- `js` Dart package was removed. + +## 6.0.0 + +- You need to run `rinf template`, `cargo install rinf` again to use this new version. +- Now the communication between Dart and Rust is much simpler. You can mark messages in `.proto` files so that Rinf's code generator can generate channels in-between. This new system is not compatible with older Rinf versions, so please check the docs before you upgrade. +- Added the ability to customize Rinf's behaviors by writing fields inside `pubspec.yaml` file. Thanks @thlorenz! +- Allowed users to check when the documentation page was made and edited. Thanks @VictorieeMan! +- Now it's possible to quit `rinf message --watch` by pressing `q` on your keyboard. +- Internal code has been organized. + +## 6.0.0-beta + +- This is a beta version. + +## 6.0.0-alpha + +- This is an alpha version. + +## 5.4.0 + +- Now users do not have to manually install `protoc` binary executable anymore. Protobuf compiler is now automatically installed. Note that you need to run `cargo install rinf` again to use this new version. + +## 5.3.1 + +- Fixed a bug with `rinf message` that omits `mod.rs` inside a folder without any message. + +## 5.3.0 + +- Now it is possible to use `import` statements in `.proto` files. +- Now you can properly use Flutter's hot restart while developing. +- Tutorials and guides are improved. +- Fixed a bug with `rinf message`, that might fail if some of the folders are empty. + +## 5.2.0 + +- Unnecessary memory copy is now avoided. + +## 5.1.3 + +- Fixed introductions. + +## 5.1.2 + +- Fixed a bug with memory freeing. + +## 5.1.1 + +- The codebase was organized further. +- Fixed a problem with Dart analysis. + +## 5.1.0 + +- All the code from `flutter_rust_bridge` was removed. This was due to criticisms about Rinf from the community and FRB devs. Also, internal bridge and FFI code is now much smaller. User API remains unchanged. + +## 5.0.0 + +- Now `requestToRust` Dart function will return `null` when the handler function in Rust cannot respond or has panicked. This is a breaking change, so when you upgrade to this version, you need to run `rinf template --bridge` in the terminal and refactor some of the code where IDE warns you about mismatches. You also need to modify `lib.rs` and `with_request.rs` modules of the `hub` crate. Also, the `timeout` parameter was removed from the `requestToRust` function because Dart will always get some return value from Rust in all cases. Please refer to the example code and documentation tutorials if you need detailed information. + +## 4.20.0 + +- Added support for Android Gradle Plugin 8. + +## 4.19.1 + +- Switched to the new official website `rinf.cunarist.com`. + +## 4.19.0 + +- The mechanism for awaiting Rust's responses from Dart has become much more efficient. + +## 4.18.0 + +- Now `null` can be provided to the `timeout` parameter in the `requestToRust()` Dart function. This enables awaiting a Rust response forever, but it should be used cautiously because it may potentially lead to resource leaks. + +## 4.17.1 + +- Now `rinf message --watch` works on all platforms. Thanks @bookshiyi! + +## 4.17.0 + +- New command `rinf message --watch` for automatic message code generation. Thanks @bookshiyi! + +## 4.16.3 + +- Updated package descriptions. + +## 4.16.2 + +- Improved guides to avoid misconceptions about the communication system. Rinf only uses FFI without any web server. + +## 4.16.1 + +- Fixed the broken `rinf template --bridge` command + +## 4.16.0 + +- Vastly organized files, dependencies, and code readability. Now the `hub` crate is much cleaner than before. If you already have an app using older Rinf versions, it is recommended to run `rinf template --bridge` and add `rinf = "4.16.0"` to `Cargo.toml` of the `hub` crate. + +## 4.15.2 + +- Now the web API fetching example uses `http` instead of `https` in the example app. + +## 4.15.1 + +- Now the `reqwest` crate will be disabled when compiling the example app for Android. + +## 4.15.0 + +- Allowed setting custom timeout when using `requestToRust()`. Thanks @cipherchabon! + +## 4.14.0 + +- Added a web API fetching example to the template. +- Fixed various things such as template comments, code linting issues. + +## 4.13.2 + +- Fixed small things. + +## 4.13.1 + +- Fixed formatting issues in Dart code. + +## 4.13.0 + +- Improved the template code by disabling CPU-intensive tasks and removing unneeded dependency features. +- Improved CLI outputs from `rinf wasm`. +- Improved various guides and template comments. + +## 4.12.5 + +- Automated publication. + +## 4.12.4 + +- Fixed permission related problems with build script files. + +## 4.12.3 + +- Fixed permission related problems with build script files. + +## 4.12.2 + +- Fixed guide badges. + +## 4.12.1 + +- Fixed publishing issues. + +## 4.12.0 + +- Renamed the framework to Rinf. + +## 4.11.8 + +- Improved first guides. + +## 4.11.7 + +- Improved the example app's code and guides. + +## 4.11.6 + +- Improved the shorthand command crate. + +## 4.11.5 + +- Improved the shorthand command crate. + +## 4.11.4 + +- Improved the first preview image and some comments. + +## 4.11.3 + +- Improved the example app's code. + +## 4.11.2 + +- Fixed a problem with compilation on macOS. + +## 4.11.1 + +- Fixed a problem with compilation on macOS. + +## 4.11.0 + +- New Dart function `ensureFinalized()`. This function ensures that all Rust tasks are terminated. Take a look at the example code to understand how to run this function before closing the Flutter app. Note that you have to run `rifs template --bridge` again to use this function. + +## 4.10.0 + +- New default web alias `spawn_blocking()`. CPU-intensive blocking tasks are better to be executed on a separate thread pool. +- Improved the example app's performance and debug tests. + +## 4.9.0 + +- New default web alias `yield_now()`. Inside a long-running code, calling this will help you avoid blocking the whole async event loop, by giving the flow back to other async tasks. +- Vastly improved comments inside the `web_alias` Rust module. +- Now Rust panics on the web will be printed to the CLI too. +- Improved the example app's performance and debug tests. + +## 4.8.2 + +- Improved guide sentences. + +## 4.8.1 + +- Improved the readability of the example code. +- Organized and clarified first guides. + +## 4.8.0 + +- Now by running `rifs template --bridge`, you can apply and update only the `bridge` module inside the `hub` crate. This is useful when you've upgraded RIF but do not need to apply the whole template again. +- Improved `rifs --help` output. + +## 4.7.0 + +- Now Rust stacktrace will be printed to the CLI when a panic occurs. The changes are mostly included in the template, so make sure you've run `rifs template` on this new version. + +## 4.6.2 + +- Polished various aspects. + +## 4.6.1 + +- Stabilized `debug_print!` logic. + +## 4.6.0 + +- New `debug_print!` macro that works on all environments, including web and mobile emulators, with the power of Flutter debuggers. To use this, you need to run `rifs template` again. +- Now panic information in Rust will be properly printed to the CLI. Note that Rust panics don't crash the app and do not hinder stability. +- Improved docs. There are also more guides about well-known types in Protobuf. Thanks @LucaCoduriV! + +## 4.5.0 + +- Added support for external symbols on iOS and macOS. This is needed for some Rust crates that depend on Apple's system frameworks. + +## 4.4.2 + +- Updated docs and demo links. + +## 4.4.1 + +- Updated docs and demo links. + +## 4.4.0 + +- Improved various guides and comments. +- Fixed a bug that made the app crash when passing in an empty `Vec`. +- Fixed the formatting of Rust files. + +## 4.3.0 + +- Now `flutter run` will use `require-corp` value for `cross-origin-embedder-policy` HTTP header that works on all web browsers. + +## 4.2.1 + +- Fixed a bug with `RustResponse::default()`. + +## 4.2.0 + +- New command `rifs --help`. Thanks @bookshiyi! + +## 4.1.4 + +- Fixed a sentence in the guides. + +## 4.1.3 + +- Made `rifs message` command read `PUB_CACHE` enviornment variable if present. Thanks @rabbitson87! + +## 4.1.2 + +- Fixed `rifs template` command. + +## 4.1.1 + +- Added some guides to the shorthand crate. +- Removed an unneeded dependency from the shorthand crate. + +## 4.1.0 + +- Fixed `sleep()` on the web. +- Added demo link in the guides. + +## 4.0.3 + +- Fixed bugs with `rifs template` on Windows. +- Fixed outdated comments. +- Organized sample code. + +## 4.0.2 + +- Eliminated an unnecessary Dart dependency. + +## 4.0.1 + +- Eliminated an unnecessary Dart dependency. + +## 4.0.0 + +- Added support for sending large binaries between Dart and Rust. This is now possible by using the `blob` field in `RustRequest`, `RustResponse`, and `RustSignal`. Please make sure you've run `rifs template` before using this new version because the template has changed a little. +- Added support for nested message folders. +- Added support for Rust nightly. +- Eliminated unnecessary Dart dependencies. + +## 3.7.4 + +- Updated `cargokit`, the build connector between Flutter and Rust. + +## 3.7.3 + +- Fixed a bug with cargo. + +## 3.7.2 + +- Fixed a bug with cargo. + +## 3.7.1 + +- Organized descriptions and files. + +## 3.7.0 + +- Now this framework provides a shorthand command `rifs ...` which is equivalent to `dart run rust_in_flutter ...`. + +## 3.6.0 + +- Fixed a bug that prevents the app from running on Linux. +- Improved various texts exposed to developers for clarity. + +## 3.5.1 + +- Bumped `prost` version to avoid snake case related warnings. + +## 3.5.0 + +- Shortend some names that were unnecessarily long. + +## 3.4.5 + +- Import statements became shorter in Dart. + +## 3.4.4 + +- Cleaned up outdated dependencies in `Cargo.toml`. + +## 3.4.3 + +- Now `syntax` and `package` statements in `.proto` files should be handled automatically. + +## 3.4.2 + +- Now running `dart run rust_in_flutter message` verifies `package` statement in `.proto` files and mistakes are fixed automatically. + +## 3.4.1 + +- Now match statement is used for handling requests. This improves code readability. + +## 3.4.0 + +- Now each `.proto` file is treated as a Rust resource, which essentially becomes an API endpoint. + +## 3.3.0 + +- `RustResource` enum has been added to `interaction.proto`. Now the list of available Rust resources are managed by Protobuf, which makes the project less error-prone. This new system also has less runtime overhead because interactions are distinguished by simple integers, not strings. + +## 3.2.3 + +- Improved guides. + +## 3.2.2 + +- Organized guides. + +## 3.2.1 + +- Matched first guides with the docs. + +## 3.2.0 + +- Now when applying the Rust template with `dart run rust_in_flutter template`, `README.md` file will get a new section explaining about this framework. + +## 3.1.1 + +- Updated docs link. + +## 3.1.0 + +- Now there's a new Dart command `message`. Developers can now generate Dart and Rust message code from `.proto` files with `dart run rust_in_flutter message`. `build.rs` file that used to do this is removed. + +## 3.0.9 + +- Fixed a problem with pub.dev score. + +## 3.0.8 + +- Fixed a problem with pub.dev score. + +## 3.0.7 + +- Fixed a problem with pub.dev score. + +## 3.0.6 + +- Fixed a problem with pub.dev score. + +## 3.0.5 + +- Moved documentation to a dedicated website. +- Now `build.rs` will automatically modify PATH for `protoc-gen-dart`. +- Fixed an error appearing in Rust-analyzer's webassembly mode. + +## 3.0.4 + +- Polished template code. + +## 3.0.3 + +- Polished template code. + +## 3.0.2 + +- Polished guides, comments and template code. + +## 3.0.1 + +- Fixed and organized tutorials and comments. + +## 3.0.0 + +- Adopted Protobuf for message serialization. Now communication between Dart and Rust is much more type-safe and faster than before. Because the template has now changed, you need to run `dart run rust_in_flutter template` again when migrating from version 2. Thanks @wheregmis` and @bookshiyi! + +## 2.9.0 + +- Removed `corrosion`. Now this package solely relies on `cargokit` and is much more slimmer. Thanks @bookshiyi! +- Removed unneeded files from pub.dev publication. + +## 2.8.5 + +- Fixed a problem with pub.dev score. + +## 2.8.4 + +- Fixed a problem with pub.dev score. + +## 2.8.3 + +- Wrote new catchphrase. + +## 2.8.2 + +- Updated links. + +## 2.8.1 + +- Updated links. + +## 2.8.0 + +- Removed unneeded dependencies. + +## 2.7.4 + +- Fixed CI badge showing rate limit error. + +## 2.7.3 + +- Fixed wrong guides. + +## 2.7.2 + +- Organized guides. + +## 2.7.1 + +- Organized guides. Thanks @bookshiyi! + +## 2.7.0 + +- Stabilized web-related Rust toolchain's auto-installation. Thanks @bookshiyi! + +## 2.6.0 + +- Applied continuous integration for checking builds and improving project stability. Thanks @bookshiyi! + +## 2.5.6 + +- Updated Cargokit. Thanks @bookshiyi! + +## 2.5.5 + +- Improved guides about HTTP headers. + +## 2.5.4 + +- Updated example code. + +## 2.5.3 + +- Improved guides and CLI messages. + +## 2.5.2 + +- Optimized web binary size. + +## 2.5.1 + +- Optimized web performance. + +## 2.5.0 + +- Now Rust logic will be restarted upon Dart's hot restart on the web too. +- CLI commands are shortened. + +## 2.4.0 + +- Fixed the problem with dangling threads from the `tokio` runtime remaining after closing the Flutter app. Even after the app window was closed, `tokio` threads were still running, resulting in becoming a background process without a window. Now the `tokio` runtime will properly be shut down. + +## 2.3.2 + +- Re-publishing due to `pub.dev`'s `[UNKNOWN PLATFORMS]` error. + +## 2.3.1 + +- Restored the benefits section in the first guide. + +## 2.3.0 + +- Improved Dart's hot restart process on native platforms. + +## 2.2.0 + +- Improved the procedure of building for the web. +- Simplfied unneeded complexities. + +## 2.1.2 + +- Improved web alias module. +- Fixed small things. + +## 2.1.1 + +- Optimized the bridge thread on native platforms. +- Updated many minor errors in the guides. +- Fixed a problem with import statement not being written in `./lib/main.dart` when applying Rust template. + +## 2.1.0 + +- Merged `frb_engine` crate into `hub`. +- Removed unneeded intermediate worker pools. +- Added `time` web alias import. +- Added many guides and comments. + +## 2.0.1 + +- Improved guides. +- Added `print!` web alias macro. +- Organized exposed Dart APIs. + +## 2.0.0 + +- Added web support. + +## 1.6.6 + +- Improved guides. +- Now, the template application command will check if the current directory is a Flutter project first. + +## 1.6.5 + +- Improved guides. + +## 1.6.4 + +- Organized guide sections. + +## 1.6.3 + +- Organized guide sections. + +## 1.6.2 + +- Filled in missing translations. + +## 1.6.1 + +- Slightly improved guide sections. + +## 1.6.0 + +- Added step-by-step guides. + +## 1.5.3 + +- Fixed some example app code. + +## 1.5.2 + +- Improved the readability of example app code. + +## 1.5.1 + +- Added Japanese translation. +- Fixed some sentences in Korean guides. + +## 1.5.0 + +- Now the Android NDK version that the Flutter SDK expects will be used, not the version specified by this package. +- Fixed a bug saying `IntoDart` trait is not implemented. + +## 1.4.1 + +- Improved various guides. + +## 1.4.0 + +- Filled in various guides to help developers understand the structure more easily. + +## 1.3.2 + +- Added Chinese guides. Thanks @moluopro! +- Added Korean guides. +- Added guides about build tool version issues. +- Added guides about library bundling. + +## 1.3.1 + +- Fixed a problem with Rust crate path detection on Android. + +## 1.3.0 + +- Changed the name of an exposed enum. Now `Operation` has changed to `RustOperation` so that it won't make confusions with other operations. All developers should update their code to match this new name, probably using the batch replace function in various IDEs. +- Updated code snippets. + +## 1.2.8 + +- Fixed small things. + +## 1.2.7 + +- Stabilized `main.dart` modifcation upon `dart run rust_in_flutter:apply_template`. + +## 1.2.6 + +- Hid the information regarding the compilation of connector crates to avoid confusion with actual crates. + +## 1.2.5 + +- Updated the guide about Android NDK version. + +## 1.2.4 + +- Updated many outdated comments and guides. +- Decreased the time spent on `ensureInitialized`. Also, `ensureInitialized()` is automatically inserted in `main.dart` when doing `dart run rust_in_flutter:apply_template` from now on. +- Various code improvements were applied. + +## 1.2.3 + +- Clarified template structure in guides. + +## 1.2.2 + +- Hide more Dart APIs that are not meant to be used outside. + +## 1.2.1 + +- Updated many comments. +- Fine-tuned the visibility of Dart APIs. +- Organized guides. + +## 1.2.0 + +- Made the Rust request handler more future-proof, taking potential web support into account. + +## 1.1.1 + +- Improved various guides to help understanding the features of this package. + +## 1.1.0 + +- Now this package is a Flutter FFI plugin without dummy native code. +- Improved guides + +## 1.0.4 + +- Fixed a problem with library bundling on Linux. +- Added comments. +- Added guides. +- Improved template application. + +## 1.0.3 + +- Included code snippets in guides. + +## 1.0.2 + +- Fixed typos. +- Organized inner code. + +## 1.0.1 + +- Enforced bundling on macOS and iOS. +- Improved pub score. +- Make `apply_rust` modify `.gitignore`. + +## 1.0.0 + +- Previously `flutter_rust_app_template`, now this is a small convenient framework that can be applied to existing Flutter projects. diff --git a/flutter_ffi_plugin/pubspec.yaml b/flutter_ffi_plugin/pubspec.yaml index 44ef2ded6..454a6a114 100644 --- a/flutter_ffi_plugin/pubspec.yaml +++ b/flutter_ffi_plugin/pubspec.yaml @@ -1,82 +1,82 @@ -name: rinf -description: Rust for native business logic, Flutter for flexible and beautiful GUI -version: 6.12.0 -repository: https://github.com/cunarist/rinf - -environment: - sdk: ">=3.0.5 <4.0.0" - flutter: ">=3.3.0" - -dependencies: - flutter: - sdk: flutter - package_config: ^2.1.0 - path: ^1.8.3 - watcher: ^1.1.0 - ffi: ^2.1.0 - yaml: ^3.1.2 - -dev_dependencies: - lints: ">=3.0.0 <5.0.0" - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - # This section identifies this Flutter project as a plugin project. - # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) - # which should be registered in the plugin registry. This is required for - # using method channels. - # The Android 'package' specifies package in which the registered class is. - # This is required for using method channels on Android. - # The 'ffiPlugin' specifies that native code should be built and bundled. - # This is required for using `dart:ffi`. - # All these are used by the tooling to maintain consistency when - # adding or updating assets for this project. - # - # Please refer to README.md for a detailed explanation. - plugin: - platforms: - android: - ffiPlugin: true - ios: - ffiPlugin: true - linux: - ffiPlugin: true - macos: - ffiPlugin: true - windows: - ffiPlugin: true - web: - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages +name: rinf +description: Rust for native business logic, Flutter for flexible and beautiful GUI +version: 6.12.0 +repository: https://github.com/cunarist/rinf + +environment: + sdk: ">=3.0.5 <4.0.0" + flutter: ">=3.3.0" + +dependencies: + flutter: + sdk: flutter + package_config: ^2.1.0 + path: ^1.8.3 + watcher: ^1.1.0 + ffi: ^2.1.0 + yaml: ^3.1.2 + +dev_dependencies: + lints: ">=3.0.0 <5.0.0" + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) + # which should be registered in the plugin registry. This is required for + # using method channels. + # The Android 'package' specifies package in which the registered class is. + # This is required for using method channels on Android. + # The 'ffiPlugin' specifies that native code should be built and bundled. + # This is required for using `dart:ffi`. + # All these are used by the tooling to maintain consistency when + # adding or updating assets for this project. + # + # Please refer to README.md for a detailed explanation. + plugin: + platforms: + android: + ffiPlugin: true + ios: + ffiPlugin: true + linux: + ffiPlugin: true + macos: + ffiPlugin: true + windows: + ffiPlugin: true + web: + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index 341223574..e430db3e6 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -1,19 +1,19 @@ -[package] -# Do not change the name of this crate. -name = "hub" -version = "0.1.0" -edition = "2021" - -[lib] -# `lib` is required for non-library targets, -# such as tests and benchmarks. -# `cdylib` is for Linux, Android, Windows, and web. -# `staticlib` is for iOS and macOS. -crate-type = ["lib", "cdylib", "staticlib"] - -[dependencies] -rinf = "6.12.0" -prost = "0.12.6" -tokio = { version = "1", features = ["sync"] } -# wasm-bindgen = "0.2.92" # Uncomment this line to target the web -# tokio_with_wasm = "0.4.4" # Uncomment this line to target the web +[package] +# Do not change the name of this crate. +name = "hub" +version = "0.1.0" +edition = "2021" + +[lib] +# `lib` is required for non-library targets, +# such as tests and benchmarks. +# `cdylib` is for Linux, Android, Windows, and web. +# `staticlib` is for iOS and macOS. +crate-type = ["lib", "cdylib", "staticlib"] + +[dependencies] +rinf = "6.12.0" +prost = "0.12.6" +tokio = { version = "1", features = ["sync"] } +# wasm-bindgen = "0.2.92" # Uncomment this line to target the web +# tokio_with_wasm = "0.4.4" # Uncomment this line to target the web diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index 77db03570..b540f59ff 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -1,23 +1,23 @@ -[package] -name = "rinf" -version = "6.12.0" -edition = "2021" -license = "MIT" -description = "Rust for native business logic, Flutter for flexible and beautiful GUI" -repository = "https://github.com/cunarist/rinf" -documentation = "https://rinf.cunarist.com" -rust-version = "1.70" - -[target.'cfg(not(target_family = "wasm"))'.dependencies] -os-thread-local = "0.1.3" -backtrace = "0.3.69" -protoc-prebuilt = "0.3.0" -home = "0.5.9" -which = "6.0.0" -allo-isolate = "0.1.24" -tokio = { version = "1", features = ["rt-multi-thread"] } - -[target.'cfg(target_family = "wasm")'.dependencies] -js-sys = "0.3.69" -wasm-bindgen = "0.2.92" -wasm-bindgen-futures = "0.4.42" +[package] +name = "rinf" +version = "6.12.0" +edition = "2021" +license = "MIT" +description = "Rust for native business logic, Flutter for flexible and beautiful GUI" +repository = "https://github.com/cunarist/rinf" +documentation = "https://rinf.cunarist.com" +rust-version = "1.70" + +[target.'cfg(not(target_family = "wasm"))'.dependencies] +os-thread-local = "0.1.3" +backtrace = "0.3.69" +protoc-prebuilt = "0.3.0" +home = "0.5.9" +which = "6.0.0" +allo-isolate = "0.1.24" +tokio = { version = "1", features = ["rt-multi-thread"] } + +[target.'cfg(target_family = "wasm")'.dependencies] +js-sys = "0.3.69" +wasm-bindgen = "0.2.92" +wasm-bindgen-futures = "0.4.42" From 116af7e0713d087270e58e91b3bf35aa528d17cf Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 00:19:30 +0900 Subject: [PATCH 042/128] Version 6.12.1 --- CHANGELOG.md | 4 ++++ flutter_ffi_plugin/CHANGELOG.md | 4 ++++ flutter_ffi_plugin/example/native/hub/Cargo.toml | 2 +- flutter_ffi_plugin/pubspec.yaml | 2 +- flutter_ffi_plugin/template/native/hub/Cargo.toml | 2 +- rust_crate/Cargo.toml | 2 +- 6 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bac09b83..b59dc68e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.12.1 + +- Fixed linefeed problem in published files. + ## 6.12.0 - Generated message channels are now more efficient. diff --git a/flutter_ffi_plugin/CHANGELOG.md b/flutter_ffi_plugin/CHANGELOG.md index 621658232..400fe3dc1 100644 --- a/flutter_ffi_plugin/CHANGELOG.md +++ b/flutter_ffi_plugin/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.12.1 + +- Fixed linefeed problem in published files. + ## 6.12.0 - Generated message channels are now more efficient. diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index a8e0c456c..de173be11 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" crate-type = ["lib", "cdylib", "staticlib"] [dependencies] -rinf = "6.12.0" +rinf = "6.12.1" prost = "0.12.6" # tokio = { version = "1", features = ["sync"] } wasm-bindgen = "0.2.92" # Uncomment this line to target the web diff --git a/flutter_ffi_plugin/pubspec.yaml b/flutter_ffi_plugin/pubspec.yaml index 454a6a114..a3d989aa8 100644 --- a/flutter_ffi_plugin/pubspec.yaml +++ b/flutter_ffi_plugin/pubspec.yaml @@ -1,6 +1,6 @@ name: rinf description: Rust for native business logic, Flutter for flexible and beautiful GUI -version: 6.12.0 +version: 6.12.1 repository: https://github.com/cunarist/rinf environment: diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index e430db3e6..c8be858e6 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" crate-type = ["lib", "cdylib", "staticlib"] [dependencies] -rinf = "6.12.0" +rinf = "6.12.1" prost = "0.12.6" tokio = { version = "1", features = ["sync"] } # wasm-bindgen = "0.2.92" # Uncomment this line to target the web diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index b540f59ff..db8c2f9c2 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rinf" -version = "6.12.0" +version = "6.12.1" edition = "2021" license = "MIT" description = "Rust for native business logic, Flutter for flexible and beautiful GUI" From 2d2faa6f6a9ba760d100dddd62260e670307fbc1 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 12:02:21 +0900 Subject: [PATCH 043/128] Remove unneeded lint statement --- rust_crate/src/macros.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index dc2060d8c..28c0bf548 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -1,5 +1,3 @@ -#![allow(clippy::crate_in_macro_def)] - #[macro_export] /// Writes the interface code /// needed to communicate with Dart. From 713b0f572f732822a1a01c37c92fd83b632ea265 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 16:40:24 +0900 Subject: [PATCH 044/128] Detect Rust warnings in CI --- .github/workflows/quality_control.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/quality_control.yaml b/.github/workflows/quality_control.yaml index cc861e651..9082f463f 100644 --- a/.github/workflows/quality_control.yaml +++ b/.github/workflows/quality_control.yaml @@ -23,6 +23,8 @@ jobs: code: name: dart-and-rust-code runs-on: ubuntu-latest + env: + RUSTFLAGS: -D warnings steps: - name: Checkout repository From 394ff0f23c099abc577ccd04e3ef034d8b264e08 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 16:42:19 +0900 Subject: [PATCH 045/128] Do not import `backtrace` globally --- rust_crate/src/interface_os.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 395143ee1..13ab06bc2 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -1,6 +1,5 @@ use crate::debug_print; use allo_isolate::{IntoDart, Isolate, ZeroCopyBuffer}; -use backtrace::Backtrace; use os_thread_local::ThreadLocal; use std::cell::RefCell; use std::future::Future; @@ -35,7 +34,7 @@ where #[cfg(debug_assertions)] { std::panic::set_hook(Box::new(|panic_info| { - let backtrace = Backtrace::new(); + let backtrace = backtrace::Backtrace::new(); debug_print!("A panic occurred in Rust.\n{panic_info}\n{backtrace:?}"); })); } From 923fda46f78df292d7957f4e0ba45170f88b5df3 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 16:47:07 +0900 Subject: [PATCH 046/128] Make the linter on release mode web happy --- rust_crate/src/interface_web.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index ab34c49a9..4a527995a 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -1,4 +1,3 @@ -use crate::debug_print; use js_sys::Uint8Array; use std::future::Future; use wasm_bindgen::prelude::*; @@ -12,7 +11,7 @@ where #[cfg(debug_assertions)] { std::panic::set_hook(Box::new(|panic_info| { - debug_print!("A panic occurred in Rust.\n{panic_info}"); + crate::debug_print!("A panic occurred in Rust.\n{panic_info}"); })); } From bdbd45a8668c5deefbb242d97431c7d6f4949738 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 17:03:36 +0900 Subject: [PATCH 047/128] Use Clippy for checking errors in CI --- .github/workflows/quality_control.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quality_control.yaml b/.github/workflows/quality_control.yaml index 9082f463f..3244dbaf1 100644 --- a/.github/workflows/quality_control.yaml +++ b/.github/workflows/quality_control.yaml @@ -58,10 +58,10 @@ jobs: run: | rustup target add wasm32-unknown-unknown RUSTFLAGS="-D warnings" - cargo check - cargo check --release - cargo check --target wasm32-unknown-unknown - cargo check --target wasm32-unknown-unknown --release + cargo clippy + cargo clippy --release + cargo clippy --target wasm32-unknown-unknown + cargo clippy --target wasm32-unknown-unknown --release - name: Analyze code run: | From 216eb632d3ec1c11c600e5058bcde9204ab6a125 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 17:04:21 +0900 Subject: [PATCH 048/128] Remove unneeded CI command --- .github/workflows/quality_control.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/quality_control.yaml b/.github/workflows/quality_control.yaml index 3244dbaf1..88b8d33b6 100644 --- a/.github/workflows/quality_control.yaml +++ b/.github/workflows/quality_control.yaml @@ -57,7 +57,6 @@ jobs: - name: Check for any errors run: | rustup target add wasm32-unknown-unknown - RUSTFLAGS="-D warnings" cargo clippy cargo clippy --release cargo clippy --target wasm32-unknown-unknown From 9112c816d614c728c9735000dab11bc69979a866 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 17:07:57 +0900 Subject: [PATCH 049/128] Make Clippy happy --- rust_crate/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 28c0bf548..21c09d9f3 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -19,7 +19,7 @@ macro_rules! write_interface { #[cfg(not(target_family = "wasm"))] #[no_mangle] - pub extern "C" fn send_dart_signal_extern( + pub unsafe extern "C" fn send_dart_signal_extern( message_id: i64, message_pointer: *const u8, message_size: usize, From 55e70b4771f29d1b1cd4e8353e76ea2509610372 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 17:15:21 +0900 Subject: [PATCH 050/128] Add doc comments for `RustSignal` fields --- flutter_ffi_plugin/lib/src/interface.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/flutter_ffi_plugin/lib/src/interface.dart b/flutter_ffi_plugin/lib/src/interface.dart index f7676b79f..a3bc1c8ab 100644 --- a/flutter_ffi_plugin/lib/src/interface.dart +++ b/flutter_ffi_plugin/lib/src/interface.dart @@ -10,7 +10,13 @@ typedef HandleRustSignal = void Function(int, Uint8List, Uint8List); /// This type is generic, and the message /// can be of any type declared in Protobuf. class RustSignal { - T message; - Uint8List binary; + /// The message instance of a class generated by Protobuf. + final T message; + + /// Binary data included in the signal. + /// This field is useful for sending custom bytes + /// without the overhead of serialization/deserialization. + final Uint8List binary; + RustSignal(this.message, this.binary); } From 4557ca865906430c32d926c61489fb0fa734c179 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 17:16:55 +0900 Subject: [PATCH 051/128] Add doc comments for `DartSignal` fields --- rust_crate/src/interface.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index 27ba04207..cd18338d5 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -10,7 +10,11 @@ use super::interface_web::*; /// This type is generic, and the message /// can be of any type declared in Protobuf. pub struct DartSignal { + /// The message instance of a struct generated by Protobuf. pub message: T, + /// Binary data included in the signal. + /// This field is useful for sending custom bytes + /// without the overhead of serialization/deserialization. pub binary: Vec, } From 9e123737d63dd0fc7aec8481c2f6e406c9bbed01 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 17:48:35 +0900 Subject: [PATCH 052/128] Remove all panics from Rinf executable --- rust_crate/src/common.rs | 3 +++ rust_crate/src/lib.rs | 1 + rust_crate/src/main.rs | 58 +++++++++++++++++++++++++--------------- 3 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 rust_crate/src/common.rs diff --git a/rust_crate/src/common.rs b/rust_crate/src/common.rs new file mode 100644 index 000000000..fa138cb41 --- /dev/null +++ b/rust_crate/src/common.rs @@ -0,0 +1,3 @@ +use std::error::Error; + +pub type Result = std::result::Result>; diff --git a/rust_crate/src/lib.rs b/rust_crate/src/lib.rs index cceb7e5b9..8d5a7d1b2 100644 --- a/rust_crate/src/lib.rs +++ b/rust_crate/src/lib.rs @@ -1,3 +1,4 @@ +mod common; mod macros; mod interface; diff --git a/rust_crate/src/main.rs b/rust_crate/src/main.rs index ee8aa8a8a..fe396e900 100644 --- a/rust_crate/src/main.rs +++ b/rust_crate/src/main.rs @@ -1,39 +1,55 @@ +mod common; +use common::*; + #[cfg(not(target_family = "wasm"))] -fn main() { +fn main() -> Result<()> { use std::env; use std::fs; use std::path; use std::process; // Verify Protobuf compiler. - let protoc_path; - if let Ok(installed) = which::which("protoc") { + let protoc_path = if let Ok(installed) = which::which("protoc") { // Get the path of Protobuf compiler that's already installed. println!("Detected `protoc`, skipping auto installation."); - protoc_path = installed.parent().unwrap().to_path_buf(); + installed + .parent() + .ok_or("Could not get the parent of `protoc` path.")? + .to_path_buf() } else { // Install Protobuf compiler and get the path. - let home_path = home::home_dir().unwrap(); + let home_path = + home::home_dir().ok_or("Could not get home directory for `protoc` installation.")?; let out_path = home_path.join(".local").join("bin"); - fs::create_dir_all(&out_path).unwrap(); - env::set_var("OUT_DIR", out_path.to_str().unwrap()); + fs::create_dir_all(&out_path)?; + env::set_var( + "OUT_DIR", + out_path + .to_str() + .ok_or("Could not set environment variable path")?, + ); let install_result = protoc_prebuilt::init("25.2"); - if install_result.is_err() { - println!("Automatic installation of `protoc` failed."); - println!("Try installing `protoc` manually and adding it to PATH."); - } - let (protoc_binary_path, _) = install_result.unwrap(); - protoc_path = protoc_binary_path.parent().unwrap().to_path_buf(); - } + let (protoc_binary_path, _) = install_result.map_err(|_| { + format!( + "{}\n{}", + "Automatic installation of `protoc` failed.", + "Try installing `protoc` manually and adding it to PATH." + ) + })?; + protoc_binary_path + .parent() + .ok_or("Could not get the parent of installed `protoc` path.")? + .to_path_buf() + }; // Find the path where Dart executables are located. #[cfg(target_family = "windows")] - let pub_cache_bin_path = path::PathBuf::from(env::var("LOCALAPPDATA").unwrap()) + let pub_cache_bin_path = path::PathBuf::from(env::var("LOCALAPPDATA")?) .join("Pub") .join("Cache") .join("bin"); #[cfg(target_family = "unix")] - let pub_cache_bin_path = path::PathBuf::from(env::var("HOME").unwrap()) + let pub_cache_bin_path = path::PathBuf::from(env::var("HOME")?) .join(".pub-cache") .join("bin"); @@ -44,19 +60,19 @@ fn main() { }; path_var.push(protoc_path); path_var.push(pub_cache_bin_path); - env::set_var("PATH", env::join_paths(path_var).unwrap()); + env::set_var("PATH", env::join_paths(path_var)?); // Get command-line arguments excluding the program name. let dart_command_args: Vec = env::args().skip(1).collect(); - // Build the command to run the Dart script. - let dart_path = which::which("dart").expect("Couldn't find Dart executable"); + // Run the Dart script. + let dart_path = which::which("dart")?; let mut command = process::Command::new(dart_path); command.args(["run", "rinf"]); command.args(&dart_command_args); + command.status()?; - // Execute the command - let _ = command.status(); + Ok(()) } #[cfg(target_family = "wasm")] From 1d6c8bc51b2b24d8d66ec02b710c84342d3d601d Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 18:32:18 +0900 Subject: [PATCH 053/128] Remove panicking code from Rust lib crate --- rust_crate/src/interface.rs | 21 ++++++++++++----- rust_crate/src/interface_os.rs | 42 ++++++++++++++++++++------------- rust_crate/src/interface_web.rs | 13 ++++++++-- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index cd18338d5..06c427086 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -1,3 +1,4 @@ +use crate::debug_print; use std::future::Future; #[cfg(not(target_family = "wasm"))] @@ -18,15 +19,23 @@ pub struct DartSignal { pub binary: Vec, } -/// Send a signal to Dart. -pub fn send_rust_signal(message_id: i32, message_bytes: Vec, binary: Vec) { - send_rust_signal_real(message_id, message_bytes, binary); -} - /// Runs the main function in Rust. pub fn start_rust_logic(main_future: F) where F: Future + Send + 'static, { - start_rust_logic_real(main_future); + let result = start_rust_logic_real(main_future); + if let Err(error) = result { + debug_print!("Could not start Rust logic.\n{error:#?}"); + } +} + +/// Send a signal to Dart. +pub fn send_rust_signal(message_id: i32, message_bytes: Vec, binary: Vec) { + let result = send_rust_signal_real(message_id, message_bytes, binary); + if let Err(error) = result { + // We cannot use `debug_print` here because + // it uses `send_rust_siganl` internally. + println!("Could not send Rust signal.\n{error:#?}"); + } } diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 13ab06bc2..41aa3a2bc 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -1,9 +1,9 @@ +use crate::common::*; use crate::debug_print; use allo_isolate::{IntoDart, Isolate, ZeroCopyBuffer}; use os_thread_local::ThreadLocal; use std::cell::RefCell; use std::future::Future; -use std::panic::catch_unwind; use std::sync::{Mutex, OnceLock}; use tokio::runtime::{Builder, Runtime}; @@ -11,11 +11,15 @@ static DART_ISOLATE: Mutex> = Mutex::new(None); #[no_mangle] pub extern "C" fn prepare_isolate_extern(port: i64) { - let _ = catch_unwind(|| { - let dart_isolate = Isolate::new(port); - let mut guard = DART_ISOLATE.lock().unwrap(); - guard.replace(dart_isolate); - }); + let dart_isolate = Isolate::new(port); + let mut guard = match DART_ISOLATE.lock() { + Ok(inner) => inner, + Err(_) => { + println!("Could not unlock Dart isolate mutex."); + return; + } + }; + guard.replace(dart_isolate); } // We use `os_thread_local` so that when the program fails @@ -26,7 +30,7 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { type TokioRuntime = OnceLock>>>; static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); -pub fn start_rust_logic_real(main_future: F) +pub fn start_rust_logic_real(main_future: F) -> Result<()> where F: Future + Send + 'static, { @@ -40,7 +44,7 @@ where } // Run the main function. - let tokio_runtime = Builder::new_multi_thread().enable_all().build().unwrap(); + let tokio_runtime = Builder::new_multi_thread().enable_all().build()?; tokio_runtime.spawn(main_future); TOKIO_RUNTIME .get_or_init(|| ThreadLocal::new(|| RefCell::new(None))) @@ -51,19 +55,21 @@ where // being replaced with the new one. cell.replace(Some(tokio_runtime)); }); + + Ok(()) } -pub fn send_rust_signal_real(message_id: i32, message_bytes: Vec, binary: Vec) { +pub fn send_rust_signal_real( + message_id: i32, + message_bytes: Vec, + binary: Vec, +) -> Result<()> { // When `DART_ISOLATE` is not initialized, do nothing. // This can happen when running test code in Rust. - let guard = DART_ISOLATE.lock().unwrap(); - let dart_isolate = match guard.as_ref() { - Some(inner) => inner, - None => { - debug_print!("Dart isolate for sending Rust signals is not present."); - return; - } - }; + let guard = DART_ISOLATE.lock()?; + let dart_isolate = guard + .as_ref() + .ok_or("Dart isolate for sending Rust signals is not present.")?; // If a `Vec` is empty, we can't just simply send it to Dart // because panic can occur from null pointers. @@ -87,4 +93,6 @@ pub fn send_rust_signal_real(message_id: i32, message_bytes: Vec, binary: Ve ] .into_dart(), ); + + Ok(()) } diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index 4a527995a..313458314 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -1,9 +1,10 @@ +use crate::common::*; use js_sys::Uint8Array; use std::future::Future; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::spawn_local; -pub fn start_rust_logic_real(main_future: F) +pub fn start_rust_logic_real(main_future: F) -> Result<()> where F: Future + Send + 'static, { @@ -17,6 +18,8 @@ where // Run the main function. spawn_local(main_future); + + Ok(()) } #[wasm_bindgen] @@ -25,10 +28,16 @@ extern "C" { pub fn send_rust_signal_extern(resource: i32, message_bytes: Uint8Array, binary: Uint8Array); } -pub fn send_rust_signal_real(message_id: i32, message_bytes: Vec, binary: Vec) { +pub fn send_rust_signal_real( + message_id: i32, + message_bytes: Vec, + binary: Vec, +) -> Result<()> { send_rust_signal_extern( message_id, js_sys::Uint8Array::from(message_bytes.as_slice()), js_sys::Uint8Array::from(binary.as_slice()), ); + + Ok(()) } From 25d4185d914e26c8042bc05efd5c3ce79053b08e Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 18:33:02 +0900 Subject: [PATCH 054/128] Remove lint warning from Rust executable in wasm --- rust_crate/src/main.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rust_crate/src/main.rs b/rust_crate/src/main.rs index fe396e900..3d810512a 100644 --- a/rust_crate/src/main.rs +++ b/rust_crate/src/main.rs @@ -26,7 +26,7 @@ fn main() -> Result<()> { "OUT_DIR", out_path .to_str() - .ok_or("Could not set environment variable path")?, + .ok_or("Could not set the path for `protoc` installation.")?, ); let install_result = protoc_prebuilt::init("25.2"); let (protoc_binary_path, _) = install_result.map_err(|_| { @@ -76,6 +76,7 @@ fn main() -> Result<()> { } #[cfg(target_family = "wasm")] -fn main() { +fn main() -> Result<()> { // Dummy function to make the linter happy. + Ok(()) } From c06f0ee16f588f5dc637d7daca574cd97dd56ef1 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 18:42:31 +0900 Subject: [PATCH 055/128] Remove `unwrap` and `expect` from `sample_crate` --- .../native/hub/src/sample_functions.rs | 25 +++++++++++-------- .../example/native/sample_crate/src/lib.rs | 14 +++-------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index 63075d1bc..03b31f61c 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -79,8 +79,14 @@ pub async fn stream_fractal() { // Receive frame join handles in order. tokio::spawn(async move { loop { - let join_handle = receiver.recv().await.unwrap(); - let received_frame = join_handle.await.unwrap(); + let join_handle = match receiver.recv().await { + Some(inner) => inner, + None => continue, + }; + let received_frame = match join_handle.await { + Ok(inner) => inner, + Err(_) => continue, + }; if let Some(fractal_image) = received_frame { // Stream the image data to Dart. SampleFractal { @@ -124,15 +130,11 @@ pub async fn run_debug_tests() { // Fetch data from a web API. let url = "http://jsonplaceholder.typicode.com/todos/1"; let web_response = sample_crate::fetch_from_web_api(url).await; - debug_print!("Response from a web API: {web_response}"); + debug_print!("Response from a web API: {web_response:?}"); // Use a crate that accesses operating system APIs. - let option = sample_crate::get_hardward_id(); - if let Some(hwid) = option { - debug_print!("Hardware ID: {hwid}"); - } else { - debug_print!("Hardware ID is not available on this platform."); - } + let hwid = sample_crate::get_hardward_id(); + debug_print!("Hardware ID: {hwid:?}"); // Test `tokio::join!` for futures. let join_first = async { @@ -201,8 +203,9 @@ pub async fn run_debug_tests() { join_handles.push(join_handle); } for join_handle in join_handles { - let text = join_handle.await.unwrap(); - debug_print!("{text}"); + if let Ok(text) = join_handle.await { + debug_print!("{text}"); + } } debug_print!("Debug tests completed!"); diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs index 0e7d26483..68be63ce6 100755 --- a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs +++ b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs @@ -1,8 +1,7 @@ //! This crate is written for Rinf demonstrations. -pub use fractal::draw_fractal_image; - mod fractal; +pub use fractal::draw_fractal_image; // `machineid_rs` only supports desktop platforms. @@ -12,7 +11,7 @@ pub fn get_hardward_id() -> Option { builder .add_component(machineid_rs::HWIDComponent::SystemID) .add_component(machineid_rs::HWIDComponent::CPUCores); - let hwid = builder.build("mykey").unwrap(); + let hwid = builder.build("mykey").ok()?; Some(hwid) } #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] @@ -29,11 +28,6 @@ pub fn get_current_time() -> DateTime { // `reqwest` supports all platforms, including web. -pub async fn fetch_from_web_api(url: &str) -> String { - reqwest::get(url) - .await - .expect("Could not get the response from the example web API.") - .text() - .await - .expect("Could not read body from the web response.") +pub async fn fetch_from_web_api(url: &str) -> Option { + reqwest::get(url).await.ok()?.text().await.ok() } From fa4e226e1ecbaf611b0cd4d073b4f2c777cec1ba Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 18:42:49 +0900 Subject: [PATCH 056/128] Organize code in `sample_crate` --- flutter_ffi_plugin/example/native/sample_crate/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs index 68be63ce6..a6170456f 100755 --- a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs +++ b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs @@ -4,7 +4,6 @@ mod fractal; pub use fractal::draw_fractal_image; // `machineid_rs` only supports desktop platforms. - #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] pub fn get_hardward_id() -> Option { let mut builder = machineid_rs::IdBuilder::new(machineid_rs::Encryption::MD5); @@ -20,14 +19,12 @@ pub fn get_hardward_id() -> Option { } // `chrono` supports all platforms, including web. - use chrono::{offset, DateTime}; pub fn get_current_time() -> DateTime { offset::Local::now() } // `reqwest` supports all platforms, including web. - pub async fn fetch_from_web_api(url: &str) -> Option { reqwest::get(url).await.ok()?.text().await.ok() } From dcbf4c9099a6babf2b0e34a5100e5986fb6d1f75 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 19:06:35 +0900 Subject: [PATCH 057/128] Remove panicking code from Dart signal handler --- flutter_ffi_plugin/bin/src/message.dart | 58 +++++++++++++++++-------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 0acaef5d7..cc9f5d5b8 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -267,7 +267,7 @@ use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; rustPath, ''' type ${messageName}Cell = Mutex>>, + UnboundedSender>, Option>>, )>>; pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = @@ -278,16 +278,16 @@ impl ${normalizePascal(messageName)} { let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock().unwrap(); if guard.is_none() { let (sender, receiver) = unbounded_channel(); - guard.replace((Some(sender), Some(receiver))); + guard.replace((sender, Some(receiver))); } #[cfg(debug_assertions)] { // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - if guard.as_ref().unwrap().0.as_ref().unwrap().is_closed() { + if guard.as_ref().unwrap().0.is_closed() { let (sender, receiver) = unbounded_channel(); - guard.replace((Some(sender), Some(receiver))); + guard.replace((sender, Some(receiver))); } } let pair = guard.take().unwrap(); @@ -391,13 +391,17 @@ impl ${normalizePascal(messageName)} { use crate::tokio; use prost::Message; +use rinf::debug_print; use rinf::DartSignal; use std::collections::HashMap; +use std::error::Error; use std::sync::OnceLock; use tokio::sync::mpsc::unbounded_channel; -type SignalHandlers = - OnceLock, Vec) + Send + Sync>>>; +type SignalHandlers = OnceLock< + HashMap, Vec) + -> Result<(), Box> + Send + Sync>>, +>; static SIGNAL_HANDLERS: SignalHandlers = OnceLock::new(); pub fn handle_dart_signal( @@ -406,10 +410,11 @@ pub fn handle_dart_signal( binary: Vec ) { let hash_map = SIGNAL_HANDLERS.get_or_init(|| { - let mut new_hash_map = - HashMap - ::, Vec) + Send + Sync>> - ::new(); + let mut new_hash_map = HashMap::< + i32, + Box, Vec) + -> Result<(), Box> + Send + Sync>, + >::new(); '''; for (final entry in markedMessagesAll.entries) { final subpath = entry.key; @@ -432,29 +437,35 @@ new_hash_map.insert( use super::$modulePath$filename::*; let message = ${normalizePascal(messageName)}::decode( message_bytes.as_slice() - ).unwrap(); + )?; let dart_signal = DartSignal { message, binary, }; - let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock().unwrap(); + let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock()?; if guard.is_none() { let (sender, receiver) = unbounded_channel(); - guard.replace((Some(sender), Some(receiver))); + guard.replace((sender, Some(receiver))); } #[cfg(debug_assertions)] { // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - if guard.as_ref().unwrap().0.as_ref().unwrap().is_closed() { + let pair = guard + .as_ref() + .ok_or("Message channel in Rust not present.")?; + if pair.0.is_closed() { let (sender, receiver) = unbounded_channel(); - guard.replace((Some(sender), Some(receiver))); + guard.replace((sender, Some(receiver))); } } - let pair = guard.as_ref().unwrap(); - let sender = pair.0.as_ref().unwrap(); + let pair = guard + .as_ref() + .ok_or("Message channel in Rust not present.")?; + let sender = &pair.0; let _ = sender.send(dart_signal); + Ok(()) }), ); '''; @@ -466,8 +477,17 @@ new_hash_map.insert( new_hash_map }); - let signal_handler = hash_map.get(&message_id).unwrap(); - signal_handler(message_bytes, binary); + let signal_handler = match hash_map.get(&message_id) { + Some(inner) => inner, + None => { + debug_print!("Message ID not found in the handler Hashmap."); + return; + } + }; + let result = signal_handler(message_bytes, binary); + if let Err(error) = result { + debug_print!("Could not process hashmap.\\n{error:#?}"); + } } '''; await File.fromUri(rustOutputPath.join('generated.rs')) From b61d56b55f3b0e42cd7e385793edcc213703bc5a Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 19:11:24 +0900 Subject: [PATCH 058/128] Replace all `unwrap` with `expect` --- flutter_ffi_plugin/bin/src/message.dart | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index cc9f5d5b8..2c14deb62 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -275,7 +275,8 @@ pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = impl ${normalizePascal(messageName)} { pub fn get_dart_signal_receiver() -> UnboundedReceiver> { - let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock().unwrap(); + let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock() + .expect("Could not access the channel lock."); if guard.is_none() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); @@ -285,14 +286,19 @@ impl ${normalizePascal(messageName)} { // After Dart's hot restart, // a sender from the previous run already exists // which is now closed. - if guard.as_ref().unwrap().0.is_closed() { + let pair = guard + .as_ref() + .expect("Message channel in Rust not present."); + if pair.0.is_closed() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); } } - let pair = guard.take().unwrap(); + let pair = guard + .as_ref() + .expect("Message channel in Rust not present."); guard.replace((pair.0, None)); - pair.1.expect("A receiver can be taken only once") + pair.1.expect("Each Dart signal receiver can be taken only once") } } ''', From ddb32ded45ba32b3d44999204b9ef8c86ce196e4 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 19:13:01 +0900 Subject: [PATCH 059/128] Fix a small bug --- flutter_ffi_plugin/bin/src/message.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 2c14deb62..60e3df3ce 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -295,7 +295,7 @@ impl ${normalizePascal(messageName)} { } } let pair = guard - .as_ref() + .take() .expect("Message channel in Rust not present."); guard.replace((pair.0, None)); pair.1.expect("Each Dart signal receiver can be taken only once") From 320e2dede44d3eeb55b39c9b6db7c06e80b748e7 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 19:17:52 +0900 Subject: [PATCH 060/128] Remove `catch_unwind` as there's no panicking code anymore --- rust_crate/src/interface.rs | 9 +++------ rust_crate/src/macros.rs | 30 ++++++++++++++++-------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index 06c427086..c839bd326 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -1,4 +1,4 @@ -use crate::debug_print; +use crate::common::*; use std::future::Future; #[cfg(not(target_family = "wasm"))] @@ -20,14 +20,11 @@ pub struct DartSignal { } /// Runs the main function in Rust. -pub fn start_rust_logic(main_future: F) +pub fn start_rust_logic(main_future: F) -> Result<()> where F: Future + Send + 'static, { - let result = start_rust_logic_real(main_future); - if let Err(error) = result { - debug_print!("Could not start Rust logic.\n{error:#?}"); - } + start_rust_logic_real(main_future) } /// Send a signal to Dart. diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 21c09d9f3..5042f8bf2 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -8,13 +8,19 @@ macro_rules! write_interface { #[cfg(not(target_family = "wasm"))] #[no_mangle] pub extern "C" fn start_rust_logic_extern() { - let _ = std::panic::catch_unwind(|| $crate::start_rust_logic(main())); + let result = $crate::start_rust_logic(main()); + if let Err(error) = result { + println!("Could not start Rust logic.\n{error:#?}"); + } } #[cfg(target_family = "wasm")] #[wasm_bindgen::prelude::wasm_bindgen] pub fn start_rust_logic_extern() { - let _ = std::panic::catch_unwind(|| $crate::start_rust_logic(main())); + let result = $crate::start_rust_logic(main()); + if let Err(error) = result { + println!("Could not start Rust logic.\n{error:#?}"); + } } #[cfg(not(target_family = "wasm"))] @@ -26,23 +32,19 @@ macro_rules! write_interface { binary_pointer: *const u8, binary_size: usize, ) { - let _ = std::panic::catch_unwind(|| { - let message_bytes = - unsafe { std::slice::from_raw_parts(message_pointer, message_size).to_vec() }; - let binary = - unsafe { std::slice::from_raw_parts(binary_pointer, binary_size).to_vec() }; - messages::generated::handle_dart_signal(message_id as i32, message_bytes, binary); - }); + let message_bytes = + unsafe { std::slice::from_raw_parts(message_pointer, message_size).to_vec() }; + let binary = + unsafe { std::slice::from_raw_parts(binary_pointer, binary_size).to_vec() }; + messages::generated::handle_dart_signal(message_id as i32, message_bytes, binary); } #[cfg(target_family = "wasm")] #[wasm_bindgen::prelude::wasm_bindgen] pub fn send_dart_signal_extern(message_id: i32, message_bytes: &[u8], binary: &[u8]) { - let _ = std::panic::catch_unwind(|| { - let message_bytes = message_bytes.to_vec(); - let binary = binary.to_vec(); - messages::generated::handle_dart_signal(message_id, message_bytes, binary); - }); + let message_bytes = message_bytes.to_vec(); + let binary = binary.to_vec(); + messages::generated::handle_dart_signal(message_id, message_bytes, binary); } }; } From b8357ad4fd0524146a97dfc2387932f4bb3be474 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 9 Jun 2024 19:22:02 +0900 Subject: [PATCH 061/128] Make clipper happy in release mode --- rust_crate/src/interface_os.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 41aa3a2bc..cf1f13401 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -1,5 +1,4 @@ use crate::common::*; -use crate::debug_print; use allo_isolate::{IntoDart, Isolate, ZeroCopyBuffer}; use os_thread_local::ThreadLocal; use std::cell::RefCell; @@ -39,7 +38,7 @@ where { std::panic::set_hook(Box::new(|panic_info| { let backtrace = backtrace::Backtrace::new(); - debug_print!("A panic occurred in Rust.\n{panic_info}\n{backtrace:?}"); + crate::debug_print!("A panic occurred in Rust.\n{panic_info}\n{backtrace:?}"); })); } From 01e61cec657e3d7aca555442d0e54c8a67f87be1 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 10 Jun 2024 01:29:52 +0900 Subject: [PATCH 062/128] Consider base href on the web --- flutter_ffi_plugin/lib/src/load_web.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/flutter_ffi_plugin/lib/src/load_web.dart b/flutter_ffi_plugin/lib/src/load_web.dart index 759492a26..a4861d5ba 100644 --- a/flutter_ffi_plugin/lib/src/load_web.dart +++ b/flutter_ffi_plugin/lib/src/load_web.dart @@ -23,13 +23,19 @@ Future loadJsFile() async { final loadCompleter = Completer(); js.context['completeRinfLoad'] = loadCompleter.complete; + // Flutter app doesn't always have the top-level path of the domain. + // Sometimes, the flutter app might be placed in a lower path. + // This variable includes domain and the base path. + final baseHref = Uri.base; + // Use the default JavaScript path unless provided. - final path = jsLibPath ?? "/pkg/hub.js"; + final path = jsLibPath ?? "pkg/hub.js"; + final fullUrl = baseHref.resolve(path); final scriptElement = ScriptElement(); scriptElement.type = "module"; scriptElement.innerHtml = ''' -import init, * as wasmBindings from "$path"; +import init, * as wasmBindings from "$fullUrl"; await init(); window.rinf = { ...wasmBindings }; completeRinfLoad(); From 52d10a32a937673dfde7b3de049a071818b37ca6 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 10 Jun 2024 01:48:41 +0900 Subject: [PATCH 063/128] Upgrade `tokio_with_wasm` --- documentation/docs/frequently-asked-questions.md | 2 +- flutter_ffi_plugin/example/native/hub/Cargo.toml | 13 ++++++++++--- flutter_ffi_plugin/example/native/hub/src/lib.rs | 6 ++++-- flutter_ffi_plugin/template/native/hub/Cargo.toml | 7 +++++-- flutter_ffi_plugin/template/native/hub/src/lib.rs | 5 ++++- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/documentation/docs/frequently-asked-questions.md b/documentation/docs/frequently-asked-questions.md index d64be28e8..b5848f184 100644 --- a/documentation/docs/frequently-asked-questions.md +++ b/documentation/docs/frequently-asked-questions.md @@ -270,7 +270,7 @@ Here are the current constraints of the `wasm32-unknown-unknown` target: - Numerous functionalities within `std::fs` remain unimplemented. - Various features of `std::net` are not available. Consider using `reqwest` crate instead. `reqwest` supports `wasm32-unknown-unknown` and relies on JavaScript to perform network communications. -- `std::thread::spawn` doesn't work. Consider using `tokio_with_wasm::tokio::task::spawn_blocking` instead. +- `std::thread::spawn` doesn't work. Consider using `tokio_with_wasm::task::spawn_blocking` instead. - Several features of `std::time::Instant` are unimplemented. Consider using `chrono` as an alternative. `chrono` supports `wasm32-unknown-unknown` and relies on JavaScript to obtain system time. - In case of a panic in an asynchronous Rust task, it aborts and throws a JavaScript `RuntimeError` [which Rust cannot catch](https://stackoverflow.com/questions/59426545/rust-paniccatch-unwind-no-use-in-webassembly). A recommended practice is to replace `.unwrap` with `.expect` or handle errors with `Err` instances. diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index de173be11..8b720ab3d 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -14,7 +14,14 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] rinf = "6.12.1" prost = "0.12.6" -# tokio = { version = "1", features = ["sync"] } -wasm-bindgen = "0.2.92" # Uncomment this line to target the web -tokio_with_wasm = "0.4.4" # Uncomment this line to target the web +tokio = { version = "1", features = ["rt", "sync", "macros", "time"] } sample_crate = { path = "../sample_crate" } + +[target.'cfg(target_family = "wasm")'.dependencies] +wasm-bindgen = "0.2.92" +tokio_with_wasm = { version = "0.5.0", features = [ + "rt", + "sync", + "macros", + "time", +] } diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs index 26bc5a855..1cbfda2dd 100755 --- a/flutter_ffi_plugin/example/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs @@ -4,8 +4,10 @@ mod messages; mod sample_functions; -// use tokio; -use tokio_with_wasm::tokio; // Uncomment this line to target the web +#[cfg(not(target_family = "wasm"))] +use tokio; +#[cfg(target_family = "wasm")] +use tokio_with_wasm as tokio; rinf::write_interface!(); diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index c8be858e6..9ccfff7a0 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -15,5 +15,8 @@ crate-type = ["lib", "cdylib", "staticlib"] rinf = "6.12.1" prost = "0.12.6" tokio = { version = "1", features = ["sync"] } -# wasm-bindgen = "0.2.92" # Uncomment this line to target the web -# tokio_with_wasm = "0.4.4" # Uncomment this line to target the web + +# Uncomment below to target the web. +# [target.'cfg(target_family = "wasm")'.dependencies] +# wasm-bindgen = "0.2.92" +# tokio_with_wasm = { version = "0.5.0", features = ["sync"] } diff --git a/flutter_ffi_plugin/template/native/hub/src/lib.rs b/flutter_ffi_plugin/template/native/hub/src/lib.rs index e1a12658b..5c84058cf 100644 --- a/flutter_ffi_plugin/template/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/template/native/hub/src/lib.rs @@ -3,8 +3,11 @@ mod messages; +// Uncomment below to target the web. +// #[cfg(not(target_family = "wasm"))] use tokio; -// use tokio_with_wasm::tokio; // Uncomment this line to target the web +// #[cfg(target_family = "wasm")] +// use tokio_with_wasm as tokio; rinf::write_interface!(); From d4f0a6a895164e5153573bc568580ae5ee396eb1 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 10 Jun 2024 01:57:24 +0900 Subject: [PATCH 064/128] Bump `tokio_with_wasm` version --- flutter_ffi_plugin/example/native/hub/Cargo.toml | 2 +- flutter_ffi_plugin/template/native/hub/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index 8b720ab3d..c5828b869 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -19,7 +19,7 @@ sample_crate = { path = "../sample_crate" } [target.'cfg(target_family = "wasm")'.dependencies] wasm-bindgen = "0.2.92" -tokio_with_wasm = { version = "0.5.0", features = [ +tokio_with_wasm = { version = "0.5.1", features = [ "rt", "sync", "macros", diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index 9ccfff7a0..6e1614cb9 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -19,4 +19,4 @@ tokio = { version = "1", features = ["sync"] } # Uncomment below to target the web. # [target.'cfg(target_family = "wasm")'.dependencies] # wasm-bindgen = "0.2.92" -# tokio_with_wasm = { version = "0.5.0", features = ["sync"] } +# tokio_with_wasm = { version = "0.5.1", features = ["sync"] } From 4dcaf20ca7c135495218dd0ce01e219b9039f864 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 10 Jun 2024 02:05:01 +0900 Subject: [PATCH 065/128] Update Python automation script --- automate/__main__.py | 52 ++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/automate/__main__.py b/automate/__main__.py index d0fa5d425..ad99b6966 100644 --- a/automate/__main__.py +++ b/automate/__main__.py @@ -50,23 +50,33 @@ def replace_text_in_file(filepath: str, change_from: str, change_to: str): # Enable the web target, since it's not enabled by default. replace_text_in_file( "native/hub/src/lib.rs", - "use tokio;", - "// use tokio;", + '// #[cfg(not(target_family = "wasm"))]', + '#[cfg(not(target_family = "wasm"))]', ) replace_text_in_file( "native/hub/src/lib.rs", - "// use tokio_with_wasm", - "use tokio_with_wasm", + '// #[cfg(target_family = "wasm")]', + '#[cfg(target_family = "wasm")]', + ) + replace_text_in_file( + "native/hub/src/lib.rs", + "// use tokio_with_wasm as tokio;", + "use tokio_with_wasm as tokio;", + ) + replace_text_in_file( + "native/hub/Cargo.toml", + "# [target.'cfg(target_family = \"wasm\")'.dependencies]", + "[target.'cfg(target_family = \"wasm\")'.dependencies]", ) replace_text_in_file( "native/hub/Cargo.toml", - "# wasm-bindgen", - "wasm-bindgen", + '# wasm-bindgen = "0.2.92"', + 'wasm-bindgen = "0.2.92"', ) replace_text_in_file( "native/hub/Cargo.toml", - "# tokio_with_wasm", - "tokio_with_wasm", + '# tokio_with_wasm = { version = "0.5.1", features = ["sync"] }', + 'tokio_with_wasm = { version = "0.5.1", features = ["sync"] }', ) os.chdir("../") @@ -104,23 +114,33 @@ def replace_text_in_file(filepath: str, change_from: str, change_to: str): # Enable the web target, since it's not enabled by default. replace_text_in_file( "native/hub/src/lib.rs", - "use tokio;", - "// use tokio;", + '// #[cfg(not(target_family = "wasm"))]', + '#[cfg(not(target_family = "wasm"))]', ) replace_text_in_file( "native/hub/src/lib.rs", - "// use tokio_with_wasm", - "use tokio_with_wasm", + '// #[cfg(target_family = "wasm")]', + '#[cfg(target_family = "wasm")]', + ) + replace_text_in_file( + "native/hub/src/lib.rs", + "// use tokio_with_wasm as tokio;", + "use tokio_with_wasm as tokio;", + ) + replace_text_in_file( + "native/hub/Cargo.toml", + "# [target.'cfg(target_family = \"wasm\")'.dependencies]", + "[target.'cfg(target_family = \"wasm\")'.dependencies]", ) replace_text_in_file( "native/hub/Cargo.toml", - "# wasm-bindgen", - "wasm-bindgen", + '# wasm-bindgen = "0.2.92"', + 'wasm-bindgen = "0.2.92"', ) replace_text_in_file( "native/hub/Cargo.toml", - "# tokio_with_wasm", - "tokio_with_wasm", + '# tokio_with_wasm = { version = "0.5.1", features = ["sync"] }', + 'tokio_with_wasm = { version = "0.5.1", features = ["sync"] }', ) os.chdir("../") From da5bf8fb5aa4e7d5c84fff7031ac6c1e8c05373f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 11 Jun 2024 23:00:24 +0900 Subject: [PATCH 066/128] Upgrade `tokio_with_wasm` to 0.5.3 --- automate/__main__.py | 44 +++++-------------- .../example/native/hub/Cargo.toml | 8 ++-- .../example/native/hub/src/lib.rs | 6 +-- .../native/hub/src/sample_functions.rs | 10 ++++- .../template/native/hub/Cargo.toml | 3 +- .../template/native/hub/src/lib.rs | 7 +-- 6 files changed, 29 insertions(+), 49 deletions(-) diff --git a/automate/__main__.py b/automate/__main__.py index ad99b6966..08901ecda 100644 --- a/automate/__main__.py +++ b/automate/__main__.py @@ -50,34 +50,24 @@ def replace_text_in_file(filepath: str, change_from: str, change_to: str): # Enable the web target, since it's not enabled by default. replace_text_in_file( "native/hub/src/lib.rs", - '// #[cfg(not(target_family = "wasm"))]', - '#[cfg(not(target_family = "wasm"))]', + "use tokio;", + "// use tokio;", ) replace_text_in_file( "native/hub/src/lib.rs", - '// #[cfg(target_family = "wasm")]', - '#[cfg(target_family = "wasm")]', - ) - replace_text_in_file( - "native/hub/src/lib.rs", - "// use tokio_with_wasm as tokio;", - "use tokio_with_wasm as tokio;", + "// use tokio_with_wasm::alias as tokio;", + "use tokio_with_wasm::alias as tokio;", ) replace_text_in_file( "native/hub/Cargo.toml", - "# [target.'cfg(target_family = \"wasm\")'.dependencies]", - "[target.'cfg(target_family = \"wasm\")'.dependencies]", + '# tokio_with_wasm = { version = "0.5.3", features = ["sync"] }', + 'tokio_with_wasm = { version = "0.5.3", features = ["sync"] }', ) replace_text_in_file( "native/hub/Cargo.toml", '# wasm-bindgen = "0.2.92"', 'wasm-bindgen = "0.2.92"', ) - replace_text_in_file( - "native/hub/Cargo.toml", - '# tokio_with_wasm = { version = "0.5.1", features = ["sync"] }', - 'tokio_with_wasm = { version = "0.5.1", features = ["sync"] }', - ) os.chdir("../") @@ -114,34 +104,24 @@ def replace_text_in_file(filepath: str, change_from: str, change_to: str): # Enable the web target, since it's not enabled by default. replace_text_in_file( "native/hub/src/lib.rs", - '// #[cfg(not(target_family = "wasm"))]', - '#[cfg(not(target_family = "wasm"))]', + "use tokio;", + "// use tokio;", ) replace_text_in_file( "native/hub/src/lib.rs", - '// #[cfg(target_family = "wasm")]', - '#[cfg(target_family = "wasm")]', - ) - replace_text_in_file( - "native/hub/src/lib.rs", - "// use tokio_with_wasm as tokio;", - "use tokio_with_wasm as tokio;", + "// use tokio_with_wasm::alias as tokio;", + "use tokio_with_wasm::alias as tokio;", ) replace_text_in_file( "native/hub/Cargo.toml", - "# [target.'cfg(target_family = \"wasm\")'.dependencies]", - "[target.'cfg(target_family = \"wasm\")'.dependencies]", + '# tokio_with_wasm = { version = "0.5.3", features = ["sync"] }', + 'tokio_with_wasm = { version = "0.5.3", features = ["sync"] }', ) replace_text_in_file( "native/hub/Cargo.toml", '# wasm-bindgen = "0.2.92"', 'wasm-bindgen = "0.2.92"', ) - replace_text_in_file( - "native/hub/Cargo.toml", - '# tokio_with_wasm = { version = "0.5.1", features = ["sync"] }', - 'tokio_with_wasm = { version = "0.5.1", features = ["sync"] }', - ) os.chdir("../") diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index c5828b869..f3d5ea843 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -15,13 +15,11 @@ crate-type = ["lib", "cdylib", "staticlib"] rinf = "6.12.1" prost = "0.12.6" tokio = { version = "1", features = ["rt", "sync", "macros", "time"] } -sample_crate = { path = "../sample_crate" } - -[target.'cfg(target_family = "wasm")'.dependencies] -wasm-bindgen = "0.2.92" -tokio_with_wasm = { version = "0.5.1", features = [ +tokio_with_wasm = { version = "0.5.3", features = [ "rt", "sync", "macros", "time", ] } +wasm-bindgen = "0.2.92" +sample_crate = { path = "../sample_crate" } diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs index 1cbfda2dd..d5a610202 100755 --- a/flutter_ffi_plugin/example/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs @@ -4,10 +4,8 @@ mod messages; mod sample_functions; -#[cfg(not(target_family = "wasm"))] -use tokio; -#[cfg(target_family = "wasm")] -use tokio_with_wasm as tokio; +// use tokio; +use tokio_with_wasm::alias as tokio; rinf::write_interface!(); diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index 03b31f61c..2205bb4bb 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -209,5 +209,13 @@ pub async fn run_debug_tests() { } debug_print!("Debug tests completed!"); - panic!("INTENTIONAL DEBUG PANIC"); + + tokio::spawn(async { + // Panic in a separate task + // to avoid memory leak on the web. + // On the web (`wasm32-unknown-unknown`), + // catching and unwinding panics is not possible. + // It is better to avoid panicking code at all costs on the web. + panic!("INTENTIONAL DEBUG PANIC"); + }); } diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index 6e1614cb9..dd4842216 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -17,6 +17,5 @@ prost = "0.12.6" tokio = { version = "1", features = ["sync"] } # Uncomment below to target the web. -# [target.'cfg(target_family = "wasm")'.dependencies] +# tokio_with_wasm = { version = "0.5.3", features = ["sync"] } # wasm-bindgen = "0.2.92" -# tokio_with_wasm = { version = "0.5.1", features = ["sync"] } diff --git a/flutter_ffi_plugin/template/native/hub/src/lib.rs b/flutter_ffi_plugin/template/native/hub/src/lib.rs index 5c84058cf..9c2519f42 100644 --- a/flutter_ffi_plugin/template/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/template/native/hub/src/lib.rs @@ -3,11 +3,8 @@ mod messages; -// Uncomment below to target the web. -// #[cfg(not(target_family = "wasm"))] -use tokio; -// #[cfg(target_family = "wasm")] -// use tokio_with_wasm as tokio; +use tokio; // Comment this line to target the web. +// use tokio_with_wasm::alias as tokio; // Uncomment this line to target the web. rinf::write_interface!(); From 91d410dd48737337aacbdbbde58fc61ae85b8f3e Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 11 Jun 2024 23:15:01 +0900 Subject: [PATCH 067/128] Simplify automation script --- automate/__main__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/automate/__main__.py b/automate/__main__.py index 08901ecda..d444894d9 100644 --- a/automate/__main__.py +++ b/automate/__main__.py @@ -60,13 +60,13 @@ def replace_text_in_file(filepath: str, change_from: str, change_to: str): ) replace_text_in_file( "native/hub/Cargo.toml", - '# tokio_with_wasm = { version = "0.5.3", features = ["sync"] }', - 'tokio_with_wasm = { version = "0.5.3", features = ["sync"] }', + "# tokio_with_wasm", + "tokio_with_wasm", ) replace_text_in_file( "native/hub/Cargo.toml", - '# wasm-bindgen = "0.2.92"', - 'wasm-bindgen = "0.2.92"', + "# wasm-bindgen", + "wasm-bindgen", ) os.chdir("../") @@ -114,13 +114,13 @@ def replace_text_in_file(filepath: str, change_from: str, change_to: str): ) replace_text_in_file( "native/hub/Cargo.toml", - '# tokio_with_wasm = { version = "0.5.3", features = ["sync"] }', - 'tokio_with_wasm = { version = "0.5.3", features = ["sync"] }', + "# tokio_with_wasm", + "tokio_with_wasm", ) replace_text_in_file( "native/hub/Cargo.toml", - '# wasm-bindgen = "0.2.92"', - 'wasm-bindgen = "0.2.92"', + "# wasm-bindgen", + "wasm-bindgen", ) os.chdir("../") From 402d0101e48bc962e9b5929e08742ae6eda26de9 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Wed, 12 Jun 2024 00:10:39 +0900 Subject: [PATCH 068/128] Make Rinf commands work offline --- flutter_ffi_plugin/bin/rinf.dart | 2 + flutter_ffi_plugin/bin/src/helpers.dart | 70 ++++++++++++++++-------- flutter_ffi_plugin/bin/src/internet.dart | 7 +++ flutter_ffi_plugin/bin/src/message.dart | 65 +++++++++++++--------- flutter_ffi_plugin/pubspec.yaml | 1 + rust_crate/src/main.rs | 2 +- 6 files changed, 96 insertions(+), 51 deletions(-) create mode 100644 flutter_ffi_plugin/bin/src/internet.dart diff --git a/flutter_ffi_plugin/bin/rinf.dart b/flutter_ffi_plugin/bin/rinf.dart index 458321b77..8db92fa57 100755 --- a/flutter_ffi_plugin/bin/rinf.dart +++ b/flutter_ffi_plugin/bin/rinf.dart @@ -1,6 +1,7 @@ import 'src/config.dart'; import 'src/helpers.dart'; import 'src/message.dart'; +import 'src/internet.dart'; Future main(List args) async { if (args.isEmpty) { @@ -10,6 +11,7 @@ Future main(List args) async { } final rinfConfig = await loadVerifiedRinfConfig("pubspec.yaml"); + await checkConnectivity(); switch (args[0]) { case "config": diff --git a/flutter_ffi_plugin/bin/src/helpers.dart b/flutter_ffi_plugin/bin/src/helpers.dart index ece9703e8..a52d67ece 100644 --- a/flutter_ffi_plugin/bin/src/helpers.dart +++ b/flutter_ffi_plugin/bin/src/helpers.dart @@ -4,6 +4,7 @@ import 'package:yaml/yaml.dart'; import 'config.dart'; import 'message.dart'; import 'common.dart'; +import 'internet.dart'; /// Creates new folders and files to an existing Flutter project folder. Future applyRustTemplate({ @@ -197,31 +198,52 @@ Future copyDirectory(Uri source, Uri destination) async { } Future buildWebassembly({bool isReleaseMode = false}) async { - // Verify Rust toolchain. - print("Verifying Rust toolchain for the web." + - "\nThis might take a while if there are new updates."); - await Process.run("rustup", ["toolchain", "install", "nightly"]); - await Process.run("rustup", [ - "+nightly", - "component", - "add", - "rust-src", - ]); - await Process.run("rustup", [ - "+nightly", - "target", - "add", - "wasm32-unknown-unknown", - ]); // For actual compilation - await Process.run("rustup", [ - "target", - "add", - "wasm32-unknown-unknown", - ]); // For Rust-analyzer - await Process.run("cargo", ["install", "wasm-pack"]); - await Process.run("cargo", ["install", "wasm-bindgen-cli"]); + // Ensure Rust toolchain. + if (isInternetConnected) { + print("Ensuring Rust toolchain for the web." + + "\nThis is done by installing it globally on the system."); + final processResults = []; + processResults.add(await Process.run("rustup", [ + "toolchain", + "install", + "nightly", + ])); + processResults.add(await Process.run("rustup", [ + "+nightly", + "component", + "add", + "rust-src", + ])); + processResults.add(await Process.run("rustup", [ + "+nightly", + "target", + "add", + "wasm32-unknown-unknown", + ])); // For actual compilation + processResults.add(await Process.run("rustup", [ + "target", + "add", + "wasm32-unknown-unknown", + ])); // For Rust-analyzer + processResults.add(await Process.run("cargo", [ + "install", + "wasm-pack", + ])); + processResults.add(await Process.run("cargo", [ + "install", + "wasm-bindgen-cli", + ])); + processResults.forEach((processResult) { + if (processResult.exitCode != 0) { + print(processResult.stderr.toString().trim()); + throw Exception('Cannot globally install Rust toolchain for the web.'); + } + }); + } else { + print("Skipping ensurement of Rust toolchain for the web."); + } - // Verify Flutter SDK web server's response headers. + // Patch Flutter SDK web server's response headers. try { await patchServerHeaders(); print("Patched Flutter SDK's web server with CORS HTTP headers."); diff --git a/flutter_ffi_plugin/bin/src/internet.dart b/flutter_ffi_plugin/bin/src/internet.dart new file mode 100644 index 000000000..02d8eef6c --- /dev/null +++ b/flutter_ffi_plugin/bin/src/internet.dart @@ -0,0 +1,7 @@ +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +var isInternetConnected = false; + +Future checkConnectivity() async { + isInternetConnected = await InternetConnectionChecker().hasConnection; +} diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 60e3df3ce..04e4e98ff 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -3,6 +3,7 @@ import 'package:path/path.dart'; import 'package:watcher/watcher.dart'; import 'config.dart'; import 'common.dart'; +import 'internet.dart'; enum MarkType { dartSignal, @@ -46,7 +47,7 @@ Future generateMessageCode({ resourcesInFolders, ); - // Verify `package` statement in `.proto` files. + // Include `package` statement in `.proto` files. // Package name should be the same as the filename // because Rust filenames are written with package name // and Dart filenames are written with the `.proto` filename. @@ -76,18 +77,24 @@ Future generateMessageCode({ } // Generate Rust message files. - if (!silent) { - print("Verifying `protoc-gen-prost` for Rust." + - "\nThis might take a while if there are new updates."); - } - final cargoInstallCommand = await Process.run('cargo', [ - 'install', - 'protoc-gen-prost', - ...(messageConfig.rustSerde ? ['protoc-gen-prost-serde'] : []) - ]); - if (cargoInstallCommand.exitCode != 0) { - print(cargoInstallCommand.stderr.toString().trim()); - throw Exception('Cannot globally install `protoc-gen-prost` Rust crate'); + if (isInternetConnected) { + if (!silent) { + print("Ensuring `protoc-gen-prost` for Rust." + + "\nThis is done by installing it globally on the system."); + } + final cargoInstallCommand = await Process.run('cargo', [ + 'install', + 'protoc-gen-prost', + ...(messageConfig.rustSerde ? ['protoc-gen-prost-serde'] : []) + ]); + if (cargoInstallCommand.exitCode != 0) { + print(cargoInstallCommand.stderr.toString().trim()); + throw Exception('Cannot globally install `protoc-gen-prost` Rust crate'); + } + } else { + if (!silent) { + print("Skipping ensurement of `protoc-gen-prost` for Rust."); + } } for (final entry in resourcesInFolders.entries) { final subPath = entry.key; @@ -164,19 +171,25 @@ Future generateMessageCode({ } // Generate Dart message files. - if (!silent) { - print("Verifying `protoc_plugin` for Dart." + - "\nThis might take a while if there are new updates."); - } - final pubGlobalActivateCommand = await Process.run('dart', [ - 'pub', - 'global', - 'activate', - 'protoc_plugin', - ]); - if (pubGlobalActivateCommand.exitCode != 0) { - print(pubGlobalActivateCommand.stderr.toString().trim()); - throw Exception('Cannot globally install `protoc_plugin` Dart package'); + if (isInternetConnected) { + if (!silent) { + print("Ensuring `protoc_plugin` for Dart." + + "\nThis is done by installing it globally on the system."); + } + final pubGlobalActivateCommand = await Process.run('dart', [ + 'pub', + 'global', + 'activate', + 'protoc_plugin', + ]); + if (pubGlobalActivateCommand.exitCode != 0) { + print(pubGlobalActivateCommand.stderr.toString().trim()); + throw Exception('Cannot globally install `protoc_plugin` Dart package'); + } + } else { + if (!silent) { + print("Skipping ensurement of `protoc_plugin` for Dart."); + } } for (final entry in resourcesInFolders.entries) { final subPath = entry.key; diff --git a/flutter_ffi_plugin/pubspec.yaml b/flutter_ffi_plugin/pubspec.yaml index a3d989aa8..94b9c5ba3 100644 --- a/flutter_ffi_plugin/pubspec.yaml +++ b/flutter_ffi_plugin/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: watcher: ^1.1.0 ffi: ^2.1.0 yaml: ^3.1.2 + internet_connection_checker: ^1.0.0 dev_dependencies: lints: ">=3.0.0 <5.0.0" diff --git a/rust_crate/src/main.rs b/rust_crate/src/main.rs index 3d810512a..b6b615b7b 100644 --- a/rust_crate/src/main.rs +++ b/rust_crate/src/main.rs @@ -8,7 +8,7 @@ fn main() -> Result<()> { use std::path; use std::process; - // Verify Protobuf compiler. + // Ensure Protobuf compiler. let protoc_path = if let Ok(installed) = which::which("protoc") { // Get the path of Protobuf compiler that's already installed. println!("Detected `protoc`, skipping auto installation."); From 992940150ca2db7cd0faf3089c3e73bc0a23bb27 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Wed, 12 Jun 2024 00:42:15 +0900 Subject: [PATCH 069/128] Make message ID `i32` --- flutter_ffi_plugin/lib/src/interface_os.dart | 29 ++++++-------------- rust_crate/src/macros.rs | 2 +- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/flutter_ffi_plugin/lib/src/interface_os.dart b/flutter_ffi_plugin/lib/src/interface_os.dart index 781b19291..81610d161 100644 --- a/flutter_ffi_plugin/lib/src/interface_os.dart +++ b/flutter_ffi_plugin/lib/src/interface_os.dart @@ -77,20 +77,10 @@ Future sendDartSignalReal( binaryMemory.asTypedList(binary.length).setAll(0, binary); final rustFunction = rustLibrary.lookupFunction< - Void Function( - IntPtr, - Pointer, - IntPtr, - Pointer, - IntPtr, - ), - void Function( - int, - Pointer, - int, - Pointer, - int, - )>('send_dart_signal_extern'); + Void Function(Int32, Pointer, UintPtr, Pointer, UintPtr), + void Function(int, Pointer, int, Pointer, int)>( + 'send_dart_signal_extern', + ); rustFunction( messageId, @@ -105,12 +95,9 @@ Future sendDartSignalReal( } void prepareIsolateReal(int port) { - final rustFunction = rustLibrary.lookupFunction< - Void Function( - IntPtr, - ), - void Function( - int, - )>('prepare_isolate_extern'); + final rustFunction = + rustLibrary.lookupFunction( + 'prepare_isolate_extern', + ); rustFunction(port); } diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 5042f8bf2..1c15cb8a5 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -26,7 +26,7 @@ macro_rules! write_interface { #[cfg(not(target_family = "wasm"))] #[no_mangle] pub unsafe extern "C" fn send_dart_signal_extern( - message_id: i64, + message_id: i32, message_pointer: *const u8, message_size: usize, binary_pointer: *const u8, From da221ac71914134d46594095b78c19c67288badc Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Wed, 12 Jun 2024 00:43:09 +0900 Subject: [PATCH 070/128] Upgrade `allo-isolate` --- rust_crate/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index db8c2f9c2..525845784 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -14,7 +14,7 @@ backtrace = "0.3.69" protoc-prebuilt = "0.3.0" home = "0.5.9" which = "6.0.0" -allo-isolate = "0.1.24" +allo-isolate = "0.1.25" tokio = { version = "1", features = ["rt-multi-thread"] } [target.'cfg(target_family = "wasm")'.dependencies] From c6d4d9f90bc4ba42f23539d2f479058d0c301e21 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Wed, 12 Jun 2024 00:49:03 +0900 Subject: [PATCH 071/128] Remove unneeded cast --- rust_crate/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 1c15cb8a5..95e7739eb 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -36,7 +36,7 @@ macro_rules! write_interface { unsafe { std::slice::from_raw_parts(message_pointer, message_size).to_vec() }; let binary = unsafe { std::slice::from_raw_parts(binary_pointer, binary_size).to_vec() }; - messages::generated::handle_dart_signal(message_id as i32, message_bytes, binary); + messages::generated::handle_dart_signal(message_id, message_bytes, binary); } #[cfg(target_family = "wasm")] From 17a1c7cf809224e25d7fde5682360d247cdb50a5 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Fri, 14 Jun 2024 23:43:08 +0900 Subject: [PATCH 072/128] Separate single-threaded start function --- .../example/native/hub/src/sample_functions.rs | 1 + rust_crate/src/interface.rs | 16 ++++++++++++++-- rust_crate/src/interface_web.rs | 2 +- rust_crate/src/macros.rs | 4 ++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index 2205bb4bb..ff56cf849 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -208,6 +208,7 @@ pub async fn run_debug_tests() { } } + tokio::time::sleep(std::time::Duration::from_secs(2)).await; debug_print!("Debug tests completed!"); tokio::spawn(async { diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index c839bd326..e8aa8afd0 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -19,14 +19,26 @@ pub struct DartSignal { pub binary: Vec, } -/// Runs the main function in Rust. -pub fn start_rust_logic(main_future: F) -> Result<()> +/// Runs the async main function in Rust. +/// This spawns the function in a multi-threaded runtime. +#[cfg(not(target_family = "wasm"))] +pub fn start_rust_logic_mt(main_future: F) -> Result<()> where F: Future + Send + 'static, { start_rust_logic_real(main_future) } +/// Runs the async main function in Rust. +/// This spawns the function in a single-threaded runtime. +#[cfg(target_family = "wasm")] +pub fn start_rust_logic_st(main_future: F) -> Result<()> +where + F: Future + 'static, +{ + start_rust_logic_real(main_future) +} + /// Send a signal to Dart. pub fn send_rust_signal(message_id: i32, message_bytes: Vec, binary: Vec) { let result = send_rust_signal_real(message_id, message_bytes, binary); diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index 313458314..9bb6e0f92 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -6,7 +6,7 @@ use wasm_bindgen_futures::spawn_local; pub fn start_rust_logic_real(main_future: F) -> Result<()> where - F: Future + Send + 'static, + F: Future + 'static, { // Add kind description for panics. #[cfg(debug_assertions)] diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 95e7739eb..31b80ee7b 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -8,7 +8,7 @@ macro_rules! write_interface { #[cfg(not(target_family = "wasm"))] #[no_mangle] pub extern "C" fn start_rust_logic_extern() { - let result = $crate::start_rust_logic(main()); + let result = $crate::start_rust_logic_mt(main()); if let Err(error) = result { println!("Could not start Rust logic.\n{error:#?}"); } @@ -17,7 +17,7 @@ macro_rules! write_interface { #[cfg(target_family = "wasm")] #[wasm_bindgen::prelude::wasm_bindgen] pub fn start_rust_logic_extern() { - let result = $crate::start_rust_logic(main()); + let result = $crate::start_rust_logic_st(main()); if let Err(error) = result { println!("Could not start Rust logic.\n{error:#?}"); } From 01652f10d7aec631ebfa09ed983c16ca880356e3 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 15 Jun 2024 08:46:47 +0900 Subject: [PATCH 073/128] Remove unused code --- flutter_ffi_plugin/example/native/hub/src/sample_functions.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index ff56cf849..2205bb4bb 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -208,7 +208,6 @@ pub async fn run_debug_tests() { } } - tokio::time::sleep(std::time::Duration::from_secs(2)).await; debug_print!("Debug tests completed!"); tokio::spawn(async { From cad245a7abf76d2e35ecb3bce5fdef42666d81a3 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 15 Jun 2024 10:31:15 +0900 Subject: [PATCH 074/128] Upgrade `tokio_with_wasm` --- flutter_ffi_plugin/example/native/hub/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index f3d5ea843..ae98af917 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -15,7 +15,7 @@ crate-type = ["lib", "cdylib", "staticlib"] rinf = "6.12.1" prost = "0.12.6" tokio = { version = "1", features = ["rt", "sync", "macros", "time"] } -tokio_with_wasm = { version = "0.5.3", features = [ +tokio_with_wasm = { version = "0.6.0", features = [ "rt", "sync", "macros", From 1d3f846e9c6ded686d168519373403a883e100d0 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 15 Jun 2024 10:43:05 +0900 Subject: [PATCH 075/128] Update template --- flutter_ffi_plugin/template/native/hub/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index dd4842216..13b0ebd57 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -17,5 +17,5 @@ prost = "0.12.6" tokio = { version = "1", features = ["sync"] } # Uncomment below to target the web. -# tokio_with_wasm = { version = "0.5.3", features = ["sync"] } +# tokio_with_wasm = { version = "0.6.0", features = ["sync"] } # wasm-bindgen = "0.2.92" From fe8194b6840ab4d98b7a076ae1476295602b068f Mon Sep 17 00:00:00 2001 From: temeddix Date: Sat, 15 Jun 2024 18:42:03 +0900 Subject: [PATCH 076/128] Match the name of the start Rust function --- rust_crate/src/interface.rs | 13 +++++++++---- rust_crate/src/macros.rs | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index e8aa8afd0..880cf91e6 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -20,9 +20,13 @@ pub struct DartSignal { } /// Runs the async main function in Rust. -/// This spawns the function in a multi-threaded runtime. +/// On native platforms, futures usually implement the `Send` trait +/// to be safely sent between threads. +/// Even in a single-threaded (current-thread) runtime, +/// the `Runtime` object itself might be moved between threads, +/// along with all the tasks it manages. #[cfg(not(target_family = "wasm"))] -pub fn start_rust_logic_mt(main_future: F) -> Result<()> +pub fn start_rust_logic(main_future: F) -> Result<()> where F: Future + Send + 'static, { @@ -30,9 +34,10 @@ where } /// Runs the async main function in Rust. -/// This spawns the function in a single-threaded runtime. +/// On the web, futures usually don't implement the `Send` trait +/// because JavaScript environment is fundamentally single-threaded. #[cfg(target_family = "wasm")] -pub fn start_rust_logic_st(main_future: F) -> Result<()> +pub fn start_rust_logic(main_future: F) -> Result<()> where F: Future + 'static, { diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 31b80ee7b..95e7739eb 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -8,7 +8,7 @@ macro_rules! write_interface { #[cfg(not(target_family = "wasm"))] #[no_mangle] pub extern "C" fn start_rust_logic_extern() { - let result = $crate::start_rust_logic_mt(main()); + let result = $crate::start_rust_logic(main()); if let Err(error) = result { println!("Could not start Rust logic.\n{error:#?}"); } @@ -17,7 +17,7 @@ macro_rules! write_interface { #[cfg(target_family = "wasm")] #[wasm_bindgen::prelude::wasm_bindgen] pub fn start_rust_logic_extern() { - let result = $crate::start_rust_logic_st(main()); + let result = $crate::start_rust_logic(main()); if let Err(error) = result { println!("Could not start Rust logic.\n{error:#?}"); } From 145d3b5d23df74b4bb57acf54df8b8a43d6a6af8 Mon Sep 17 00:00:00 2001 From: temeddix Date: Sat, 15 Jun 2024 20:09:57 +0900 Subject: [PATCH 077/128] Upgrade `tokio_with_wasm` --- flutter_ffi_plugin/example/native/hub/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml index ae98af917..77b69f15d 100755 --- a/flutter_ffi_plugin/example/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml @@ -15,7 +15,7 @@ crate-type = ["lib", "cdylib", "staticlib"] rinf = "6.12.1" prost = "0.12.6" tokio = { version = "1", features = ["rt", "sync", "macros", "time"] } -tokio_with_wasm = { version = "0.6.0", features = [ +tokio_with_wasm = { version = "0.6.1", features = [ "rt", "sync", "macros", From 9a7cc71351c5ad272857a7898e4469454d005b83 Mon Sep 17 00:00:00 2001 From: temeddix Date: Sat, 15 Jun 2024 20:20:55 +0900 Subject: [PATCH 078/128] First crate feature `multi-worker` --- rust_crate/Cargo.toml | 3 +++ rust_crate/src/interface_os.rs | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index 525845784..b03aef31a 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -8,6 +8,9 @@ repository = "https://github.com/cunarist/rinf" documentation = "https://rinf.cunarist.com" rust-version = "1.70" +[features] +multi-worker = [] + [target.'cfg(not(target_family = "wasm"))'.dependencies] os-thread-local = "0.1.3" backtrace = "0.3.69" diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index cf1f13401..047e49eb7 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -42,8 +42,16 @@ where })); } - // Run the main function. + // Build the tokio runtime. + #[cfg(not(feature = "multi-worker"))] + let tokio_runtime = Builder::new_multi_thread() + .worker_threads(1) + .enable_all() + .build()?; + #[cfg(feature = "multi-worker")] let tokio_runtime = Builder::new_multi_thread().enable_all().build()?; + + // Run the main function. tokio_runtime.spawn(main_future); TOKIO_RUNTIME .get_or_init(|| ThreadLocal::new(|| RefCell::new(None))) From d4fde7b80ac3604ab5f817066baf02cd455066d2 Mon Sep 17 00:00:00 2001 From: temeddix Date: Sat, 15 Jun 2024 20:23:10 +0900 Subject: [PATCH 079/128] Update FAQ docs --- documentation/docs/frequently-asked-questions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/frequently-asked-questions.md b/documentation/docs/frequently-asked-questions.md index b5848f184..fd10391e0 100644 --- a/documentation/docs/frequently-asked-questions.md +++ b/documentation/docs/frequently-asked-questions.md @@ -44,7 +44,7 @@ android { ### How does concurrency work under the hood? -On native platforms, Dart runs in a single thread as usual, while Rust utilizes the async `tokio` runtime to take advantage of all cores on the computer, allowing async tasks to run efficiently within that runtime. +On native platforms, Dart runs in the main thread, while Rust utilizes the async `tokio` runtime, allowing async tasks to run efficiently within a separate thread. On the web, Dart and Rust both run inside JavaScript's async event loop in the main thread, with Rust `Future`s being converted into JavaScript `Promise`s internally. This is a necessary constraint because [webassembly component proposal](https://github.com/WebAssembly/proposals) is not stabilized as of February 2024. From 7226d0d55c1ec8cb432ff6e742c1b408b565b671 Mon Sep 17 00:00:00 2001 From: temeddix Date: Sat, 15 Jun 2024 20:39:38 +0900 Subject: [PATCH 080/128] Add configuration guides --- documentation/docs/configuration.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/documentation/docs/configuration.md b/documentation/docs/configuration.md index 9ed7b4332..e534da96c 100644 --- a/documentation/docs/configuration.md +++ b/documentation/docs/configuration.md @@ -1,6 +1,8 @@ # Configuration -You can customize some Rinf behaviors by configuring the `pubspec.yaml` file. Rinf will change its behaviors by reading the fields below. All fields are optional and it's not necessary to write them. +## 📋 YAML File + +You can customize the behavior of Rinf CLI commands by configuring the `pubspec.yaml` file. All fields are optional and it's not necessary to write them. ```yaml title="pubspec.yaml" rinf: @@ -16,3 +18,11 @@ You can check the current configuration status by running the command below in t ```bash title="CLI" rinf config ``` + +## 📦 Crate Features + +```toml title="native/hub/Cargo.toml" +rinf = { version = "0.0.0", features = ["feature-name"] } +``` + +- `multi-worker`: Starts a worker thread for each CPU core available on the system within the `tokio` runtime. By default, the `tokio` runtime uses only one thread. Enabling this feature allows the `tokio` runtime to utilize all the cores on your computer. This feature does not affect applications on the web platform. From 4cba370a592894f7094bac3949969a1dd7ee15ce Mon Sep 17 00:00:00 2001 From: temeddix Date: Sat, 15 Jun 2024 20:49:20 +0900 Subject: [PATCH 081/128] Ease the return type of the main Rust function --- rust_crate/src/interface.rs | 4 ++-- rust_crate/src/interface_os.rs | 6 ++++-- rust_crate/src/interface_web.rs | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index 880cf91e6..0b1d8fcba 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -28,7 +28,7 @@ pub struct DartSignal { #[cfg(not(target_family = "wasm"))] pub fn start_rust_logic(main_future: F) -> Result<()> where - F: Future + Send + 'static, + F: Future + Send + 'static, { start_rust_logic_real(main_future) } @@ -39,7 +39,7 @@ where #[cfg(target_family = "wasm")] pub fn start_rust_logic(main_future: F) -> Result<()> where - F: Future + 'static, + F: Future + 'static, { start_rust_logic_real(main_future) } diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 047e49eb7..11851af73 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -31,7 +31,7 @@ static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); pub fn start_rust_logic_real(main_future: F) -> Result<()> where - F: Future + Send + 'static, + F: Future + Send + 'static, { // Enable backtrace output for panics. #[cfg(debug_assertions)] @@ -52,7 +52,9 @@ where let tokio_runtime = Builder::new_multi_thread().enable_all().build()?; // Run the main function. - tokio_runtime.spawn(main_future); + tokio_runtime.spawn(async { + main_future.await; + }); TOKIO_RUNTIME .get_or_init(|| ThreadLocal::new(|| RefCell::new(None))) .with(move |cell| { diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index 9bb6e0f92..e8cc4330b 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -6,7 +6,7 @@ use wasm_bindgen_futures::spawn_local; pub fn start_rust_logic_real(main_future: F) -> Result<()> where - F: Future + 'static, + F: Future + 'static, { // Add kind description for panics. #[cfg(debug_assertions)] @@ -17,7 +17,9 @@ where } // Run the main function. - spawn_local(main_future); + spawn_local(async { + main_future.await; + }); Ok(()) } From 3ea5bf5b0a09d40309e39e54f4f6dd2db3af4b45 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 15:32:57 +0900 Subject: [PATCH 082/128] Use the true current-thread tokio runtime by default --- rust_crate/Cargo.toml | 4 +- rust_crate/src/interface_os.rs | 120 ++++++++++++++++++++++++++------- 2 files changed, 99 insertions(+), 25 deletions(-) diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index b03aef31a..520a0f49b 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -9,7 +9,7 @@ documentation = "https://rinf.cunarist.com" rust-version = "1.70" [features] -multi-worker = [] +multi-worker = ["tokio/rt-multi-thread"] [target.'cfg(not(target_family = "wasm"))'.dependencies] os-thread-local = "0.1.3" @@ -18,7 +18,7 @@ protoc-prebuilt = "0.3.0" home = "0.5.9" which = "6.0.0" allo-isolate = "0.1.25" -tokio = { version = "1", features = ["rt-multi-thread"] } +tokio = { version = "1", features = ["rt"] } [target.'cfg(target_family = "wasm")'.dependencies] js-sys = "0.3.69" diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 11851af73..c5818968e 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -3,8 +3,12 @@ use allo_isolate::{IntoDart, Isolate, ZeroCopyBuffer}; use os_thread_local::ThreadLocal; use std::cell::RefCell; use std::future::Future; -use std::sync::{Mutex, OnceLock}; -use tokio::runtime::{Builder, Runtime}; +use std::pin::Pin; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex, OnceLock}; +use std::task::{Context, Poll, Waker}; +use std::thread; +use tokio::runtime::Builder; static DART_ISOLATE: Mutex> = Mutex::new(None); @@ -23,11 +27,12 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { // We use `os_thread_local` so that when the program fails // and the main thread exits unexpectedly, -// the whole async tokio runtime can disappear as well. +// the whole async tokio runtime can shut down as well +// by receiving a signal via the shutdown channel. // Without this solution, zombie threads inside the tokio runtime // might outlive the app. -type TokioRuntime = OnceLock>>>; -static TOKIO_RUNTIME: TokioRuntime = OnceLock::new(); +type ShutdownSenderLock = OnceLock>>>; +static SHUTDOWN_SENDER: ShutdownSenderLock = OnceLock::new(); pub fn start_rust_logic_real(main_future: F) -> Result<()> where @@ -42,28 +47,49 @@ where })); } + // Prepare the channel that will notify tokio runtime to shutdown + // after the main Dart thread has gone. + let (shutdown_sender, shutdown_receiver) = shutdown_channel(); + let shutdown_sender_lock = + SHUTDOWN_SENDER.get_or_init(move || ThreadLocal::new(|| RefCell::new(None))); + shutdown_sender_lock.with(|cell| cell.replace(Some(shutdown_sender))); + // Build the tokio runtime. #[cfg(not(feature = "multi-worker"))] - let tokio_runtime = Builder::new_multi_thread() - .worker_threads(1) - .enable_all() - .build()?; + { + let tokio_runtime = Builder::new_current_thread().enable_all().build()?; + thread::spawn(move || { + tokio_runtime.spawn(async { + main_future.await; + }); + tokio_runtime.block_on(shutdown_receiver); + // Dropping the tokio runtime makes it shut down. + drop(tokio_runtime); + }); + } #[cfg(feature = "multi-worker")] - let tokio_runtime = Builder::new_multi_thread().enable_all().build()?; - - // Run the main function. - tokio_runtime.spawn(async { - main_future.await; - }); - TOKIO_RUNTIME - .get_or_init(|| ThreadLocal::new(|| RefCell::new(None))) - .with(move |cell| { - // If there was already a tokio runtime previously, - // most likely due to Dart's hot restart, - // its tasks as well as itself will be terminated, - // being replaced with the new one. - cell.replace(Some(tokio_runtime)); + { + static TOKIO_RUNTIME: Mutex> = Mutex::new(None); + let tokio_runtime = Builder::new_multi_thread().enable_all().build()?; + tokio_runtime.spawn(async { + main_future.await; + }); + tokio_runtime.spawn(async { + shutdown_receiver.await; + thread::spawn(|| { + if let Ok(mut guard) = TOKIO_RUNTIME.lock() { + let runtime_option = guard.take(); + if let Some(runtime) = runtime_option { + // Dropping the tokio runtime makes it shut down. + drop(runtime); + } + } + }) }); + if let Ok(mut guard) = TOKIO_RUNTIME.lock() { + guard.replace(tokio_runtime); + } + } Ok(()) } @@ -105,3 +131,51 @@ pub fn send_rust_signal_real( Ok(()) } + +struct ShutdownSender { + is_sent: Arc, + waker: Arc>>, +} + +impl Drop for ShutdownSender { + fn drop(&mut self) { + self.is_sent.store(true, Ordering::SeqCst); + if let Ok(mut guard) = self.waker.lock() { + if let Some(waker) = guard.take() { + waker.wake(); + } + } + } +} + +struct ShutdownReceiver { + is_sent: Arc, + waker: Arc>>, +} + +impl Future for ShutdownReceiver { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.is_sent.load(Ordering::SeqCst) { + Poll::Ready(()) + } else { + if let Ok(mut guard) = self.waker.lock() { + guard.replace(cx.waker().clone()); + } + Poll::Pending + } + } +} + +fn shutdown_channel() -> (ShutdownSender, ShutdownReceiver) { + let is_sent = Arc::new(AtomicBool::new(false)); + let waker = Arc::new(Mutex::new(None)); + + let sender = ShutdownSender { + is_sent: Arc::clone(&is_sent), + waker: Arc::clone(&waker), + }; + let receiver = ShutdownReceiver { is_sent, waker }; + + (sender, receiver) +} From 24e8e2244b39abffe4df9ac650dcd1b8975326dd Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 15:47:02 +0900 Subject: [PATCH 083/128] Reduce memory copy on Dart signal --- flutter_ffi_plugin/bin/src/message.dart | 10 +++++----- rust_crate/src/macros.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 04e4e98ff..e99fcfd30 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -418,20 +418,20 @@ use std::sync::OnceLock; use tokio::sync::mpsc::unbounded_channel; type SignalHandlers = OnceLock< - HashMap, Vec) + HashMap) -> Result<(), Box> + Send + Sync>>, >; static SIGNAL_HANDLERS: SignalHandlers = OnceLock::new(); pub fn handle_dart_signal( message_id: i32, - message_bytes: Vec, + message_bytes: &[u8], binary: Vec ) { let hash_map = SIGNAL_HANDLERS.get_or_init(|| { let mut new_hash_map = HashMap::< i32, - Box, Vec) + Box) -> Result<(), Box> + Send + Sync>, >::new(); '''; @@ -452,10 +452,10 @@ pub fn handle_dart_signal( rustReceiveScript += ''' new_hash_map.insert( ${markedMessage.id}, - Box::new(|message_bytes: Vec, binary: Vec| { + Box::new(|message_bytes: &[u8], binary: Vec| { use super::$modulePath$filename::*; let message = ${normalizePascal(messageName)}::decode( - message_bytes.as_slice() + message_bytes )?; let dart_signal = DartSignal { message, diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 95e7739eb..213d03653 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -33,7 +33,7 @@ macro_rules! write_interface { binary_size: usize, ) { let message_bytes = - unsafe { std::slice::from_raw_parts(message_pointer, message_size).to_vec() }; + unsafe { std::slice::from_raw_parts(message_pointer, message_size) }; let binary = unsafe { std::slice::from_raw_parts(binary_pointer, binary_size).to_vec() }; messages::generated::handle_dart_signal(message_id, message_bytes, binary); From 36679e80f16a67264572dedcc1ba3d5862544179 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 15:52:39 +0900 Subject: [PATCH 084/128] Add comments and clarify code --- rust_crate/src/interface_os.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index c5818968e..e0629a8b8 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -87,7 +87,14 @@ where }) }); if let Ok(mut guard) = TOKIO_RUNTIME.lock() { - guard.replace(tokio_runtime); + // If there was already a tokio runtime previously, + // most likely due to Dart's hot restart, + // its tasks as well as itself will be terminated, + // being replaced with the new one. + let runtime_option = guard.replace(tokio_runtime); + if let Some(previous_runtime) = runtime_option { + drop(previous_runtime); + } } } From 11b86f0574b6842ecf4950269c9e0ba5fc01ed24 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 15:57:43 +0900 Subject: [PATCH 085/128] Fix a wrong type annotation --- rust_crate/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 213d03653..7a4bb0e35 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -42,7 +42,7 @@ macro_rules! write_interface { #[cfg(target_family = "wasm")] #[wasm_bindgen::prelude::wasm_bindgen] pub fn send_dart_signal_extern(message_id: i32, message_bytes: &[u8], binary: &[u8]) { - let message_bytes = message_bytes.to_vec(); + let message_bytes = message_bytes; let binary = binary.to_vec(); messages::generated::handle_dart_signal(message_id, message_bytes, binary); } From cf2fc1e853bd8da64c2e20dc381d825a9e1120e6 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 16:03:09 +0900 Subject: [PATCH 086/128] Add docs about base href --- documentation/docs/running-and-building.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/documentation/docs/running-and-building.md b/documentation/docs/running-and-building.md index 2539a0105..261652970 100644 --- a/documentation/docs/running-and-building.md +++ b/documentation/docs/running-and-building.md @@ -33,7 +33,9 @@ rinf wasm --release flutter run --release # Choose a browser ``` -To build the optimized release version of the web application: +To build the optimized release version of the web application[^4]: + +[^4]: Rinf supports hosting a Flutter app at a [non-root location](https://docs.flutter.dev/ui/navigation/url-strategies#hosting-a-flutter-app-at-a-non-root-location). For example, you can place your Flutter app in `https://mywebsite.com/subpath/deeperpath/`. ```bash title="CLI" rinf wasm --release From c470642ec0ff57ab8b9218b84a7e1ddcd34bb8e0 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 16:19:01 +0900 Subject: [PATCH 087/128] Let the example code snippet include widget --- README.md | 36 +++++++++++------------ documentation/overrides/home.html | 47 ------------------------------- flutter_ffi_plugin/README.md | 36 +++++++++++------------ rust_crate/README.md | 36 +++++++++++------------ 4 files changed, 48 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index cd954b972..095ce1f21 100644 --- a/README.md +++ b/README.md @@ -32,32 +32,28 @@ All platforms available with Flutter are [tested](https://github.com/cunarist/ri Below is Dart code with widgets, and following that is Rust code with business logic. ```dart -MySchemaInput( - fieldOne: 1, - fieldTwo: 2, - fieldThree: 3, -).sendSignalToRust() - -final stream = MySchemaOutput.rustSignalStream; -await for (final rustSignal in stream) { - // Custom Dart logic -} +StreamBuilder( + stream: MyMessage.rustSignalStream, + builder: (context, snapshot) { + final rustSignal = snapshot.data; + if (rustSignal == null) { + return Text("Nothing received yet"); + } + final myMessage = rustSignal.message; + return Text(myMessage.currentNumber.toString()); + }, +) ``` ```rust -MySchemaOutput { - field_four: 4, - field_five: 5, - field_six: 6, +MyMessage { + current_number: 7, }.send_signal_to_dart() - -let mut receiver = MySchemaInput::get_dart_signal_receiver(); -while let Some(dart_signal) = receiver.recv().await { - // Custom Rust logic -} ``` -All the message classes and structs are generated by Rinf. You can simply define the message schema with Protobuf. Sending messages between Dart and Rust is very convenient. +Of course, the opposite way from Dart to Rust is also possible in a similar manner. + +All message classes and structs are generated by Rinf. You can define the message schema simply with Protobuf, making message passing between Dart and Rust very convenient. ## 🎁 Benefits diff --git a/documentation/overrides/home.html b/documentation/overrides/home.html index 4fb486a0a..d597b887f 100644 --- a/documentation/overrides/home.html +++ b/documentation/overrides/home.html @@ -207,53 +207,6 @@

Platform Support

-
-

Communication

-
-
-

Dart with Widgets

-
-
-MySchemaInput(
-  fieldOne: 1,
-  fieldTwo: 2,
-  fieldThree: 3,
-).sendSignalToRust()
-
-final stream = MySchemaOutput.rustSignalStream;
-await for (final rustSignal in stream) {
-  // Custom Dart logic
-}
-          
-
-
-
-

Rust with Business Logic

-
-
-MySchemaOutput {
-    field_four: 4,
-    field_five: 5,
-    field_six: 6,
-}.send_signal_to_dart()
-
-let mut receiver = MySchemaInput::get_dart_signal_receiver();
-while let Some(dart_signal) = receiver.recv().await {
-    // Custom Rust logic
-}
-          
-
-
-
-
-

- All the message classes and structs are generated by Rinf. You can - simply define the message schema with Protobuf. Sending messages between - Dart and Rust is very convenient. -

-
-
-

Benefits

diff --git a/flutter_ffi_plugin/README.md b/flutter_ffi_plugin/README.md index cd954b972..095ce1f21 100644 --- a/flutter_ffi_plugin/README.md +++ b/flutter_ffi_plugin/README.md @@ -32,32 +32,28 @@ All platforms available with Flutter are [tested](https://github.com/cunarist/ri Below is Dart code with widgets, and following that is Rust code with business logic. ```dart -MySchemaInput( - fieldOne: 1, - fieldTwo: 2, - fieldThree: 3, -).sendSignalToRust() - -final stream = MySchemaOutput.rustSignalStream; -await for (final rustSignal in stream) { - // Custom Dart logic -} +StreamBuilder( + stream: MyMessage.rustSignalStream, + builder: (context, snapshot) { + final rustSignal = snapshot.data; + if (rustSignal == null) { + return Text("Nothing received yet"); + } + final myMessage = rustSignal.message; + return Text(myMessage.currentNumber.toString()); + }, +) ``` ```rust -MySchemaOutput { - field_four: 4, - field_five: 5, - field_six: 6, +MyMessage { + current_number: 7, }.send_signal_to_dart() - -let mut receiver = MySchemaInput::get_dart_signal_receiver(); -while let Some(dart_signal) = receiver.recv().await { - // Custom Rust logic -} ``` -All the message classes and structs are generated by Rinf. You can simply define the message schema with Protobuf. Sending messages between Dart and Rust is very convenient. +Of course, the opposite way from Dart to Rust is also possible in a similar manner. + +All message classes and structs are generated by Rinf. You can define the message schema simply with Protobuf, making message passing between Dart and Rust very convenient. ## 🎁 Benefits diff --git a/rust_crate/README.md b/rust_crate/README.md index cd954b972..095ce1f21 100644 --- a/rust_crate/README.md +++ b/rust_crate/README.md @@ -32,32 +32,28 @@ All platforms available with Flutter are [tested](https://github.com/cunarist/ri Below is Dart code with widgets, and following that is Rust code with business logic. ```dart -MySchemaInput( - fieldOne: 1, - fieldTwo: 2, - fieldThree: 3, -).sendSignalToRust() - -final stream = MySchemaOutput.rustSignalStream; -await for (final rustSignal in stream) { - // Custom Dart logic -} +StreamBuilder( + stream: MyMessage.rustSignalStream, + builder: (context, snapshot) { + final rustSignal = snapshot.data; + if (rustSignal == null) { + return Text("Nothing received yet"); + } + final myMessage = rustSignal.message; + return Text(myMessage.currentNumber.toString()); + }, +) ``` ```rust -MySchemaOutput { - field_four: 4, - field_five: 5, - field_six: 6, +MyMessage { + current_number: 7, }.send_signal_to_dart() - -let mut receiver = MySchemaInput::get_dart_signal_receiver(); -while let Some(dart_signal) = receiver.recv().await { - // Custom Rust logic -} ``` -All the message classes and structs are generated by Rinf. You can simply define the message schema with Protobuf. Sending messages between Dart and Rust is very convenient. +Of course, the opposite way from Dart to Rust is also possible in a similar manner. + +All message classes and structs are generated by Rinf. You can define the message schema simply with Protobuf, making message passing between Dart and Rust very convenient. ## 🎁 Benefits From 3434b87c65460ca1de6b051b376a17dd1e0b2580 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 16:48:11 +0900 Subject: [PATCH 088/128] Unify binary types --- flutter_ffi_plugin/bin/src/message.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index e99fcfd30..1b98a24bd 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -418,7 +418,7 @@ use std::sync::OnceLock; use tokio::sync::mpsc::unbounded_channel; type SignalHandlers = OnceLock< - HashMap) + HashMap Result<(), Box> + Send + Sync>>, >; static SIGNAL_HANDLERS: SignalHandlers = OnceLock::new(); @@ -426,12 +426,12 @@ static SIGNAL_HANDLERS: SignalHandlers = OnceLock::new(); pub fn handle_dart_signal( message_id: i32, message_bytes: &[u8], - binary: Vec + binary: &[u8] ) { let hash_map = SIGNAL_HANDLERS.get_or_init(|| { let mut new_hash_map = HashMap::< i32, - Box) + Box Result<(), Box> + Send + Sync>, >::new(); '''; @@ -452,14 +452,14 @@ pub fn handle_dart_signal( rustReceiveScript += ''' new_hash_map.insert( ${markedMessage.id}, - Box::new(|message_bytes: &[u8], binary: Vec| { + Box::new(|message_bytes: &[u8], binary: &[u8]| { use super::$modulePath$filename::*; let message = ${normalizePascal(messageName)}::decode( message_bytes )?; let dart_signal = DartSignal { message, - binary, + binary: binary.to_vec(), }; let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock()?; if guard.is_none() { From 6223ea802159da677dc1b33e54e945f03a7050fd Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 16:48:33 +0900 Subject: [PATCH 089/128] Fix a type mismatch --- rust_crate/src/macros.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 7a4bb0e35..927bdada6 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -34,8 +34,7 @@ macro_rules! write_interface { ) { let message_bytes = unsafe { std::slice::from_raw_parts(message_pointer, message_size) }; - let binary = - unsafe { std::slice::from_raw_parts(binary_pointer, binary_size).to_vec() }; + let binary = unsafe { std::slice::from_raw_parts(binary_pointer, binary_size) }; messages::generated::handle_dart_signal(message_id, message_bytes, binary); } From 3db2e4f24c02692812583c6971a12ced7305666d Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 17:10:54 +0900 Subject: [PATCH 090/128] Fix a type mismatch --- rust_crate/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 927bdada6..8dc6097a2 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -42,7 +42,7 @@ macro_rules! write_interface { #[wasm_bindgen::prelude::wasm_bindgen] pub fn send_dart_signal_extern(message_id: i32, message_bytes: &[u8], binary: &[u8]) { let message_bytes = message_bytes; - let binary = binary.to_vec(); + let binary = binary; messages::generated::handle_dart_signal(message_id, message_bytes, binary); } }; From fb3b03bc1d146042f134b3a41df352fb8a346530 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 20:00:43 +0900 Subject: [PATCH 091/128] Improve code readability --- documentation/docs/tutorial.md | 3 ++- .../example/native/hub/src/sample_functions.rs | 11 ++++++----- rust_crate/src/macros.rs | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/documentation/docs/tutorial.md b/documentation/docs/tutorial.md index 8669599e9..c9741016e 100644 --- a/documentation/docs/tutorial.md +++ b/documentation/docs/tutorial.md @@ -127,13 +127,14 @@ Define an async Rust function that runs forever, sending numbers to Dart every s ```rust title="native/hub/src/sample_functions.rs" ... use crate::messages; +use std::time::Duration; ... pub async fn stream_amazing_number() { use messages::tutorial_resource::*; let mut current_number: i32 = 1; loop { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(Duration::from_secs(1)).await; MyAmazingNumber { current_number }.send_signal_to_dart(); // GENERATED current_number += 1; } diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index 2205bb4bb..981fbc49d 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -3,6 +3,7 @@ use crate::messages; use crate::tokio; use rinf::debug_print; +use std::time::Duration; use tokio::sync::Mutex; // Using the `cfg` macro enables conditional statement. @@ -57,7 +58,7 @@ pub async fn stream_fractal() { tokio::spawn(async move { loop { // Wait for 40 milliseconds on each frame - tokio::time::sleep(std::time::Duration::from_millis(40)).await; + tokio::time::sleep(Duration::from_millis(40)).await; if sender.capacity() == 0 { continue; } @@ -120,7 +121,7 @@ pub async fn run_debug_tests() { return; } - tokio::time::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(Duration::from_secs(1)).await; debug_print!("Starting debug tests."); // Get the current time. @@ -138,15 +139,15 @@ pub async fn run_debug_tests() { // Test `tokio::join!` for futures. let join_first = async { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(Duration::from_secs(1)).await; debug_print!("First future finished."); }; let join_second = async { - tokio::time::sleep(std::time::Duration::from_secs(2)).await; + tokio::time::sleep(Duration::from_secs(2)).await; debug_print!("Second future finished."); }; let join_third = async { - tokio::time::sleep(std::time::Duration::from_secs(3)).await; + tokio::time::sleep(Duration::from_secs(3)).await; debug_print!("Third future finished."); }; tokio::join!(join_first, join_second, join_third); diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index 8dc6097a2..cdc5c8fd3 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -32,9 +32,9 @@ macro_rules! write_interface { binary_pointer: *const u8, binary_size: usize, ) { - let message_bytes = - unsafe { std::slice::from_raw_parts(message_pointer, message_size) }; - let binary = unsafe { std::slice::from_raw_parts(binary_pointer, binary_size) }; + use std::slice::from_raw_parts; + let message_bytes = unsafe { from_raw_parts(message_pointer, message_size) }; + let binary = unsafe { from_raw_parts(binary_pointer, binary_size) }; messages::generated::handle_dart_signal(message_id, message_bytes, binary); } From 02754956aa7ed4ab88f2025f73bb38170a1981ed Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 20:38:48 +0900 Subject: [PATCH 092/128] Make backtrace optional feature --- rust_crate/Cargo.toml | 3 ++- rust_crate/src/interface_os.rs | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index 520a0f49b..352853308 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -10,10 +10,11 @@ rust-version = "1.70" [features] multi-worker = ["tokio/rt-multi-thread"] +show-backtrace = ["backtrace"] [target.'cfg(not(target_family = "wasm"))'.dependencies] os-thread-local = "0.1.3" -backtrace = "0.3.69" +backtrace = { version = "0.3.69", optional = true } protoc-prebuilt = "0.3.0" home = "0.5.9" which = "6.0.0" diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index e0629a8b8..3494c3147 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -41,10 +41,19 @@ where // Enable backtrace output for panics. #[cfg(debug_assertions)] { - std::panic::set_hook(Box::new(|panic_info| { - let backtrace = backtrace::Backtrace::new(); - crate::debug_print!("A panic occurred in Rust.\n{panic_info}\n{backtrace:?}"); - })); + #[cfg(not(feature = "backtrace"))] + { + std::panic::set_hook(Box::new(|panic_info| { + crate::debug_print!("A panic occurred in Rust.\n{panic_info}"); + })); + } + #[cfg(feature = "backtrace")] + { + std::panic::set_hook(Box::new(|panic_info| { + let backtrace = backtrace::Backtrace::new(); + crate::debug_print!("A panic occurred in Rust.\n{panic_info}\n{backtrace:?}"); + })); + } } // Prepare the channel that will notify tokio runtime to shutdown From b0bc69244fd3b7240930436c1bed72461018bd9f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 20:48:57 +0900 Subject: [PATCH 093/128] Add backtrace feature to the docs --- documentation/docs/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/docs/configuration.md b/documentation/docs/configuration.md index e534da96c..266aa48ba 100644 --- a/documentation/docs/configuration.md +++ b/documentation/docs/configuration.md @@ -26,3 +26,4 @@ rinf = { version = "0.0.0", features = ["feature-name"] } ``` - `multi-worker`: Starts a worker thread for each CPU core available on the system within the `tokio` runtime. By default, the `tokio` runtime uses only one thread. Enabling this feature allows the `tokio` runtime to utilize all the cores on your computer. This feature does not affect applications on the web platform. +- `show-backtrace`: Prints the full backtrace in the CLI when a panic occurs in debug mode. This feature does not affect debugging on the web platform. From 4d3360949b0ccb9c7aa6aef5038a0422c0d87bc4 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 20:51:56 +0900 Subject: [PATCH 094/128] Explain `show-backtrace` in the docs --- documentation/docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/configuration.md b/documentation/docs/configuration.md index 266aa48ba..33a9cc208 100644 --- a/documentation/docs/configuration.md +++ b/documentation/docs/configuration.md @@ -26,4 +26,4 @@ rinf = { version = "0.0.0", features = ["feature-name"] } ``` - `multi-worker`: Starts a worker thread for each CPU core available on the system within the `tokio` runtime. By default, the `tokio` runtime uses only one thread. Enabling this feature allows the `tokio` runtime to utilize all the cores on your computer. This feature does not affect applications on the web platform. -- `show-backtrace`: Prints the full backtrace in the CLI when a panic occurs in debug mode. This feature does not affect debugging on the web platform. +- `show-backtrace`: Prints the full backtrace in the CLI when a panic occurs in debug mode. In general, backtrace is not very helpful when debugging async apps, so consider using [`tracing`](https://crates.io/crates/tracing) for logging purposes. Note that this feature does not affect debugging on the web platform. From 9aebf0a5e167308dfa9fed4fb7e6eca2ba249144 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 20:53:23 +0900 Subject: [PATCH 095/128] Improve guides about `multi-worker` --- documentation/docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/configuration.md b/documentation/docs/configuration.md index 33a9cc208..eab38f96f 100644 --- a/documentation/docs/configuration.md +++ b/documentation/docs/configuration.md @@ -25,5 +25,5 @@ rinf config rinf = { version = "0.0.0", features = ["feature-name"] } ``` -- `multi-worker`: Starts a worker thread for each CPU core available on the system within the `tokio` runtime. By default, the `tokio` runtime uses only one thread. Enabling this feature allows the `tokio` runtime to utilize all the cores on your computer. This feature does not affect applications on the web platform. +- `multi-worker`: Starts a worker thread for each CPU core available on the system within the `tokio` runtime by enabling its `rt-multi-thread` feature. By default, the `tokio` runtime uses only one thread. Enabling this feature allows the `tokio` runtime to utilize all the cores on your computer. This feature does not affect applications on the web platform. - `show-backtrace`: Prints the full backtrace in the CLI when a panic occurs in debug mode. In general, backtrace is not very helpful when debugging async apps, so consider using [`tracing`](https://crates.io/crates/tracing) for logging purposes. Note that this feature does not affect debugging on the web platform. From 1705de320a22c28a8eb12f6824f97664572db0a1 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 20:57:21 +0900 Subject: [PATCH 096/128] Add a sentence in the docs --- documentation/docs/configuration.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/documentation/docs/configuration.md b/documentation/docs/configuration.md index eab38f96f..692c3cec3 100644 --- a/documentation/docs/configuration.md +++ b/documentation/docs/configuration.md @@ -21,6 +21,8 @@ rinf config ## 📦 Crate Features +Customizing the behavior of the Rinf crate is possible through its crate features. + ```toml title="native/hub/Cargo.toml" rinf = { version = "0.0.0", features = ["feature-name"] } ``` From 9a7f7369754266eca9a74f47cd9d7747d54a0cce Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 21:37:56 +0900 Subject: [PATCH 097/128] Remove old guides --- documentation/docs/messaging.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/documentation/docs/messaging.md b/documentation/docs/messaging.md index 83cb90b6b..d74493465 100644 --- a/documentation/docs/messaging.md +++ b/documentation/docs/messaging.md @@ -1,11 +1,5 @@ # Messaging -!!! warning - - If you are using Rinf version 5 or earlier, please refer to the [historical documentation](https://github.com/cunarist/rinf/blob/v5.4.0/documentation/docs/writing-code.md). With the introduction of Rinf version 6, a simpler way for communication between Dart and Rust has been implemented, and the system has undergone significant changes. - -Marking Protobuf messages with special comments empower them with the capability to transmit signals across Dart and Rust. This is achieved by allowing Rinf's code generator to create the necessary channels for communication between Dart and Rust. - There are 2 types of special comments that you can mark messages with. ## 📭 Dart Signal From 716884282e1f3db27d03482966b896cbfe45c3a1 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 16 Jun 2024 23:54:14 +0900 Subject: [PATCH 098/128] Format code snippets --- README.md | 3 ++- flutter_ffi_plugin/README.md | 3 ++- rust_crate/README.md | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 095ce1f21..bb8eca3a0 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,8 @@ StreamBuilder( ```rust MyMessage { current_number: 7, -}.send_signal_to_dart() +} +.send_signal_to_dart() ``` Of course, the opposite way from Dart to Rust is also possible in a similar manner. diff --git a/flutter_ffi_plugin/README.md b/flutter_ffi_plugin/README.md index 095ce1f21..bb8eca3a0 100644 --- a/flutter_ffi_plugin/README.md +++ b/flutter_ffi_plugin/README.md @@ -48,7 +48,8 @@ StreamBuilder( ```rust MyMessage { current_number: 7, -}.send_signal_to_dart() +} +.send_signal_to_dart() ``` Of course, the opposite way from Dart to Rust is also possible in a similar manner. diff --git a/rust_crate/README.md b/rust_crate/README.md index 095ce1f21..bb8eca3a0 100644 --- a/rust_crate/README.md +++ b/rust_crate/README.md @@ -48,7 +48,8 @@ StreamBuilder( ```rust MyMessage { current_number: 7, -}.send_signal_to_dart() +} +.send_signal_to_dart() ``` Of course, the opposite way from Dart to Rust is also possible in a similar manner. From 088ec56688a999d9f82a0d40af85444b33049088 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 17 Jun 2024 20:11:33 +0900 Subject: [PATCH 099/128] Make the return type of the main empty --- rust_crate/src/interface.rs | 4 ++-- rust_crate/src/interface_os.rs | 6 ++---- rust_crate/src/interface_web.rs | 6 ++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index 0b1d8fcba..880cf91e6 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -28,7 +28,7 @@ pub struct DartSignal { #[cfg(not(target_family = "wasm"))] pub fn start_rust_logic(main_future: F) -> Result<()> where - F: Future + Send + 'static, + F: Future + Send + 'static, { start_rust_logic_real(main_future) } @@ -39,7 +39,7 @@ where #[cfg(target_family = "wasm")] pub fn start_rust_logic(main_future: F) -> Result<()> where - F: Future + 'static, + F: Future + 'static, { start_rust_logic_real(main_future) } diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 3494c3147..ea81574b9 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -36,7 +36,7 @@ static SHUTDOWN_SENDER: ShutdownSenderLock = OnceLock::new(); pub fn start_rust_logic_real(main_future: F) -> Result<()> where - F: Future + Send + 'static, + F: Future + Send + 'static, { // Enable backtrace output for panics. #[cfg(debug_assertions)] @@ -68,9 +68,7 @@ where { let tokio_runtime = Builder::new_current_thread().enable_all().build()?; thread::spawn(move || { - tokio_runtime.spawn(async { - main_future.await; - }); + tokio_runtime.spawn(main_future); tokio_runtime.block_on(shutdown_receiver); // Dropping the tokio runtime makes it shut down. drop(tokio_runtime); diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index e8cc4330b..9bb6e0f92 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -6,7 +6,7 @@ use wasm_bindgen_futures::spawn_local; pub fn start_rust_logic_real(main_future: F) -> Result<()> where - F: Future + 'static, + F: Future + 'static, { // Add kind description for panics. #[cfg(debug_assertions)] @@ -17,9 +17,7 @@ where } // Run the main function. - spawn_local(async { - main_future.await; - }); + spawn_local(main_future); Ok(()) } From 64af97cb22be10dc83ab650475c2e89be4047048 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 17 Jun 2024 22:23:45 +0900 Subject: [PATCH 100/128] Use `Result` in sample functions code --- .../example/native/hub/src/common.rs | 3 +++ flutter_ffi_plugin/example/native/hub/src/lib.rs | 1 + .../example/native/hub/src/sample_functions.rs | 15 +++++++++------ .../example/native/sample_crate/src/common.rs | 3 +++ .../example/native/sample_crate/src/lib.rs | 15 ++++++++++----- 5 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 flutter_ffi_plugin/example/native/hub/src/common.rs create mode 100644 flutter_ffi_plugin/example/native/sample_crate/src/common.rs diff --git a/flutter_ffi_plugin/example/native/hub/src/common.rs b/flutter_ffi_plugin/example/native/hub/src/common.rs new file mode 100644 index 000000000..c7a6d7bab --- /dev/null +++ b/flutter_ffi_plugin/example/native/hub/src/common.rs @@ -0,0 +1,3 @@ +use std::error::Error; + +pub type Result = std::result::Result>; diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs index d5a610202..017c2991f 100755 --- a/flutter_ffi_plugin/example/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs @@ -1,6 +1,7 @@ //! This `hub` crate is the //! entry point of the Rust logic. +mod common; mod messages; mod sample_functions; diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index 981fbc49d..cb6830734 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -1,5 +1,6 @@ //! This crate is written for Rinf demonstrations. +use crate::common::*; use crate::messages; use crate::tokio; use rinf::debug_print; @@ -12,8 +13,8 @@ const IS_DEBUG_MODE: bool = true; #[cfg(not(debug_assertions))] const IS_DEBUG_MODE: bool = false; -// This is one of the best ways to keep a global mutable state in Rust. -// You can also use `tokio::sync::RwLock` or `tokio::sync::OnceCell`. +// This is one of the ways to keep a global mutable state in Rust. +// You can also use `tokio::sync::RwLock` or `std::lazy::LazyLock`. static VECTOR: Mutex> = Mutex::const_new(Vec::new()); // Business logic for the counter widget. @@ -116,9 +117,9 @@ async fn use_messages() { } // Business logic for testing various crates. -pub async fn run_debug_tests() { +pub async fn run_debug_tests() -> Result<()> { if !IS_DEBUG_MODE { - return; + return Ok(()); } tokio::time::sleep(Duration::from_secs(1)).await; @@ -130,11 +131,11 @@ pub async fn run_debug_tests() { // Fetch data from a web API. let url = "http://jsonplaceholder.typicode.com/todos/1"; - let web_response = sample_crate::fetch_from_web_api(url).await; + let web_response = sample_crate::fetch_from_web_api(url).await?; debug_print!("Response from a web API: {web_response:?}"); // Use a crate that accesses operating system APIs. - let hwid = sample_crate::get_hardward_id(); + let hwid = sample_crate::get_hardward_id()?; debug_print!("Hardware ID: {hwid:?}"); // Test `tokio::join!` for futures. @@ -219,4 +220,6 @@ pub async fn run_debug_tests() { // It is better to avoid panicking code at all costs on the web. panic!("INTENTIONAL DEBUG PANIC"); }); + + Ok(()) } diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/common.rs b/flutter_ffi_plugin/example/native/sample_crate/src/common.rs new file mode 100644 index 000000000..c7a6d7bab --- /dev/null +++ b/flutter_ffi_plugin/example/native/sample_crate/src/common.rs @@ -0,0 +1,3 @@ +use std::error::Error; + +pub type Result = std::result::Result>; diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs index a6170456f..85927dbea 100755 --- a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs +++ b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs @@ -1,17 +1,21 @@ //! This crate is written for Rinf demonstrations. +mod common; mod fractal; + +use common::*; + pub use fractal::draw_fractal_image; // `machineid_rs` only supports desktop platforms. #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] -pub fn get_hardward_id() -> Option { +pub fn get_hardward_id() -> Result { let mut builder = machineid_rs::IdBuilder::new(machineid_rs::Encryption::MD5); builder .add_component(machineid_rs::HWIDComponent::SystemID) .add_component(machineid_rs::HWIDComponent::CPUCores); - let hwid = builder.build("mykey").ok()?; - Some(hwid) + let hwid = builder.build("mykey")?; + Ok(hwid) } #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] pub fn get_hardward_id() -> Option { @@ -25,6 +29,7 @@ pub fn get_current_time() -> DateTime { } // `reqwest` supports all platforms, including web. -pub async fn fetch_from_web_api(url: &str) -> Option { - reqwest::get(url).await.ok()?.text().await.ok() +pub async fn fetch_from_web_api(url: &str) -> Result { + let fetched = reqwest::get(url).await?.text().await?; + Ok(fetched) } From 092ee1e626cd028ca310ffcc07b4e06c65eb57aa Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 17 Jun 2024 22:27:33 +0900 Subject: [PATCH 101/128] Make the sample code work on the web --- flutter_ffi_plugin/example/native/sample_crate/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs index 85927dbea..aab1573ba 100755 --- a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs +++ b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs @@ -18,8 +18,8 @@ pub fn get_hardward_id() -> Result { Ok(hwid) } #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] -pub fn get_hardward_id() -> Option { - None +pub fn get_hardward_id() -> Result { + Ok(String::from("UNSUPPORTED")) } // `chrono` supports all platforms, including web. From 06a556f7342ef7ff60d82c2b02ccd1258fb05617 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 17 Jun 2024 22:51:14 +0900 Subject: [PATCH 102/128] Completely remove `expect` as well as `unwrap` --- flutter_ffi_plugin/bin/src/message.dart | 23 ++++++++++++++----- .../native/hub/src/sample_functions.rs | 6 +++-- .../template/native/hub/src/common.rs | 3 +++ .../template/native/hub/src/lib.rs | 9 ++++++-- 4 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 flutter_ffi_plugin/template/native/hub/src/common.rs diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 1b98a24bd..79ddeaa07 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -258,12 +258,16 @@ import 'package:rinf/rinf.dart'; rustPath, ''' #![allow(unused_imports)] +#![allow(dead_code)] use crate::tokio; use prost::Message; use rinf::{send_rust_signal, DartSignal}; +use std::error::Error; use std::sync::Mutex; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; + +type Result = std::result::Result>; ''', atFront: true, ); @@ -287,9 +291,13 @@ pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = Mutex::new(None); impl ${normalizePascal(messageName)} { - pub fn get_dart_signal_receiver() -> UnboundedReceiver> { - let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock() - .expect("Could not access the channel lock."); + pub fn get_dart_signal_receiver() + -> Result>> + { + let mut guard = + ${snakeName.toUpperCase()}_CHANNEL.lock().map_err(|_| { + String::from("Could not acquire the channel lock.") + })?; if guard.is_none() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); @@ -301,7 +309,7 @@ impl ${normalizePascal(messageName)} { // which is now closed. let pair = guard .as_ref() - .expect("Message channel in Rust not present."); + .ok_or("Message channel in Rust not present.")?; if pair.0.is_closed() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); @@ -309,9 +317,12 @@ impl ${normalizePascal(messageName)} { } let pair = guard .take() - .expect("Message channel in Rust not present."); + .ok_or("Message channel in Rust not present.")?; guard.replace((pair.0, None)); - pair.1.expect("Each Dart signal receiver can be taken only once") + let receiver = pair + .1 + .ok_or("Each Dart signal receiver can be taken only once")?; + Ok(receiver) } } ''', diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index cb6830734..1177f83b4 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -18,11 +18,11 @@ const IS_DEBUG_MODE: bool = false; static VECTOR: Mutex> = Mutex::const_new(Vec::new()); // Business logic for the counter widget. -pub async fn tell_numbers() { +pub async fn tell_numbers() -> Result<()> { use messages::counter_number::*; // Stream getter is generated from a marked Protobuf message. - let mut receiver = SampleNumberInput::get_dart_signal_receiver(); + let mut receiver = SampleNumberInput::get_dart_signal_receiver()?; while let Some(dart_signal) = receiver.recv().await { // Extract values from the message received from Dart. // This message is a type that's declared in its Protobuf file. @@ -44,6 +44,8 @@ pub async fn tell_numbers() { } .send_signal_to_dart(); } + + Ok(()) } // Business logic for the fractal image. diff --git a/flutter_ffi_plugin/template/native/hub/src/common.rs b/flutter_ffi_plugin/template/native/hub/src/common.rs new file mode 100644 index 000000000..c7a6d7bab --- /dev/null +++ b/flutter_ffi_plugin/template/native/hub/src/common.rs @@ -0,0 +1,3 @@ +use std::error::Error; + +pub type Result = std::result::Result>; diff --git a/flutter_ffi_plugin/template/native/hub/src/lib.rs b/flutter_ffi_plugin/template/native/hub/src/lib.rs index 9c2519f42..80ec36e12 100644 --- a/flutter_ffi_plugin/template/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/template/native/hub/src/lib.rs @@ -1,10 +1,11 @@ //! This `hub` crate is the //! entry point of the Rust logic. +mod common; mod messages; use tokio; // Comment this line to target the web. -// use tokio_with_wasm::alias as tokio; // Uncomment this line to target the web. + // use tokio_with_wasm::alias as tokio; // Uncomment this line to target the web. rinf::write_interface!(); @@ -15,10 +16,14 @@ rinf::write_interface!(); // use `tokio::task::spawn_blocking`. async fn main() { use messages::basic::*; + tokio::spawn(communicate()); +} + +async fn communicate() -> Result<()> { // Send signals to Dart like below. SmallNumber { number: 7 }.send_signal_to_dart(); // Get receivers that listen to Dart signals like below. - let mut receiver = SmallText::get_dart_signal_receiver(); + let mut receiver = SmallText::get_dart_signal_receiver()?; while let Some(dart_signal) = receiver.recv().await { let message: SmallText = dart_signal.message; rinf::debug_print!("{message:?}"); From 08d17847a9cdef192b524e7a0999e3f4b858accb Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 17 Jun 2024 22:56:01 +0900 Subject: [PATCH 103/128] Make the test app work again --- flutter_ffi_plugin/template/native/hub/Cargo.toml | 4 ++-- flutter_ffi_plugin/template/native/hub/src/lib.rs | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/flutter_ffi_plugin/template/native/hub/Cargo.toml b/flutter_ffi_plugin/template/native/hub/Cargo.toml index 13b0ebd57..a739bfc75 100644 --- a/flutter_ffi_plugin/template/native/hub/Cargo.toml +++ b/flutter_ffi_plugin/template/native/hub/Cargo.toml @@ -14,8 +14,8 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] rinf = "6.12.1" prost = "0.12.6" -tokio = { version = "1", features = ["sync"] } +tokio = { version = "1", features = ["sync", "rt"] } # Uncomment below to target the web. -# tokio_with_wasm = { version = "0.6.0", features = ["sync"] } +# tokio_with_wasm = { version = "0.6.0", features = ["sync", "rt"] } # wasm-bindgen = "0.2.92" diff --git a/flutter_ffi_plugin/template/native/hub/src/lib.rs b/flutter_ffi_plugin/template/native/hub/src/lib.rs index 80ec36e12..60f4aa223 100644 --- a/flutter_ffi_plugin/template/native/hub/src/lib.rs +++ b/flutter_ffi_plugin/template/native/hub/src/lib.rs @@ -4,8 +4,9 @@ mod common; mod messages; +use crate::common::*; use tokio; // Comment this line to target the web. - // use tokio_with_wasm::alias as tokio; // Uncomment this line to target the web. +// use tokio_with_wasm::alias as tokio; // Uncomment this line to target the web. rinf::write_interface!(); @@ -15,11 +16,11 @@ rinf::write_interface!(); // If you really need to use blocking code, // use `tokio::task::spawn_blocking`. async fn main() { - use messages::basic::*; tokio::spawn(communicate()); } async fn communicate() -> Result<()> { + use messages::basic::*; // Send signals to Dart like below. SmallNumber { number: 7 }.send_signal_to_dart(); // Get receivers that listen to Dart signals like below. @@ -28,4 +29,5 @@ async fn communicate() -> Result<()> { let message: SmallText = dart_signal.message; rinf::debug_print!("{message:?}"); } + Ok(()) } From f2363e4454ac00b7754adec23858e7b21b468cbf Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 17 Jun 2024 23:37:56 +0900 Subject: [PATCH 104/128] Simplify the message output --- flutter_ffi_plugin/bin/src/message.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 79ddeaa07..3aa6a836d 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -294,10 +294,9 @@ impl ${normalizePascal(messageName)} { pub fn get_dart_signal_receiver() -> Result>> { - let mut guard = - ${snakeName.toUpperCase()}_CHANNEL.lock().map_err(|_| { - String::from("Could not acquire the channel lock.") - })?; + let mut guard = ${snakeName.toUpperCase()}_CHANNEL + .lock() + .map_err(|_| "Could not acquire the channel lock.")?; if guard.is_none() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); @@ -321,7 +320,7 @@ impl ${normalizePascal(messageName)} { guard.replace((pair.0, None)); let receiver = pair .1 - .ok_or("Each Dart signal receiver can be taken only once")?; + .ok_or("Each Dart signal receiver can be taken only once.")?; Ok(receiver) } } From a2d73c31fc1402d67a81a85ed66018a971d4e6b6 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 17 Jun 2024 23:45:15 +0900 Subject: [PATCH 105/128] Add comments --- flutter_ffi_plugin/example/native/hub/src/common.rs | 4 ++++ flutter_ffi_plugin/template/native/hub/src/common.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/flutter_ffi_plugin/example/native/hub/src/common.rs b/flutter_ffi_plugin/example/native/hub/src/common.rs index c7a6d7bab..44f453a42 100644 --- a/flutter_ffi_plugin/example/native/hub/src/common.rs +++ b/flutter_ffi_plugin/example/native/hub/src/common.rs @@ -1,3 +1,7 @@ use std::error::Error; +/// Using this `Result` type alias allows +/// handling any error type that implements the `Error` trait. +/// This approach eliminates the need +/// to depend on external crates for error handling. pub type Result = std::result::Result>; diff --git a/flutter_ffi_plugin/template/native/hub/src/common.rs b/flutter_ffi_plugin/template/native/hub/src/common.rs index c7a6d7bab..44f453a42 100644 --- a/flutter_ffi_plugin/template/native/hub/src/common.rs +++ b/flutter_ffi_plugin/template/native/hub/src/common.rs @@ -1,3 +1,7 @@ use std::error::Error; +/// Using this `Result` type alias allows +/// handling any error type that implements the `Error` trait. +/// This approach eliminates the need +/// to depend on external crates for error handling. pub type Result = std::result::Result>; From 297f40cdba7a8aceed069e5fc9293f2a860b9eda Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 00:52:33 +0900 Subject: [PATCH 106/128] Update docs about `get_dart_signal_receiver` --- .../docs/frequently-asked-questions.md | 24 ++-- documentation/docs/graceful-shutdown.md | 3 +- documentation/docs/messaging.md | 4 +- documentation/docs/tutorial.md | 107 +++++++++--------- 4 files changed, 61 insertions(+), 77 deletions(-) diff --git a/documentation/docs/frequently-asked-questions.md b/documentation/docs/frequently-asked-questions.md index fd10391e0..c78e1fe88 100644 --- a/documentation/docs/frequently-asked-questions.md +++ b/documentation/docs/frequently-asked-questions.md @@ -131,9 +131,9 @@ There might be various Rust codes with these attribute above: ```rust title="Rust" #[cfg(target_family = "wasm")] -... +{} #[cfg(not(target_family = "wasm"))] -... +{} ``` Since the environments of the web and native platforms are so different, there are times when you need to use these attributes to include and exclude parts of the code depending on whether they are targeting web or not. @@ -148,6 +148,8 @@ By default, Rust-analyzer runs in native mode. To make it run in webassembly mod target = "wasm32-unknown-unknown" ``` +You need to restart Rust language server for this to take effect. + ### CMake cache is broken after I moved the app folder ```title="Output" @@ -171,12 +173,9 @@ If you are using older Android versions, you may encounter errors due to issues To address this, you can modify `AndroidManifest.xml` files under `./android/app/src/` as follows. ```xml title="android/app/src/**/AndroidManifest.xml" -... -... ``` ### How can I await a response? @@ -188,7 +187,7 @@ However, if you really need to store some state in a Flutter widget, you can ach ```proto title="messages/tutorial_resource.proto" syntax = "proto3"; package tutorial_resource; -... + // [RINF:DART-SIGNAL] message MyUniqueInput { int32 interaction_id = 1; @@ -203,7 +202,6 @@ message MyUniqueOutput { ``` ```dart title="lib/main.dart" -... import 'dart:async'; import 'package:example_app/messages/tutorial_resource.pb.dart'; @@ -211,21 +209,17 @@ var currentInteractionId = 0; final myUniqueOutputs = Map>(); void main() async { - ... - MyUniqueOutput.rustSignalStream.listen((rustSignal) { + MyUniqueOutput.rustSignalStream.listen((rustSignal) { final myUniqueInput = rustSignal.message; myUniqueOutputs[myUniqueInput.interactionId]!.complete(myUniqueInput); }); - ... } -... ``` ```dart title="lib/main.dart" -... import 'dart:async'; import 'package:example_app/messages/tutorial_resource.pb.dart'; -... + onPressed: () async { final completer = Completer(); myUniqueOutputs[currentInteractionId] = completer; @@ -236,7 +230,6 @@ onPressed: () async { currentInteractionId += 1; final myUniqueOutput = await completer.future; }, -... ``` ```rust title="native/hub/src/sample_functions.rs" @@ -257,7 +250,6 @@ pub async fn respond() { ```rust title="native/hub/src/lib.rs" async fn main() { - ... tokio::spawn(sample_functions::respond()); } ``` @@ -324,9 +316,7 @@ import './messages/generated.dart'; async void main() { await initializeRust(compiledLibPath: "/path/to/library/libhub.so"); - ... } -... ``` This provided path will be used for finding dynamic library files on native platforms with Dart's `DynamicLibrary.open([compiledLibPath])`, and for loading the JavaScript module on the web with `import init, * as wasmBindings from "[compiledLibPath]"`. diff --git a/documentation/docs/graceful-shutdown.md b/documentation/docs/graceful-shutdown.md index c969946a9..42bd8447a 100644 --- a/documentation/docs/graceful-shutdown.md +++ b/documentation/docs/graceful-shutdown.md @@ -9,7 +9,7 @@ In some cases, you might need to run some finalization code in Rust before the a ```dart title="lib/main.dart" import 'dart:ui'; import 'package:flutter/material.dart'; -... + class MyApp extends StatefulWidget { const MyApp({super.key}); @@ -39,7 +39,6 @@ class _MyAppState extends State { ); } } -... ``` It's worth noting that `AppLifecycleListener` or `dispose` cannot always be relied upon for app closings. Below is a text snippet quoted from the official [Flutter docs](https://api.flutter.dev/flutter/widgets/State/dispose.html): diff --git a/documentation/docs/messaging.md b/documentation/docs/messaging.md index d74493465..e8939df8b 100644 --- a/documentation/docs/messaging.md +++ b/documentation/docs/messaging.md @@ -16,7 +16,7 @@ MyDataInput( ... ).sendSignalToRust(); ``` ```rust title="Rust" -let mut receiver = MyDataInput::get_dart_signal_receiver(); +let mut receiver = MyDataInput::get_dart_signal_receiver()?; while let Some(dart_signal) = receiver.recv().await { let message: MyDataInput = dart_signal.message; // Custom Rust logic here @@ -36,7 +36,7 @@ MyDataInput( ... ).sendSignalToRust(binary); ``` ```rust title="Rust" -let mut receiver = MyDataInput::get_dart_signal_receiver(); +let mut receiver = MyDataInput::get_dart_signal_receiver()?; while let Some(dart_signal) = receiver.recv().await { let message: MyDataInput = dart_signal.message; let binary: Vec = dart_signal.binary; diff --git a/documentation/docs/tutorial.md b/documentation/docs/tutorial.md index c9741016e..3ccd0618f 100644 --- a/documentation/docs/tutorial.md +++ b/documentation/docs/tutorial.md @@ -5,12 +5,10 @@ To grasp the basic concepts, it's beneficial to follow a step-by-step tutorial. Before we start, make sure that there's a `Column` somewhere in your widget tree. This will contain our tutorial widgets. ```dart title="lib/main.dart" -... child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [], ) -... ``` ## 🚨 From Dart to Rust @@ -19,9 +17,9 @@ Let's say that you want to create a new button in Dart that sends an array of nu Write a new `.proto` file in the `./messages` directory with a new message. Note that the message should have the comment `[RINF:DART-SIGNAL]` above it. -```proto title="messages/tutorial_resource.proto" +```proto title="messages/tutorial_messages.proto" syntax = "proto3"; -package tutorial_resource; +package tutorial_messages; // [RINF:DART-SIGNAL] message MyPreciousData { @@ -39,9 +37,8 @@ rinf message Create a button widget in Dart that accepts the user input. ```dart title="lib/main.dart" -... -import 'package:example_app/messages/tutorial_resource.pb.dart'; -... +import 'package:test_app/messages/tutorial_messages.pb.dart'; + child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -54,20 +51,21 @@ child: Column( }, child: Text("Send a Signal from Dart to Rust"), ), -... + ] +) ``` Let's listen to this message in Rust. This simple function will add one to each element in the array and capitalize all letters in the string. -```rust title="native/hub/src/sample_functions.rs" -... +```rust title="native/hub/src/tutorial_functions.rs" +use crate::common::*; use crate::messages; use rinf::debug_print; -... -pub async fn calculate_precious_data() { - use messages::tutorial_resource::*; - let mut receiver = MyPreciousData::get_dart_signal_receiver(); // GENERATED +pub async fn calculate_precious_data() -> Result<()> { + use messages::tutorial_messages::*; + + let mut receiver = MyPreciousData::get_dart_signal_receiver()?; // GENERATED while let Some(dart_signal) = receiver.recv().await { let my_precious_data = dart_signal.message; @@ -81,21 +79,20 @@ pub async fn calculate_precious_data() { debug_print!("{new_numbers:?}"); debug_print!("{new_string}"); } + + Ok(()) } -... ``` ```rust title="native/hub/src/lib.rs" -... -mod sample_functions; -... +mod tutorial_functions; + async fn main() { -... - tokio::spawn(sample_functions::calculate_precious_data()); + tokio::spawn(tutorial_functions::calculate_precious_data()); } ``` -Now we can see the printed output in the command-line when clicking the button! +Now run the app with `flutter run`. We can see the printed output in the command-line when clicking the button! ```title="Output" flutter: [4, 5, 6] @@ -108,10 +105,10 @@ Let's say that you want to send increasing numbers every second from Rust to Dar Define the message. Note that the message should have the comment `[RINF:RUST-SIGNAL]` above it. -```proto title="messages/tutorial_resource.proto" +```proto title="messages/tutorial_messages.proto" syntax = "proto3"; -package tutorial_resource; -... +package tutorial_messages; + // [RINF:RUST-SIGNAL] message MyAmazingNumber { int32 current_number = 1; } ``` @@ -124,13 +121,16 @@ rinf message Define an async Rust function that runs forever, sending numbers to Dart every second. -```rust title="native/hub/src/sample_functions.rs" -... +```toml title="native/hub/Cargo.toml" +tokio = { version = "1", features = ["sync", "rt", "time"] } +``` + +```rust title="native/hub/src/tutorial_functions.rs" use crate::messages; use std::time::Duration; -... + pub async fn stream_amazing_number() { - use messages::tutorial_resource::*; + use messages::tutorial_messages::*; let mut current_number: i32 = 1; loop { @@ -139,25 +139,20 @@ pub async fn stream_amazing_number() { current_number += 1; } } -... ``` ```rust title="native/hub/src/lib.rs" -... -mod sample_functions; -... +mod tutorial_functions; + async fn main() { -... - tokio::spawn(sample_functions::stream_amazing_number()); + tokio::spawn(tutorial_functions::stream_amazing_number()); } ``` Finally, receive the signals in Dart with `StreamBuilder` and rebuild the widget accordingly. ```dart title="lib/main.dart" -... -import 'package:example_app/messages/tutorial_resource.pb.dart'; -... +import 'package:test_app/messages/tutorial_messages.pb.dart'; children: [ StreamBuilder( stream: MyAmazingNumber.rustSignalStream, // GENERATED @@ -171,17 +166,17 @@ children: [ return Text(currentNumber.toString()); }, ), -... +] ``` ## 🤝 Back and Forth You can easily show the updated state on the screen by combining those two ways of message passing. -```proto title="messages/tutorial_resource.proto" +```proto title="messages/tutorial_messages.proto" syntax = "proto3"; -package tutorial_resource; -... +package tutorial_messages; + // [RINF:DART-SIGNAL] message MyTreasureInput {} @@ -194,9 +189,8 @@ rinf message ``` ```dart title="lib/main.dart" -... -import 'package:example_app/messages/tutorial_resource.pb.dart'; -... +import 'package:test_app/messages/tutorial_messages.pb.dart'; + children: [ StreamBuilder( stream: MyTreasureOutput.rustSignalStream, // GENERATED @@ -216,31 +210,32 @@ children: [ }, child: Text('Send the input'), ), -... +] ``` -```rust title="native/hub/src/sample_functions.rs" -... +```rust title="native/hub/src/tutorial_functions.rs" +use crate::common::*; use crate::messages; -... -pub async fn tell_treasure() { - use messages::tutorial_resource::*; + +pub async fn tell_treasure() -> Result<()> { + use messages::tutorial_messages::*; let mut current_value: i32 = 1; - let mut receiver = MyTreasureInput::get_dart_signal_receiver(); // GENERATED + + let mut receiver = MyTreasureInput::get_dart_signal_receiver()?; // GENERATED while let Some(_) = receiver.recv().await { MyTreasureOutput { current_value }.send_signal_to_dart(); // GENERATED current_value += 1; } + + Ok(()) } ``` ```rust title="native/hub/src/lib.rs" -... -mod sample_functions; -... +mod tutorial_functions; + async fn main() { -... - tokio::spawn(sample_functions::tell_treasure()); + tokio::spawn(tutorial_functions::tell_treasure()); } ``` From 412adfb8c3883379ef714e927de340616d0c660c Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 00:55:24 +0900 Subject: [PATCH 107/128] Organize docs about messaging --- documentation/docs/messaging.md | 95 ++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/documentation/docs/messaging.md b/documentation/docs/messaging.md index e8939df8b..7d8c46bc7 100644 --- a/documentation/docs/messaging.md +++ b/documentation/docs/messaging.md @@ -2,86 +2,97 @@ There are 2 types of special comments that you can mark messages with. -## 📭 Dart Signal +## 📢 Rust Signal -`[RINF:DART-SIGNAL]` generates a channel from Dart to Rust. +`[RINF:RUST-SIGNAL]` generates a channel from Rust to Dart. ```proto title="Protobuf" -// [RINF:DART-SIGNAL] -message MyDataInput { ... } +// [RINF:RUST-SIGNAL] +message MyDataOutput { ... } ``` ```dart title="Dart" -MyDataInput( ... ).sendSignalToRust(); +StreamBuilder( + stream: MyDataOutput.rustSignalStream, + builder: (context, snapshot) { + final rustSignal = snapshot.data; + if (rustSignal == null) { + // Return an empty widget. + } + final myDataOutput = rustSignal.message; + // Return a filled widget. + }, +) ``` ```rust title="Rust" -let mut receiver = MyDataInput::get_dart_signal_receiver()?; -while let Some(dart_signal) = receiver.recv().await { - let message: MyDataInput = dart_signal.message; - // Custom Rust logic here -} +MyDataOutput { ... }.send_signal_to_dart(); ``` -Use `[RINF:DART-SIGNAL-BINARY]` to include binary data without the overhead of serialization. +Use `[RINF:RUST-SIGNAL-BINARY]` to include binary data without the overhead of serialization. ```proto title="Protobuf" -// [RINF:DART-SIGNAL-BINARY] -message MyDataInput { ... } +// [RINF:RUST-SIGNAL-BINARY] +message MyDataOutput { ... } ``` ```dart title="Dart" -final binary = Uint8List(64); -MyDataInput( ... ).sendSignalToRust(binary); +StreamBuilder( + stream: MyDataOutput.rustSignalStream, + builder: (context, snapshot) { + final rustSignal = snapshot.data; + if (rustSignal == null) { + // Return an empty widget. + } + final myDataOutput = rustSignal.message; + // Return a filled widget. + }, +) ``` ```rust title="Rust" -let mut receiver = MyDataInput::get_dart_signal_receiver()?; -while let Some(dart_signal) = receiver.recv().await { - let message: MyDataInput = dart_signal.message; - let binary: Vec = dart_signal.binary; - // Custom Rust logic here -} +let binary: Vec = vec![0; 64]; +MyDataOutput { ... }.send_signal_to_dart(binary); ``` -## 📢 Rust Signal +## 📭 Dart Signal -`[RINF:RUST-SIGNAL]` generates a channel from Rust to Dart. +`[RINF:DART-SIGNAL]` generates a channel from Dart to Rust. ```proto title="Protobuf" -// [RINF:RUST-SIGNAL] -message MyDataOutput { ... } +// [RINF:DART-SIGNAL] +message MyDataInput { ... } ``` ```dart title="Dart" -final stream = MyDataOutput.rustSignalStream; -await for (final rustSignal in stream) { - MyDataOutput message = rustSignal.message; - // Custom Dart logic here -} +MyDataInput( ... ).sendSignalToRust(); ``` ```rust title="Rust" -MyDataOutput { ... }.send_signal_to_dart(); +let mut receiver = MyDataInput::get_dart_signal_receiver()?; +while let Some(dart_signal) = receiver.recv().await { + let message: MyDataInput = dart_signal.message; + // Custom Rust logic here +} ``` -Use `[RINF:RUST-SIGNAL-BINARY]` to include binary data without the overhead of serialization. +Use `[RINF:DART-SIGNAL-BINARY]` to include binary data without the overhead of serialization. ```proto title="Protobuf" -// [RINF:RUST-SIGNAL-BINARY] -message MyDataOutput { ... } +// [RINF:DART-SIGNAL-BINARY] +message MyDataInput { ... } ``` ```dart title="Dart" -final stream = MyDataOutput.rustSignalStream; -await for (final rustSignal in stream) { - MyDataOutput message = rustSignal.message; - Uint8List binary = rustSignal.binary; - // Custom Dart logic here -} +final binary = Uint8List(64); +MyDataInput( ... ).sendSignalToRust(binary); ``` ```rust title="Rust" -let binary: Vec = vec![0; 64]; -MyDataOutput { ... }.send_signal_to_dart(binary); +let mut receiver = MyDataInput::get_dart_signal_receiver()?; +while let Some(dart_signal) = receiver.recv().await { + let message: MyDataInput = dart_signal.message; + let binary: Vec = dart_signal.binary; + // Custom Rust logic here +} ``` From b85f896c7548cf2e418698d5f43865966b9c0a27 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 00:59:57 +0900 Subject: [PATCH 108/128] Clarify types in code snippets --- documentation/docs/messaging.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/documentation/docs/messaging.md b/documentation/docs/messaging.md index 7d8c46bc7..67fd07058 100644 --- a/documentation/docs/messaging.md +++ b/documentation/docs/messaging.md @@ -19,7 +19,7 @@ StreamBuilder( if (rustSignal == null) { // Return an empty widget. } - final myDataOutput = rustSignal.message; + MyDataOutput message = rustSignal.message; // Return a filled widget. }, ) @@ -44,7 +44,8 @@ StreamBuilder( if (rustSignal == null) { // Return an empty widget. } - final myDataOutput = rustSignal.message; + MyDataOutput message = rustSignal.message; + Uint8List binary = rustSignal.binary; // Return a filled widget. }, ) From a800003cc0ba90bbff9ef33dc3c69202e2053278 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 01:03:24 +0900 Subject: [PATCH 109/128] Fix an indent in the docs --- documentation/docs/frequently-asked-questions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/frequently-asked-questions.md b/documentation/docs/frequently-asked-questions.md index c78e1fe88..832561e15 100644 --- a/documentation/docs/frequently-asked-questions.md +++ b/documentation/docs/frequently-asked-questions.md @@ -209,7 +209,7 @@ var currentInteractionId = 0; final myUniqueOutputs = Map>(); void main() async { - MyUniqueOutput.rustSignalStream.listen((rustSignal) { + MyUniqueOutput.rustSignalStream.listen((rustSignal) { final myUniqueInput = rustSignal.message; myUniqueOutputs[myUniqueInput.interactionId]!.complete(myUniqueInput); }); From bed667c9ca50cfbc7993fc7dade31fdff1a8410d Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 01:07:21 +0900 Subject: [PATCH 110/128] Update old code and docs --- documentation/docs/frequently-asked-questions.md | 6 ++++-- .../example/native/hub/src/sample_functions.rs | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/documentation/docs/frequently-asked-questions.md b/documentation/docs/frequently-asked-questions.md index 832561e15..b404a74ba 100644 --- a/documentation/docs/frequently-asked-questions.md +++ b/documentation/docs/frequently-asked-questions.md @@ -233,10 +233,10 @@ onPressed: () async { ``` ```rust title="native/hub/src/sample_functions.rs" -pub async fn respond() { +pub async fn respond() -> Result<()> { use messages::tutorial_resource::*; - let mut receiver = MyUniqueInput::get_dart_signal_receiver(); + let mut receiver = MyUniqueInput::get_dart_signal_receiver()?; while let Some(dart_signal) = receiver.recv().await { let my_unique_input = dart_signal.message; MyUniqueOutput { @@ -245,6 +245,8 @@ pub async fn respond() { } .send_signal_to_dart(); } + + Ok(()) } ``` diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index 1177f83b4..80ff0ab70 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -108,14 +108,15 @@ pub async fn stream_fractal() { // A dummy function that uses sample messages to eliminate warnings. #[allow(dead_code)] -async fn use_messages() { +async fn use_messages() -> Result<()> { use messages::sample_folder::enum_and_oneof::*; - _ = SampleInput::get_dart_signal_receiver(); + let _ = SampleInput::get_dart_signal_receiver()?; SampleOutput { kind: 3, oneof_input: Some(sample_output::OneofInput::Age(25)), } - .send_signal_to_dart() + .send_signal_to_dart(); + Ok(()) } // Business logic for testing various crates. From 6d4a9fd2cc3d677b5a2b1a90d9a61800f1179fbd Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 21:21:27 +0900 Subject: [PATCH 111/128] Provide `RinfError` --- flutter_ffi_plugin/bin/src/message.dart | 61 +++++++++++++------------ rust_crate/src/common.rs | 3 -- rust_crate/src/error.rs | 43 +++++++++++++++++ rust_crate/src/interface.rs | 19 ++++---- rust_crate/src/interface_os.rs | 18 +++++--- rust_crate/src/interface_web.rs | 7 ++- rust_crate/src/lib.rs | 3 +- rust_crate/src/macros.rs | 13 ++++-- rust_crate/src/main.rs | 7 ++- 9 files changed, 114 insertions(+), 60 deletions(-) delete mode 100644 rust_crate/src/common.rs create mode 100644 rust_crate/src/error.rs diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 3aa6a836d..fccf6eff9 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -258,16 +258,14 @@ import 'package:rinf/rinf.dart'; rustPath, ''' #![allow(unused_imports)] -#![allow(dead_code)] use crate::tokio; use prost::Message; -use rinf::{send_rust_signal, DartSignal}; +use rinf::{send_rust_signal, DartSignal, RinfError}; use std::error::Error; use std::sync::Mutex; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; -type Result = std::result::Result>; ''', atFront: true, ); @@ -292,11 +290,11 @@ pub static ${snakeName.toUpperCase()}_CHANNEL: ${messageName}Cell = impl ${normalizePascal(messageName)} { pub fn get_dart_signal_receiver() - -> Result>> + -> Result>, RinfError> { let mut guard = ${snakeName.toUpperCase()}_CHANNEL .lock() - .map_err(|_| "Could not acquire the channel lock.")?; + .map_err(|_| RinfError::MessageReceiverTaken)?; if guard.is_none() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); @@ -308,7 +306,7 @@ impl ${normalizePascal(messageName)} { // which is now closed. let pair = guard .as_ref() - .ok_or("Message channel in Rust not present.")?; + .ok_or(RinfError::NoMessageChannel)?; if pair.0.is_closed() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); @@ -316,11 +314,11 @@ impl ${normalizePascal(messageName)} { } let pair = guard .take() - .ok_or("Message channel in Rust not present.")?; + .ok_or(RinfError::NoMessageChannel)?; guard.replace((pair.0, None)); let receiver = pair .1 - .ok_or("Each Dart signal receiver can be taken only once.")?; + .ok_or(RinfError::MessageReceiverTaken)?; Ok(receiver) } } @@ -382,11 +380,16 @@ final ${camelName}Controller = StreamController>(); ''' impl ${normalizePascal(messageName)} { pub fn send_signal_to_dart(&self) { - send_rust_signal( + let result = send_rust_signal( ${markedMessage.id}, self.encode_to_vec(), Vec::new(), ); + if let Err(error) = result { + println!("Could not send Rust signal."); + println!("{error:?}"); + println!("{self:?}"); + } } } ''', @@ -398,11 +401,16 @@ impl ${normalizePascal(messageName)} { ''' impl ${normalizePascal(messageName)} { pub fn send_signal_to_dart(&self, binary: Vec) { - send_rust_signal( + let result = send_rust_signal( ${markedMessage.id}, self.encode_to_vec(), binary, - ); + ); + if let Err(error) = result { + println!("Could not send Rust signal."); + println!("{error:?}"); + println!("{self:?}"); + } } } ''', @@ -421,17 +429,16 @@ impl ${normalizePascal(messageName)} { use crate::tokio; use prost::Message; use rinf::debug_print; -use rinf::DartSignal; +use rinf::{DartSignal, RinfError}; use std::collections::HashMap; use std::error::Error; use std::sync::OnceLock; use tokio::sync::mpsc::unbounded_channel; -type SignalHandlers = OnceLock< - HashMap Result<(), Box> + Send + Sync>>, ->; -static SIGNAL_HANDLERS: SignalHandlers = OnceLock::new(); +type Handler = dyn Fn(&[u8], &[u8]) -> Result<(), RinfError> + Send + Sync; +type SignalHandlers = HashMap>; +type SignalHandlersLock = OnceLock; +static SIGNAL_HANDLERS: SignalHandlersLock = OnceLock::new(); pub fn handle_dart_signal( message_id: i32, @@ -439,11 +446,7 @@ pub fn handle_dart_signal( binary: &[u8] ) { let hash_map = SIGNAL_HANDLERS.get_or_init(|| { - let mut new_hash_map = HashMap::< - i32, - Box Result<(), Box> + Send + Sync>, - >::new(); + let mut new_hash_map: SignalHandlers = HashMap::new(); '''; for (final entry in markedMessagesAll.entries) { final subpath = entry.key; @@ -464,14 +467,16 @@ new_hash_map.insert( ${markedMessage.id}, Box::new(|message_bytes: &[u8], binary: &[u8]| { use super::$modulePath$filename::*; - let message = ${normalizePascal(messageName)}::decode( - message_bytes - )?; + let message = + ${normalizePascal(messageName)}::decode(message_bytes) + .map_err(|_| RinfError::DecodeMessage)?; let dart_signal = DartSignal { message, binary: binary.to_vec(), }; - let mut guard = ${snakeName.toUpperCase()}_CHANNEL.lock()?; + let mut guard = ${snakeName.toUpperCase()}_CHANNEL + .lock() + .map_err(|_| RinfError::LockMessageChannel)?; if guard.is_none() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); @@ -483,7 +488,7 @@ new_hash_map.insert( // which is now closed. let pair = guard .as_ref() - .ok_or("Message channel in Rust not present.")?; + .ok_or(RinfError::NoMessageChannel)?; if pair.0.is_closed() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); @@ -491,7 +496,7 @@ new_hash_map.insert( } let pair = guard .as_ref() - .ok_or("Message channel in Rust not present.")?; + .ok_or(RinfError::NoMessageChannel)?; let sender = &pair.0; let _ = sender.send(dart_signal); Ok(()) diff --git a/rust_crate/src/common.rs b/rust_crate/src/common.rs deleted file mode 100644 index fa138cb41..000000000 --- a/rust_crate/src/common.rs +++ /dev/null @@ -1,3 +0,0 @@ -use std::error::Error; - -pub type Result = std::result::Result>; diff --git a/rust_crate/src/error.rs b/rust_crate/src/error.rs new file mode 100644 index 000000000..5ac2535b8 --- /dev/null +++ b/rust_crate/src/error.rs @@ -0,0 +1,43 @@ +use std::error::Error; +use std::fmt; + +#[derive(Debug)] +pub enum RinfError { + LockDartIsolate, + NoDartIsolate, + BuildRuntime, + LockMessageChannel, + NoMessageChannel, + MessageReceiverTaken, + DecodeMessage, +} + +impl fmt::Display for RinfError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RinfError::LockDartIsolate => { + write!(f, "Could not acquire the Dart isolate lock.") + } + RinfError::NoDartIsolate => { + write!(f, "Dart isolate for Rust signals was not created.") + } + RinfError::BuildRuntime => { + write!(f, "Could not build the tokio runtime.") + } + RinfError::LockMessageChannel => { + write!(f, "Could not acquire the message channel lock.") + } + RinfError::NoMessageChannel => { + write!(f, "Message channel was not created.",) + } + RinfError::MessageReceiverTaken => { + write!(f, "Each Dart signal receiver can be taken only once.") + } + RinfError::DecodeMessage => { + write!(f, "Could not decode the message.") + } + } + } +} + +impl Error for RinfError {} diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs index 880cf91e6..2bf3fe15e 100644 --- a/rust_crate/src/interface.rs +++ b/rust_crate/src/interface.rs @@ -1,4 +1,4 @@ -use crate::common::*; +use crate::error::RinfError; use std::future::Future; #[cfg(not(target_family = "wasm"))] @@ -26,7 +26,7 @@ pub struct DartSignal { /// the `Runtime` object itself might be moved between threads, /// along with all the tasks it manages. #[cfg(not(target_family = "wasm"))] -pub fn start_rust_logic(main_future: F) -> Result<()> +pub fn start_rust_logic(main_future: F) -> Result<(), RinfError> where F: Future + Send + 'static, { @@ -37,7 +37,7 @@ where /// On the web, futures usually don't implement the `Send` trait /// because JavaScript environment is fundamentally single-threaded. #[cfg(target_family = "wasm")] -pub fn start_rust_logic(main_future: F) -> Result<()> +pub fn start_rust_logic(main_future: F) -> Result<(), RinfError> where F: Future + 'static, { @@ -45,11 +45,10 @@ where } /// Send a signal to Dart. -pub fn send_rust_signal(message_id: i32, message_bytes: Vec, binary: Vec) { - let result = send_rust_signal_real(message_id, message_bytes, binary); - if let Err(error) = result { - // We cannot use `debug_print` here because - // it uses `send_rust_siganl` internally. - println!("Could not send Rust signal.\n{error:#?}"); - } +pub fn send_rust_signal( + message_id: i32, + message_bytes: Vec, + binary: Vec, +) -> Result<(), RinfError> { + send_rust_signal_real(message_id, message_bytes, binary) } diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index ea81574b9..9b3596cb8 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -1,4 +1,4 @@ -use crate::common::*; +use crate::error::RinfError; use allo_isolate::{IntoDart, Isolate, ZeroCopyBuffer}; use os_thread_local::ThreadLocal; use std::cell::RefCell; @@ -34,7 +34,7 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { type ShutdownSenderLock = OnceLock>>>; static SHUTDOWN_SENDER: ShutdownSenderLock = OnceLock::new(); -pub fn start_rust_logic_real(main_future: F) -> Result<()> +pub fn start_rust_logic_real(main_future: F) -> Result<(), RinfError> where F: Future + Send + 'static, { @@ -66,7 +66,10 @@ where // Build the tokio runtime. #[cfg(not(feature = "multi-worker"))] { - let tokio_runtime = Builder::new_current_thread().enable_all().build()?; + let tokio_runtime = Builder::new_current_thread() + .enable_all() + .build() + .map_err(|_| RinfError::BuildRuntime)?; thread::spawn(move || { tokio_runtime.spawn(main_future); tokio_runtime.block_on(shutdown_receiver); @@ -112,13 +115,16 @@ pub fn send_rust_signal_real( message_id: i32, message_bytes: Vec, binary: Vec, -) -> Result<()> { +) -> Result<(), RinfError> { // When `DART_ISOLATE` is not initialized, do nothing. // This can happen when running test code in Rust. - let guard = DART_ISOLATE.lock()?; + let guard = DART_ISOLATE + .lock() + .map_err(|_| RinfError::LockDartIsolate)?; let dart_isolate = guard .as_ref() - .ok_or("Dart isolate for sending Rust signals is not present.")?; + .ok_or("Dart isolate for sending Rust signals is not present.") + .map_err(|_| RinfError::NoDartIsolate)?; // If a `Vec` is empty, we can't just simply send it to Dart // because panic can occur from null pointers. diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index 9bb6e0f92..a32b0c4b2 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -1,10 +1,10 @@ -use crate::common::*; +use crate::error::RinfError; use js_sys::Uint8Array; use std::future::Future; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::spawn_local; -pub fn start_rust_logic_real(main_future: F) -> Result<()> +pub fn start_rust_logic_real(main_future: F) -> Result<(), RinfError> where F: Future + 'static, { @@ -32,12 +32,11 @@ pub fn send_rust_signal_real( message_id: i32, message_bytes: Vec, binary: Vec, -) -> Result<()> { +) -> Result<(), RinfError> { send_rust_signal_extern( message_id, js_sys::Uint8Array::from(message_bytes.as_slice()), js_sys::Uint8Array::from(binary.as_slice()), ); - Ok(()) } diff --git a/rust_crate/src/lib.rs b/rust_crate/src/lib.rs index 8d5a7d1b2..fae10f70c 100644 --- a/rust_crate/src/lib.rs +++ b/rust_crate/src/lib.rs @@ -1,4 +1,4 @@ -mod common; +mod error; mod macros; mod interface; @@ -7,4 +7,5 @@ mod interface_os; #[cfg(target_family = "wasm")] mod interface_web; +pub use error::*; pub use interface::*; diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index cdc5c8fd3..f5fde27f7 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -10,7 +10,8 @@ macro_rules! write_interface { pub extern "C" fn start_rust_logic_extern() { let result = $crate::start_rust_logic(main()); if let Err(error) = result { - println!("Could not start Rust logic.\n{error:#?}"); + println!("Could not start Rust logic."); + println!("{error:?}"); } } @@ -19,7 +20,8 @@ macro_rules! write_interface { pub fn start_rust_logic_extern() { let result = $crate::start_rust_logic(main()); if let Err(error) = result { - println!("Could not start Rust logic.\n{error:#?}"); + println!("Could not start Rust logic."); + println!("{error:?}"); } } @@ -59,11 +61,14 @@ macro_rules! debug_print { ( $( $t:tt )* ) => { let rust_report = format!( $( $t )* ); #[cfg(debug_assertions)] - $crate::send_rust_signal( + let result = $crate::send_rust_signal( -1, // This is a special message ID for Rust reports Vec::new(), - rust_report.into_bytes(), + rust_report.clone().into_bytes(), ); + if let Err(error) = result { + println!("Could not send Rust report.\n{error:?}\n{rust_report}"); + } #[cfg(not(debug_assertions))] let _ = rust_report; } diff --git a/rust_crate/src/main.rs b/rust_crate/src/main.rs index b6b615b7b..04cc7e74a 100644 --- a/rust_crate/src/main.rs +++ b/rust_crate/src/main.rs @@ -1,8 +1,7 @@ -mod common; -use common::*; +use std::error::Error; #[cfg(not(target_family = "wasm"))] -fn main() -> Result<()> { +fn main() -> Result<(), Box> { use std::env; use std::fs; use std::path; @@ -76,7 +75,7 @@ fn main() -> Result<()> { } #[cfg(target_family = "wasm")] -fn main() -> Result<()> { +fn main() -> Result<(), Box> { // Dummy function to make the linter happy. Ok(()) } From c3d7bfefd8eb0987052a0ebc331516a2736d38c0 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 21:42:39 +0900 Subject: [PATCH 112/128] Apply error print everywhere --- flutter_ffi_plugin/bin/src/message.dart | 24 +++++++----------------- rust_crate/src/error.rs | 4 ++++ rust_crate/src/interface_os.rs | 3 ++- rust_crate/src/macros.rs | 18 +++++++++++------- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index fccf6eff9..d87bdcb3f 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -261,7 +261,7 @@ import 'package:rinf/rinf.dart'; use crate::tokio; use prost::Message; -use rinf::{send_rust_signal, DartSignal, RinfError}; +use rinf::{debug_print, send_rust_signal, DartSignal, RinfError}; use std::error::Error; use std::sync::Mutex; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; @@ -386,9 +386,7 @@ impl ${normalizePascal(messageName)} { Vec::new(), ); if let Err(error) = result { - println!("Could not send Rust signal."); - println!("{error:?}"); - println!("{self:?}"); + debug_print!("{error}\n{self:?}"); } } } @@ -405,11 +403,9 @@ impl ${normalizePascal(messageName)} { ${markedMessage.id}, self.encode_to_vec(), binary, - ); + ); if let Err(error) = result { - println!("Could not send Rust signal."); - println!("{error:?}"); - println!("{self:?}"); + debug_print!("{error}\n{self:?}"); } } } @@ -444,7 +440,7 @@ pub fn handle_dart_signal( message_id: i32, message_bytes: &[u8], binary: &[u8] -) { +) -> Result<(), RinfError> { let hash_map = SIGNAL_HANDLERS.get_or_init(|| { let mut new_hash_map: SignalHandlers = HashMap::new(); '''; @@ -513,15 +509,9 @@ new_hash_map.insert( let signal_handler = match hash_map.get(&message_id) { Some(inner) => inner, - None => { - debug_print!("Message ID not found in the handler Hashmap."); - return; - } + None => return Err(RinfError::NoSignalHandler), }; - let result = signal_handler(message_bytes, binary); - if let Err(error) = result { - debug_print!("Could not process hashmap.\\n{error:#?}"); - } + signal_handler(message_bytes, binary) } '''; await File.fromUri(rustOutputPath.join('generated.rs')) diff --git a/rust_crate/src/error.rs b/rust_crate/src/error.rs index 5ac2535b8..c1d99107f 100644 --- a/rust_crate/src/error.rs +++ b/rust_crate/src/error.rs @@ -10,6 +10,7 @@ pub enum RinfError { NoMessageChannel, MessageReceiverTaken, DecodeMessage, + NoSignalHandler, } impl fmt::Display for RinfError { @@ -36,6 +37,9 @@ impl fmt::Display for RinfError { RinfError::DecodeMessage => { write!(f, "Could not decode the message.") } + RinfError::NoSignalHandler => { + write!(f, "Could not find the handler for Dart signal.") + } } } } diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 9b3596cb8..367d5458d 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -18,7 +18,8 @@ pub extern "C" fn prepare_isolate_extern(port: i64) { let mut guard = match DART_ISOLATE.lock() { Ok(inner) => inner, Err(_) => { - println!("Could not unlock Dart isolate mutex."); + let error = RinfError::LockDartIsolate; + println!("{error}"); return; } }; diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index f5fde27f7..c0349314e 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -10,8 +10,7 @@ macro_rules! write_interface { pub extern "C" fn start_rust_logic_extern() { let result = $crate::start_rust_logic(main()); if let Err(error) = result { - println!("Could not start Rust logic."); - println!("{error:?}"); + rinf::debug_print!("{error}"); } } @@ -20,8 +19,7 @@ macro_rules! write_interface { pub fn start_rust_logic_extern() { let result = $crate::start_rust_logic(main()); if let Err(error) = result { - println!("Could not start Rust logic."); - println!("{error:?}"); + rinf::debug_print!("{error}"); } } @@ -37,7 +35,10 @@ macro_rules! write_interface { use std::slice::from_raw_parts; let message_bytes = unsafe { from_raw_parts(message_pointer, message_size) }; let binary = unsafe { from_raw_parts(binary_pointer, binary_size) }; - messages::generated::handle_dart_signal(message_id, message_bytes, binary); + let result = messages::generated::handle_dart_signal(message_id, message_bytes, binary); + if let Err(error) = result { + rinf::debug_print!("{error}"); + } } #[cfg(target_family = "wasm")] @@ -45,7 +46,10 @@ macro_rules! write_interface { pub fn send_dart_signal_extern(message_id: i32, message_bytes: &[u8], binary: &[u8]) { let message_bytes = message_bytes; let binary = binary; - messages::generated::handle_dart_signal(message_id, message_bytes, binary); + let result = messages::generated::handle_dart_signal(message_id, message_bytes, binary); + if let Err(error) = result { + rinf::debug_print!("{error}"); + } } }; } @@ -67,7 +71,7 @@ macro_rules! debug_print { rust_report.clone().into_bytes(), ); if let Err(error) = result { - println!("Could not send Rust report.\n{error:?}\n{rust_report}"); + println!("{error}\n{rust_report}"); } #[cfg(not(debug_assertions))] let _ = rust_report; From 31855fb52cb5e5ad675eb8a4af288b77df0b0fd8 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 21:58:11 +0900 Subject: [PATCH 113/128] Put `ExampleError` in the sample crate --- .../native/hub/src/sample_functions.rs | 2 +- .../example/native/sample_crate/src/common.rs | 3 --- .../example/native/sample_crate/src/error.rs | 18 ++++++++++++++++++ .../native/sample_crate/src/fractal.rs | 7 ++++--- .../example/native/sample_crate/src/lib.rs | 19 +++++++++++++------ 5 files changed, 36 insertions(+), 13 deletions(-) delete mode 100644 flutter_ffi_plugin/example/native/sample_crate/src/common.rs create mode 100644 flutter_ffi_plugin/example/native/sample_crate/src/error.rs diff --git a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs index 80ff0ab70..44e3713c5 100755 --- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs +++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs @@ -91,7 +91,7 @@ pub async fn stream_fractal() { Ok(inner) => inner, Err(_) => continue, }; - if let Some(fractal_image) = received_frame { + if let Ok(fractal_image) = received_frame { // Stream the image data to Dart. SampleFractal { current_scale, diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/common.rs b/flutter_ffi_plugin/example/native/sample_crate/src/common.rs deleted file mode 100644 index c7a6d7bab..000000000 --- a/flutter_ffi_plugin/example/native/sample_crate/src/common.rs +++ /dev/null @@ -1,3 +0,0 @@ -use std::error::Error; - -pub type Result = std::result::Result>; diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/error.rs b/flutter_ffi_plugin/example/native/sample_crate/src/error.rs new file mode 100644 index 000000000..94fd4ff8b --- /dev/null +++ b/flutter_ffi_plugin/example/native/sample_crate/src/error.rs @@ -0,0 +1,18 @@ +use std::error::Error; +use std::fmt; + +#[derive(Debug)] +pub struct ExampleError(pub Box); + +impl fmt::Display for ExampleError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let source = self.0.as_ref(); + write!(f, "An error occured inside the example code.\n{source}") + } +} + +impl Error for ExampleError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + Some(self.0.as_ref()) + } +} diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/fractal.rs b/flutter_ffi_plugin/example/native/sample_crate/src/fractal.rs index f23053c9a..af555c975 100644 --- a/flutter_ffi_plugin/example/native/sample_crate/src/fractal.rs +++ b/flutter_ffi_plugin/example/native/sample_crate/src/fractal.rs @@ -2,6 +2,7 @@ //! Copied and modified from //! https://github.com/abour/fractal repository. +use crate::error::ExampleError; use image::ImageEncoder; const WIDTH: u32 = 384; @@ -10,7 +11,7 @@ const BUF_SIZE: u32 = WIDTH * HEIGHT * 3; const SIZE: f64 = 0.000000001; const MAX_ITER: u32 = 1000; -pub fn draw_fractal_image(scale: f64) -> Option> { +pub fn draw_fractal_image(scale: f64) -> Result, ExampleError> { let point_x: f64 = -0.5557506; let point_y: f64 = -0.55560; let mut buffer: Vec = vec![0; BUF_SIZE as usize]; @@ -27,8 +28,8 @@ pub fn draw_fractal_image(scale: f64) -> Option> { ); match result { - Ok(_) => Some(image_data), - Err(_) => None, + Ok(_) => Ok(image_data), + Err(error) => Err(ExampleError(error.into())), } } diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs index aab1573ba..8557e2931 100755 --- a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs +++ b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs @@ -1,20 +1,22 @@ //! This crate is written for Rinf demonstrations. -mod common; +mod error; mod fractal; -use common::*; +use error::ExampleError; pub use fractal::draw_fractal_image; // `machineid_rs` only supports desktop platforms. #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] -pub fn get_hardward_id() -> Result { +pub fn get_hardward_id() -> Result { let mut builder = machineid_rs::IdBuilder::new(machineid_rs::Encryption::MD5); builder .add_component(machineid_rs::HWIDComponent::SystemID) .add_component(machineid_rs::HWIDComponent::CPUCores); - let hwid = builder.build("mykey")?; + let hwid = builder + .build("mykey") + .map_err(|error| ExampleError(error.into()))?; Ok(hwid) } #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] @@ -29,7 +31,12 @@ pub fn get_current_time() -> DateTime { } // `reqwest` supports all platforms, including web. -pub async fn fetch_from_web_api(url: &str) -> Result { - let fetched = reqwest::get(url).await?.text().await?; +pub async fn fetch_from_web_api(url: &str) -> Result { + let fetched = reqwest::get(url) + .await + .map_err(|error| ExampleError(error.into()))? + .text() + .await + .map_err(|error| ExampleError(error.into()))?; Ok(fetched) } From 1a78af3d6125e444f20958661b760da42476d5dd Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:04:14 +0900 Subject: [PATCH 114/128] Remove unused import --- flutter_ffi_plugin/bin/src/message.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index d87bdcb3f..cea5ee8e9 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -262,7 +262,6 @@ import 'package:rinf/rinf.dart'; use crate::tokio; use prost::Message; use rinf::{debug_print, send_rust_signal, DartSignal, RinfError}; -use std::error::Error; use std::sync::Mutex; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; From d640318f02bf7f0c603a35792ac68e16075ac493 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:07:49 +0900 Subject: [PATCH 115/128] Organize imports --- flutter_ffi_plugin/bin/src/message.dart | 3 +-- rust_crate/src/main.rs | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index cea5ee8e9..826a0277c 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -423,8 +423,7 @@ impl ${normalizePascal(messageName)} { use crate::tokio; use prost::Message; -use rinf::debug_print; -use rinf::{DartSignal, RinfError}; +use rinf::{debug_print, DartSignal, RinfError}; use std::collections::HashMap; use std::error::Error; use std::sync::OnceLock; diff --git a/rust_crate/src/main.rs b/rust_crate/src/main.rs index 04cc7e74a..108cef1ef 100644 --- a/rust_crate/src/main.rs +++ b/rust_crate/src/main.rs @@ -1,7 +1,5 @@ -use std::error::Error; - #[cfg(not(target_family = "wasm"))] -fn main() -> Result<(), Box> { +fn main() -> Result<(), Box> { use std::env; use std::fs; use std::path; @@ -75,7 +73,7 @@ fn main() -> Result<(), Box> { } #[cfg(target_family = "wasm")] -fn main() -> Result<(), Box> { +fn main() -> Result<(), Box> { // Dummy function to make the linter happy. Ok(()) } From dfc8324dc0866a6991052af4903338df4cc367f9 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:10:16 +0900 Subject: [PATCH 116/128] Simplify generated message code --- flutter_ffi_plugin/bin/src/message.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 826a0277c..a5fce550e 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -431,8 +431,7 @@ use tokio::sync::mpsc::unbounded_channel; type Handler = dyn Fn(&[u8], &[u8]) -> Result<(), RinfError> + Send + Sync; type SignalHandlers = HashMap>; -type SignalHandlersLock = OnceLock; -static SIGNAL_HANDLERS: SignalHandlersLock = OnceLock::new(); +static SIGNAL_HANDLERS: OnceLock = OnceLock::new(); pub fn handle_dart_signal( message_id: i32, From 1ffe3c59ccc7974404d7ce999003645283fba75f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:16:10 +0900 Subject: [PATCH 117/128] Fix a type mismatch in `multi-worker` feature --- rust_crate/src/interface_os.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 367d5458d..e7424a9ca 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -81,7 +81,10 @@ where #[cfg(feature = "multi-worker")] { static TOKIO_RUNTIME: Mutex> = Mutex::new(None); - let tokio_runtime = Builder::new_multi_thread().enable_all().build()?; + let tokio_runtime = Builder::new_multi_thread() + .enable_all() + .build() + .map_err(|_| RinfError::BuildRuntime)?; tokio_runtime.spawn(async { main_future.await; }); From cfe598a4fe39fb5c92ebc1707bb8c1a43ebb52c8 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:20:44 +0900 Subject: [PATCH 118/128] Remove unneeded error conversion --- rust_crate/src/interface_os.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index e7424a9ca..dfb078993 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -120,15 +120,12 @@ pub fn send_rust_signal_real( message_bytes: Vec, binary: Vec, ) -> Result<(), RinfError> { - // When `DART_ISOLATE` is not initialized, do nothing. + // When `DART_ISOLATE` is not initialized, just return the error. // This can happen when running test code in Rust. let guard = DART_ISOLATE .lock() .map_err(|_| RinfError::LockDartIsolate)?; - let dart_isolate = guard - .as_ref() - .ok_or("Dart isolate for sending Rust signals is not present.") - .map_err(|_| RinfError::NoDartIsolate)?; + let dart_isolate = guard.as_ref().ok_or(RinfError::NoDartIsolate)?; // If a `Vec` is empty, we can't just simply send it to Dart // because panic can occur from null pointers. From 16d035f4c41d22d9d4a7ccfd5c361322bca9263e Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:29:24 +0900 Subject: [PATCH 119/128] Check with Clippy with all features enabled --- .github/workflows/quality_control.yaml | 6 +++++- rust_crate/src/interface_os.rs | 5 +---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/quality_control.yaml b/.github/workflows/quality_control.yaml index 88b8d33b6..89d1e5aab 100644 --- a/.github/workflows/quality_control.yaml +++ b/.github/workflows/quality_control.yaml @@ -54,7 +54,7 @@ jobs: working-directory: flutter_ffi_plugin/example/ run: rinf message - - name: Check for any errors + - name: Check for errors in various targets run: | rustup target add wasm32-unknown-unknown cargo clippy @@ -62,6 +62,10 @@ jobs: cargo clippy --target wasm32-unknown-unknown cargo clippy --target wasm32-unknown-unknown --release + - name: Check for errors with all features enabled + working-directory: flutter_ffi_plugin/example/native/hub + run: cargo clippy --all-features + - name: Analyze code run: | dart analyze flutter_ffi_plugin --fatal-infos diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index dfb078993..fe842e05e 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -67,10 +67,7 @@ where // Build the tokio runtime. #[cfg(not(feature = "multi-worker"))] { - let tokio_runtime = Builder::new_current_thread() - .enable_all() - .build() - .map_err(|_| RinfError::BuildRuntime)?; + let tokio_runtime = Builder::new_current_thread().enable_all().build()?; thread::spawn(move || { tokio_runtime.spawn(main_future); tokio_runtime.block_on(shutdown_receiver); From 26b9a0e2330be1708f1136a0a934fa9821eac137 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:32:06 +0900 Subject: [PATCH 120/128] Switch the feature to test CI --- rust_crate/src/interface_os.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index fe842e05e..37bfab88c 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -67,7 +67,10 @@ where // Build the tokio runtime. #[cfg(not(feature = "multi-worker"))] { - let tokio_runtime = Builder::new_current_thread().enable_all().build()?; + let tokio_runtime = Builder::new_current_thread() + .enable_all() + .build() + .map_err(|_| RinfError::BuildRuntime)?; thread::spawn(move || { tokio_runtime.spawn(main_future); tokio_runtime.block_on(shutdown_receiver); @@ -78,10 +81,7 @@ where #[cfg(feature = "multi-worker")] { static TOKIO_RUNTIME: Mutex> = Mutex::new(None); - let tokio_runtime = Builder::new_multi_thread() - .enable_all() - .build() - .map_err(|_| RinfError::BuildRuntime)?; + let tokio_runtime = Builder::new_multi_thread().enable_all().build()?; tokio_runtime.spawn(async { main_future.await; }); From a947a9d14005d0d959f0a87611195d5f6241c491 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:39:55 +0900 Subject: [PATCH 121/128] Fix a problem with newline character in generated msg code --- flutter_ffi_plugin/bin/src/message.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index a5fce550e..e1091e8c4 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -385,7 +385,7 @@ impl ${normalizePascal(messageName)} { Vec::new(), ); if let Err(error) = result { - debug_print!("{error}\n{self:?}"); + debug_print!("{error}\\n{self:?}"); } } } @@ -404,7 +404,7 @@ impl ${normalizePascal(messageName)} { binary, ); if let Err(error) = result { - debug_print!("{error}\n{self:?}"); + debug_print!("{error}\\n{self:?}"); } } } From d01b571080bf7ace7f45d18ea548cc40386c9989 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:48:04 +0900 Subject: [PATCH 122/128] Fix broken `debug_print` in release mode --- rust_crate/src/macros.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs index c0349314e..d6042b236 100644 --- a/rust_crate/src/macros.rs +++ b/rust_crate/src/macros.rs @@ -65,13 +65,15 @@ macro_rules! debug_print { ( $( $t:tt )* ) => { let rust_report = format!( $( $t )* ); #[cfg(debug_assertions)] - let result = $crate::send_rust_signal( - -1, // This is a special message ID for Rust reports - Vec::new(), - rust_report.clone().into_bytes(), - ); - if let Err(error) = result { - println!("{error}\n{rust_report}"); + { + let result = $crate::send_rust_signal( + -1, // This is a special message ID for Rust reports + Vec::new(), + rust_report.clone().into_bytes(), + ); + if let Err(error) = result { + println!("{error}\n{rust_report}"); + } } #[cfg(not(debug_assertions))] let _ = rust_report; From 8d738ab97d7f3e4fdcef6818dc7201c205bfe5b3 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:52:58 +0900 Subject: [PATCH 123/128] Fix type mismatch betweehn platforms --- flutter_ffi_plugin/example/native/sample_crate/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs index 8557e2931..431353466 100755 --- a/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs +++ b/flutter_ffi_plugin/example/native/sample_crate/src/lib.rs @@ -20,7 +20,7 @@ pub fn get_hardward_id() -> Result { Ok(hwid) } #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] -pub fn get_hardward_id() -> Result { +pub fn get_hardward_id() -> Result { Ok(String::from("UNSUPPORTED")) } From d6affccd7c505f8da3f95d910790678ca433d9ab Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 22:58:50 +0900 Subject: [PATCH 124/128] Check all features inside the library crate --- .github/workflows/quality_control.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/quality_control.yaml b/.github/workflows/quality_control.yaml index 89d1e5aab..9051d3da4 100644 --- a/.github/workflows/quality_control.yaml +++ b/.github/workflows/quality_control.yaml @@ -54,6 +54,8 @@ jobs: working-directory: flutter_ffi_plugin/example/ run: rinf message + # Targets are basically combinations of + # web/native and debug/release. - name: Check for errors in various targets run: | rustup target add wasm32-unknown-unknown @@ -62,8 +64,10 @@ jobs: cargo clippy --target wasm32-unknown-unknown cargo clippy --target wasm32-unknown-unknown --release + # The `--all-features` flag doesn't work for the entire workspace. + # That's why we are checking only the library crate. - name: Check for errors with all features enabled - working-directory: flutter_ffi_plugin/example/native/hub + working-directory: rust_crate/ run: cargo clippy --all-features - name: Analyze code From 10d7203efa9ece92c308dc5ebffaa139a61a19c6 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 23:06:24 +0900 Subject: [PATCH 125/128] Make the CI happy with all features enabled --- rust_crate/src/interface_os.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs index 37bfab88c..dfb078993 100644 --- a/rust_crate/src/interface_os.rs +++ b/rust_crate/src/interface_os.rs @@ -81,7 +81,10 @@ where #[cfg(feature = "multi-worker")] { static TOKIO_RUNTIME: Mutex> = Mutex::new(None); - let tokio_runtime = Builder::new_multi_thread().enable_all().build()?; + let tokio_runtime = Builder::new_multi_thread() + .enable_all() + .build() + .map_err(|_| RinfError::BuildRuntime)?; tokio_runtime.spawn(async { main_future.await; }); From 531b4ce5b3db2c1c8c36c16cc73e80eb6e6fd7db Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Tue, 18 Jun 2024 23:14:23 +0900 Subject: [PATCH 126/128] Fix an inappropriate error return type --- flutter_ffi_plugin/bin/src/message.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index e1091e8c4..7854f517e 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -293,7 +293,7 @@ impl ${normalizePascal(messageName)} { { let mut guard = ${snakeName.toUpperCase()}_CHANNEL .lock() - .map_err(|_| RinfError::MessageReceiverTaken)?; + .map_err(|_| RinfError::LockMessageChannel)?; if guard.is_none() { let (sender, receiver) = unbounded_channel(); guard.replace((sender, Some(receiver))); From b157f17d606a4a2030cea7fa148f2e385116d235 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Wed, 19 Jun 2024 01:25:40 +0900 Subject: [PATCH 127/128] Update first code snippet --- README.md | 1 + flutter_ffi_plugin/README.md | 1 + rust_crate/README.md | 1 + 3 files changed, 3 insertions(+) diff --git a/README.md b/README.md index bb8eca3a0..7103cd9b7 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ StreamBuilder( ```rust MyMessage { current_number: 7, + other_bool: true, } .send_signal_to_dart() ``` diff --git a/flutter_ffi_plugin/README.md b/flutter_ffi_plugin/README.md index bb8eca3a0..7103cd9b7 100644 --- a/flutter_ffi_plugin/README.md +++ b/flutter_ffi_plugin/README.md @@ -48,6 +48,7 @@ StreamBuilder( ```rust MyMessage { current_number: 7, + other_bool: true, } .send_signal_to_dart() ``` diff --git a/rust_crate/README.md b/rust_crate/README.md index bb8eca3a0..7103cd9b7 100644 --- a/rust_crate/README.md +++ b/rust_crate/README.md @@ -48,6 +48,7 @@ StreamBuilder( ```rust MyMessage { current_number: 7, + other_bool: true, } .send_signal_to_dart() ``` From 1a38f7108810228f2c507280aa1b4df5fda0a7f5 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Wed, 19 Jun 2024 01:38:14 +0900 Subject: [PATCH 128/128] Make the first code snippets look more real --- README.md | 4 ++-- flutter_ffi_plugin/README.md | 4 ++-- rust_crate/README.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7103cd9b7..f409ef9c8 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ StreamBuilder( final myMessage = rustSignal.message; return Text(myMessage.currentNumber.toString()); }, -) +), ``` ```rust @@ -50,7 +50,7 @@ MyMessage { current_number: 7, other_bool: true, } -.send_signal_to_dart() +.send_signal_to_dart(); ``` Of course, the opposite way from Dart to Rust is also possible in a similar manner. diff --git a/flutter_ffi_plugin/README.md b/flutter_ffi_plugin/README.md index 7103cd9b7..f409ef9c8 100644 --- a/flutter_ffi_plugin/README.md +++ b/flutter_ffi_plugin/README.md @@ -42,7 +42,7 @@ StreamBuilder( final myMessage = rustSignal.message; return Text(myMessage.currentNumber.toString()); }, -) +), ``` ```rust @@ -50,7 +50,7 @@ MyMessage { current_number: 7, other_bool: true, } -.send_signal_to_dart() +.send_signal_to_dart(); ``` Of course, the opposite way from Dart to Rust is also possible in a similar manner. diff --git a/rust_crate/README.md b/rust_crate/README.md index 7103cd9b7..f409ef9c8 100644 --- a/rust_crate/README.md +++ b/rust_crate/README.md @@ -42,7 +42,7 @@ StreamBuilder( final myMessage = rustSignal.message; return Text(myMessage.currentNumber.toString()); }, -) +), ``` ```rust @@ -50,7 +50,7 @@ MyMessage { current_number: 7, other_bool: true, } -.send_signal_to_dart() +.send_signal_to_dart(); ``` Of course, the opposite way from Dart to Rust is also possible in a similar manner.