From cf5a3dae7b4c9d7b2003f643ce7198a11bfd8583 Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 01:09:40 +0900
Subject: [PATCH 01/12] Provide `write_interface!` macro
---
documentation/docs/tutorial.md | 2 +-
documentation/docs/writing-code.md | 2 +-
flutter_ffi_plugin/bin/src/message.dart | 6 +-
.../example/native/hub/Cargo.toml | 3 +-
.../native/hub/src/bridge/interface_os.rs | 119 ------------
.../native/hub/src/bridge/interface_web.rs | 64 -------
.../example/native/hub/src/bridge/mod.rs | 12 --
.../example/native/hub/src/lib.rs | 4 +-
.../native/hub/src/sample_functions.rs | 2 +-
rust_crate/Cargo.toml | 2 +
.../bridge => rust_crate/src}/interface.rs | 29 +--
rust_crate/src/interface_os.rs | 41 ++++
rust_crate/src/interface_web.rs | 27 +++
rust_crate/src/lib.rs | 9 +
rust_crate/src/macros.rs | 180 ++++++++++++++++++
15 files changed, 273 insertions(+), 229 deletions(-)
delete mode 100644 flutter_ffi_plugin/example/native/hub/src/bridge/interface_os.rs
delete mode 100644 flutter_ffi_plugin/example/native/hub/src/bridge/interface_web.rs
delete mode 100755 flutter_ffi_plugin/example/native/hub/src/bridge/mod.rs
rename {flutter_ffi_plugin/example/native/hub/src/bridge => rust_crate/src}/interface.rs (53%)
create mode 100644 rust_crate/src/interface_os.rs
create mode 100644 rust_crate/src/interface_web.rs
create mode 100644 rust_crate/src/macros.rs
diff --git a/documentation/docs/tutorial.md b/documentation/docs/tutorial.md
index e0ea691e..40cd0ec1 100644
--- a/documentation/docs/tutorial.md
+++ b/documentation/docs/tutorial.md
@@ -61,8 +61,8 @@ Let's listen to this message in Rust. This simple function will add one to each
```rust title="native/hub/src/sample_functions.rs"
...
-use crate::debug_print;
use crate::messages;
+use rinf::debug_print;
...
pub async fn calculate_precious_data() {
use messages::tutorial_resource::*;
diff --git a/documentation/docs/writing-code.md b/documentation/docs/writing-code.md
index fbeee24e..eb16e044 100644
--- a/documentation/docs/writing-code.md
+++ b/documentation/docs/writing-code.md
@@ -61,7 +61,7 @@ You might be used to `println!` macro in Rust. However, using that macro isn't a
When writing Rust code in the `hub` crate, you can simply print your debug message with the `debug_print!` macro provided by this framework like below. Once you use this macro, Flutter will take care of the rest.
```rust title="Rust"
-use crate::debug_print;
+use rinf::debug_print;
debug_print!("My object is {my_object:?}");
```
diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart
index fb2bea8d..7ab4f78e 100644
--- a/flutter_ffi_plugin/bin/src/message.dart
+++ b/flutter_ffi_plugin/bin/src/message.dart
@@ -209,9 +209,11 @@ import 'package:rinf/rinf.dart';
'''
#![allow(unused_imports)]
-use crate::bridge::*;
use crate::tokio;
use prost::Message;
+use rinf::send_rust_signal;
+use rinf::DartSignal;
+use rinf::SharedCell;
use std::cell::RefCell;
use std::sync::Mutex;
use std::sync::OnceLock;
@@ -303,8 +305,8 @@ impl ${normalizePascal(messageName)} {
#![allow(unused_imports)]
#![allow(unused_variables)]
-use crate::bridge::*;
use prost::Message;
+use rinf::DartSignal;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::Mutex;
diff --git a/flutter_ffi_plugin/example/native/hub/Cargo.toml b/flutter_ffi_plugin/example/native/hub/Cargo.toml
index 337fb352..41731ad7 100755
--- a/flutter_ffi_plugin/example/native/hub/Cargo.toml
+++ b/flutter_ffi_plugin/example/native/hub/Cargo.toml
@@ -13,8 +13,7 @@ crate-type = ["lib", "cdylib", "staticlib"]
[dependencies]
rinf = "6.2.0"
-allo-isolate = "0.1.24"
-wasm-bindgen = "0.2.90"
prost = "0.12.3"
+wasm-bindgen = "0.2.90"
tokio_with_wasm = "0.4.0"
sample_crate = { path = "../sample_crate" }
diff --git a/flutter_ffi_plugin/example/native/hub/src/bridge/interface_os.rs b/flutter_ffi_plugin/example/native/hub/src/bridge/interface_os.rs
deleted file mode 100644
index de93bdeb..00000000
--- a/flutter_ffi_plugin/example/native/hub/src/bridge/interface_os.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-use super::SharedCell;
-use crate::tokio::runtime::Builder;
-use crate::tokio::runtime::Runtime;
-use allo_isolate::IntoDart;
-use allo_isolate::Isolate;
-use allo_isolate::ZeroCopyBuffer;
-use rinf::externs::os_thread_local::ThreadLocal;
-use std::cell::RefCell;
-use std::panic::catch_unwind;
-use std::sync::Mutex;
-use std::sync::OnceLock;
-
-static DART_ISOLATE: SharedCell = 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)))
- .lock()
- .unwrap();
- cell.replace(Some(dart_isolate));
- });
-}
-
-// 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();
-
-#[no_mangle]
-pub extern "C" fn start_rust_logic_extern() {
- let _ = catch_unwind(|| {
- // Enable backtrace output for panics.
- #[cfg(debug_assertions)]
- {
- use crate::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());
- 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));
- });
- });
-}
-
-#[no_mangle]
-pub extern "C" fn stop_rust_logic_extern() {
- let _ = catch_unwind(|| {
- 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(None);
- });
- });
-}
-
-#[no_mangle]
-pub extern "C" fn send_dart_signal_extern(
- message_id: i64,
- message_pointer: *const u8,
- message_size: usize,
- blob_valid: bool,
- blob_pointer: *const u8,
- blob_size: usize,
-) {
- let message_bytes =
- unsafe { Vec::from_raw_parts(message_pointer as *mut u8, message_size, message_size) };
- let blob = if blob_valid {
- unsafe {
- Some(Vec::from_raw_parts(
- blob_pointer as *mut u8,
- blob_size,
- blob_size,
- ))
- }
- } else {
- None
- };
- let _ = catch_unwind(|| {
- crate::messages::generated::handle_dart_signal(message_id as i32, message_bytes, blob);
- });
-}
-
-pub fn send_rust_signal_extern(
- message_id: i32,
- message_bytes: Vec,
- blob_valid: bool,
- blob_bytes: Vec,
-) {
- let cell = DART_ISOLATE.get().unwrap().lock().unwrap();
- let dart_isolate = cell.borrow().unwrap();
- dart_isolate.post(
- vec![
- message_id.into_dart(),
- ZeroCopyBuffer(message_bytes).into_dart(),
- blob_valid.into_dart(),
- ZeroCopyBuffer(blob_bytes).into_dart(),
- ]
- .into_dart(),
- );
-}
diff --git a/flutter_ffi_plugin/example/native/hub/src/bridge/interface_web.rs b/flutter_ffi_plugin/example/native/hub/src/bridge/interface_web.rs
deleted file mode 100644
index d474d9e0..00000000
--- a/flutter_ffi_plugin/example/native/hub/src/bridge/interface_web.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use crate::tokio;
-use rinf::externs::js_sys::Uint8Array;
-use std::panic::catch_unwind;
-use wasm_bindgen::prelude::*;
-
-#[wasm_bindgen]
-pub fn start_rust_logic_extern() {
- let _ = catch_unwind(|| {
- // Add kind description for panics.
- #[cfg(debug_assertions)]
- {
- use crate::debug_print;
- std::panic::set_hook(Box::new(|panic_info| {
- debug_print!("A panic occurred in Rust.\n{panic_info}");
- }));
- }
-
- // Run the main function.
- tokio::spawn(crate::main());
- });
-}
-
-#[wasm_bindgen]
-pub fn send_dart_signal_extern(
- message_id: i32,
- message_bytes: &[u8],
- blob_valid: bool,
- blob_bytes: &[u8],
-) {
- let message_bytes = message_bytes.to_vec();
- let blob = if blob_valid {
- Some(blob_bytes.to_vec())
- } else {
- None
- };
- let _ = catch_unwind(|| {
- crate::messages::generated::handle_dart_signal(message_id, message_bytes, blob);
- });
-}
-
-#[wasm_bindgen]
-extern "C" {
- #[wasm_bindgen(js_name = rinf_send_rust_signal_extern)]
- pub fn send_rust_signal_extern_raw(
- resource: i32,
- message_bytes: Uint8Array,
- blob_valid: bool,
- blob_bytes: Uint8Array,
- );
-}
-
-pub fn send_rust_signal_extern(
- message_id: i32,
- message_bytes: Vec,
- blob_valid: bool,
- blob_bytes: Vec,
-) {
- send_rust_signal_extern_raw(
- message_id,
- rinf::externs::js_sys::Uint8Array::from(message_bytes.as_slice()),
- blob_valid,
- rinf::externs::js_sys::Uint8Array::from(blob_bytes.as_slice()),
- );
-}
diff --git a/flutter_ffi_plugin/example/native/hub/src/bridge/mod.rs b/flutter_ffi_plugin/example/native/hub/src/bridge/mod.rs
deleted file mode 100755
index b576747b..00000000
--- a/flutter_ffi_plugin/example/native/hub/src/bridge/mod.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//! This module supports communication with Dart.
-//! DO NOT EDIT.
-
-#![allow(dead_code)]
-
-mod interface;
-pub use interface::*;
-
-#[cfg(not(target_family = "wasm"))]
-mod interface_os;
-#[cfg(target_family = "wasm")]
-mod interface_web;
diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs
index b3cd8582..b4ebe2f1 100755
--- a/flutter_ffi_plugin/example/native/hub/src/lib.rs
+++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs
@@ -1,9 +1,11 @@
+// This `tokio` will be used by Rinf.
use tokio_with_wasm::tokio;
-mod bridge;
mod messages;
mod sample_functions;
+rinf::write_interface!();
+
/// This `hub` crate is the entry point for the Rust logic.
/// Always use non-blocking async functions such as `tokio::fs::File::open`.
async fn main() {
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 9b3ed317..25e72299 100755
--- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs
+++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs
@@ -1,9 +1,9 @@
//! This module is only for Rinf demonstrations.
//! You might want to remove this module in production.
-use crate::debug_print;
use crate::messages;
use crate::tokio;
+use rinf::debug_print;
const SHOULD_DEMONSTRATE: bool = true; // Disabled when applied as template
diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml
index 188f5d4f..83d4de40 100644
--- a/rust_crate/Cargo.toml
+++ b/rust_crate/Cargo.toml
@@ -14,6 +14,8 @@ backtrace = "0.3.69"
protoc-prebuilt = "0.2.0"
home = "0.5.9"
which = "6.0.0"
+allo-isolate = "0.1.24"
[target.'cfg(target_family = "wasm")'.dependencies]
js-sys = "0.3.67"
+wasm-bindgen = "0.2.90"
diff --git a/flutter_ffi_plugin/example/native/hub/src/bridge/interface.rs b/rust_crate/src/interface.rs
similarity index 53%
rename from flutter_ffi_plugin/example/native/hub/src/bridge/interface.rs
rename to rust_crate/src/interface.rs
index 4398ec94..9c861908 100644
--- a/flutter_ffi_plugin/example/native/hub/src/bridge/interface.rs
+++ b/rust_crate/src/interface.rs
@@ -1,5 +1,3 @@
-#![allow(dead_code)]
-
use std::cell::RefCell;
use std::sync::Mutex;
use std::sync::OnceLock;
@@ -9,6 +7,9 @@ pub use super::interface_os::*;
#[cfg(target_family = "wasm")]
pub use super::interface_web::*;
+/// This is a mutable cell type that can be shared across threads.
+pub type SharedCell = OnceLock>>>;
+
/// This contains a message from Dart.
/// Optionally, a custom binary called `blob` can also be included.
/// This type is generic, and the message
@@ -18,9 +19,6 @@ pub struct DartSignal {
pub blob: Option>,
}
-/// This is a mutable cell type that can be shared across threads.
-pub type SharedCell = OnceLock>>>;
-
/// Send a signal to Dart.
pub fn send_rust_signal(message_id: i32, message_bytes: Vec, blob: Option>) {
send_rust_signal_extern(
@@ -30,24 +28,3 @@ pub fn send_rust_signal(message_id: i32, message_bytes: Vec, blob: Option {
- let rust_report = format!( $( $t )* );
- #[cfg(debug_assertions)]
- $crate::bridge::send_rust_signal(
- -1, // This is a special message ID for Rust reports
- Vec::new(),
- Some(rust_report.into_bytes()),
- );
- #[cfg(not(debug_assertions))]
- let _ = rust_report;
- }
-}
diff --git a/rust_crate/src/interface_os.rs b/rust_crate/src/interface_os.rs
new file mode 100644
index 00000000..3f55c1d4
--- /dev/null
+++ b/rust_crate/src/interface_os.rs
@@ -0,0 +1,41 @@
+use super::SharedCell;
+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();
+
+#[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)))
+ .lock()
+ .unwrap();
+ cell.replace(Some(dart_isolate));
+ });
+}
+
+pub fn send_rust_signal_extern(
+ message_id: i32,
+ message_bytes: Vec,
+ blob_valid: bool,
+ blob_bytes: Vec,
+) {
+ let cell = DART_ISOLATE.get().unwrap().lock().unwrap();
+ let dart_isolate = cell.borrow().unwrap();
+ dart_isolate.post(
+ vec![
+ message_id.into_dart(),
+ ZeroCopyBuffer(message_bytes).into_dart(),
+ blob_valid.into_dart(),
+ ZeroCopyBuffer(blob_bytes).into_dart(),
+ ]
+ .into_dart(),
+ );
+}
diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs
new file mode 100644
index 00000000..43fb427e
--- /dev/null
+++ b/rust_crate/src/interface_web.rs
@@ -0,0 +1,27 @@
+use js_sys::Uint8Array;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen]
+extern "C" {
+ #[wasm_bindgen(js_name = rinf_send_rust_signal_extern)]
+ pub fn send_rust_signal_extern_raw(
+ resource: i32,
+ message_bytes: Uint8Array,
+ blob_valid: bool,
+ blob_bytes: Uint8Array,
+ );
+}
+
+pub fn send_rust_signal_extern(
+ message_id: i32,
+ message_bytes: Vec,
+ blob_valid: bool,
+ blob_bytes: Vec,
+) {
+ send_rust_signal_extern_raw(
+ message_id,
+ js_sys::Uint8Array::from(message_bytes.as_slice()),
+ blob_valid,
+ js_sys::Uint8Array::from(blob_bytes.as_slice()),
+ );
+}
diff --git a/rust_crate/src/lib.rs b/rust_crate/src/lib.rs
index a17c6134..a7c1ed28 100644
--- a/rust_crate/src/lib.rs
+++ b/rust_crate/src/lib.rs
@@ -1 +1,10 @@
+pub use interface::*;
+pub use macros::*;
+
pub mod externs;
+mod interface;
+#[cfg(not(target_family = "wasm"))]
+mod interface_os;
+#[cfg(target_family = "wasm")]
+mod interface_web;
+mod macros;
diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs
new file mode 100644
index 00000000..3299350a
--- /dev/null
+++ b/rust_crate/src/macros.rs
@@ -0,0 +1,180 @@
+#![allow(clippy::crate_in_macro_def)]
+
+#[macro_export]
+/// Writes the interface code
+/// needed to communicate with Dart.
+/// This should be used once, and only once,
+/// at the root of the `hub` crate.
+macro_rules! write_interface {
+ () => {
+ mod interface {
+ #[cfg(not(target_family = "wasm"))]
+ pub use interface_os::*;
+ #[cfg(target_family = "wasm")]
+ pub use interface_web::*;
+
+ #[cfg(not(target_family = "wasm"))]
+ mod interface_os {
+
+ use crate::tokio::runtime::Builder;
+ use crate::tokio::runtime::Runtime;
+ use rinf::externs::os_thread_local::ThreadLocal;
+ use std::cell::RefCell;
+ use std::panic::catch_unwind;
+ use std::sync::OnceLock;
+
+ // 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();
+
+ #[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());
+ 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));
+ });
+ });
+ }
+
+ #[no_mangle]
+ pub extern "C" fn stop_rust_logic_extern() {
+ let _ = catch_unwind(|| {
+ 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(None);
+ });
+ });
+ }
+
+ #[no_mangle]
+ pub extern "C" fn send_dart_signal_extern(
+ message_id: i64,
+ message_pointer: *const u8,
+ message_size: usize,
+ blob_valid: bool,
+ blob_pointer: *const u8,
+ blob_size: usize,
+ ) {
+ let message_bytes = unsafe {
+ Vec::from_raw_parts(message_pointer as *mut u8, message_size, message_size)
+ };
+ let blob = if blob_valid {
+ unsafe {
+ Some(Vec::from_raw_parts(
+ blob_pointer as *mut u8,
+ blob_size,
+ blob_size,
+ ))
+ }
+ } else {
+ None
+ };
+ let _ = catch_unwind(|| {
+ crate::messages::generated::handle_dart_signal(
+ message_id as i32,
+ message_bytes,
+ blob,
+ );
+ });
+ }
+ }
+
+ #[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}");
+ }));
+ }
+
+ // Run the main function.
+ tokio::spawn(crate::main());
+ });
+ }
+
+ #[wasm_bindgen]
+ pub fn send_dart_signal_extern(
+ message_id: i32,
+ message_bytes: &[u8],
+ blob_valid: bool,
+ blob_bytes: &[u8],
+ ) {
+ let message_bytes = message_bytes.to_vec();
+ let blob = if blob_valid {
+ Some(blob_bytes.to_vec())
+ } else {
+ None
+ };
+ let _ = catch_unwind(|| {
+ crate::messages::generated::handle_dart_signal(
+ message_id,
+ message_bytes,
+ blob,
+ );
+ });
+ }
+ }
+ }
+ };
+}
+
+/// Delegates the printing operation to Flutter,
+/// which excels at handling various platforms
+/// including web and mobile emulators.
+/// When debugging, using this macro is recommended over `println!()`,
+/// as it seamlessly adapts to different environments.
+/// Note that this macro does nothing in release mode.
+#[macro_export]
+macro_rules! debug_print {
+ ( $( $t:tt )* ) => {
+ let rust_report = format!( $( $t )* );
+ #[cfg(debug_assertions)]
+ rinf::send_rust_signal(
+ -1, // This is a special message ID for Rust reports
+ Vec::new(),
+ Some(rust_report.into_bytes()),
+ );
+ #[cfg(not(debug_assertions))]
+ let _ = rust_report;
+ }
+}
From 5cdc51b6061a95da960aa0169b494d542f97fd39 Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 01:11:23 +0900
Subject: [PATCH 02/12] Remove `--bridge` option of `rinf template`
---
flutter_ffi_plugin/bin/rinf.dart | 13 +++----------
flutter_ffi_plugin/bin/src/helpers.dart | 13 -------------
2 files changed, 3 insertions(+), 23 deletions(-)
diff --git a/flutter_ffi_plugin/bin/rinf.dart b/flutter_ffi_plugin/bin/rinf.dart
index 7b310ae8..f74b8c65 100755
--- a/flutter_ffi_plugin/bin/rinf.dart
+++ b/flutter_ffi_plugin/bin/rinf.dart
@@ -16,14 +16,7 @@ Future main(List args) async {
print(rinfConfig);
break;
case "template":
- if (args.contains("--bridge") || args.contains("-b")) {
- await applyRustTemplate(
- onlyBridge: true,
- messageConfig: rinfConfig.message,
- );
- } else {
- await applyRustTemplate(messageConfig: rinfConfig.message);
- }
+ await applyRustTemplate(messageConfig: rinfConfig.message);
break;
case "message":
if (args.contains("--watch") || args.contains("-w")) {
@@ -47,8 +40,8 @@ Future main(List args) async {
print(" config Shows current Rinf configuration"
"\n resolved from `pubspec.yaml`"
"\n with defaults applied.");
- print(" template Applies Rust template to current project.");
- print(" -b, --bridge Only applies `bridge` Rust module.");
+ print(" template Applies Rust template"
+ "\n to current Flutter project.");
print(" message Generates message code from `.proto` files.");
print(" -w, --watch Continuously watches `.proto` files.");
print(" wasm Builds webassembly module.");
diff --git a/flutter_ffi_plugin/bin/src/helpers.dart b/flutter_ffi_plugin/bin/src/helpers.dart
index aaa65a84..11e794f4 100644
--- a/flutter_ffi_plugin/bin/src/helpers.dart
+++ b/flutter_ffi_plugin/bin/src/helpers.dart
@@ -5,7 +5,6 @@ import 'message.dart';
/// Creates new folders and files to an existing Flutter project folder.
Future applyRustTemplate({
- bool onlyBridge = false,
required RinfConfigMessage messageConfig,
}) async {
// Get the path of the current project directory
@@ -30,18 +29,6 @@ Future applyRustTemplate({
return;
}
- // Only copy the bridge module inside the `hub crate if wanted.
- if (onlyBridge) {
- final source = Directory('$packagePath/example/native/hub/src/bridge');
- final destination = Directory('$flutterProjectPath/native/hub/src/bridge');
- if (await destination.exists()) {
- await destination.delete(recursive: true);
- }
- await copyDirectory(source, destination);
- print("🎉 Rust bridge module is now ready! 🎉");
- return;
- }
-
// Copy basic folders needed for Rust to work
final templateSource = Directory('$packagePath/example/native');
final templateDestination = Directory('$flutterProjectPath/native');
From 78fd9799b19543c10d09fac51a53f70d7d901bda Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 01:17:34 +0900
Subject: [PATCH 03/12] Update first guides
---
README.md | 2 --
documentation/overrides/home.html | 15 ---------------
flutter_ffi_plugin/README.md | 2 --
rust_crate/README.md | 2 --
4 files changed, 21 deletions(-)
diff --git a/README.md b/README.md
index c041a7db..448f1055 100644
--- a/README.md
+++ b/README.md
@@ -66,9 +66,7 @@ All the message classes and structs are generated by Rinf. You can simply define
- **Minimal**: This is not a bulky framework that requires you to install so many dependencies and use complicated CLI commands. Just focus on your code using your preferred Flutter and Rust libraries.
- **Scalable**: Creating hundreds or even thousands of message APIs between Dart and Rust feels smooth and clean. Additionally, you have the flexibility to utilize any number of Rust library crates, perhaps including those you might have been working on.
- **High-level interface**: No messing with sensitive build files, no concerns about memory safety. Stay with Dart and Rust that you're familiar with.
-- **Low-level control**: Though the hard things are kept beneath the surface, you are free to modify the underlying logic such as concurrency or debugging features. There is no hidden mechanism that prevents your understanding.
- **Well maintained**: Our [automated workflows](https://github.com/cunarist/rinf/actions) including build tests are always kept passing, thanks to the main branch protection rule. Also, the number of external dependencies is kept as low as possible and documentations are thoughtfully organized.
-- **Async interaction**: Rust operations will never block Flutter's main thread because they are spawned in a separate thread pool.
- **Convenient debugging**: All the debugging functionalities are provided by default, without the need for dealing with browsers or mobile emulators. Also, the whole Rust logic is automatically restarted on Dart's hot restart.
- **Reliable**: Each component is supported by huge communities, ensuring a strong emphasis on future safety. You can easily assure your team of stability since this framework's underlying concept is fairly simple.
diff --git a/documentation/overrides/home.html b/documentation/overrides/home.html
index d6d70702..5b049a7a 100644
--- a/documentation/overrides/home.html
+++ b/documentation/overrides/home.html
@@ -290,14 +290,6 @@ High-level interface
safety. Stay with Dart and Rust that you're familiar with.
-
-
Low-level control
-
- Though the hard things are kept beneath the surface, you are free to
- modify the underlying logic such as concurrency or debugging features.
- There is no hidden mechanism that prevents your understanding.
-
-
Well maintained
@@ -307,13 +299,6 @@
Well maintained
are thoughtfully organized.
-
-
Async interaction
-
- Rust operations will never block Flutter's main thread because they
- are spawned in a separate thread pool.
-
-
Convenient debugging
diff --git a/flutter_ffi_plugin/README.md b/flutter_ffi_plugin/README.md
index c041a7db..448f1055 100644
--- a/flutter_ffi_plugin/README.md
+++ b/flutter_ffi_plugin/README.md
@@ -66,9 +66,7 @@ All the message classes and structs are generated by Rinf. You can simply define
- **Minimal**: This is not a bulky framework that requires you to install so many dependencies and use complicated CLI commands. Just focus on your code using your preferred Flutter and Rust libraries.
- **Scalable**: Creating hundreds or even thousands of message APIs between Dart and Rust feels smooth and clean. Additionally, you have the flexibility to utilize any number of Rust library crates, perhaps including those you might have been working on.
- **High-level interface**: No messing with sensitive build files, no concerns about memory safety. Stay with Dart and Rust that you're familiar with.
-- **Low-level control**: Though the hard things are kept beneath the surface, you are free to modify the underlying logic such as concurrency or debugging features. There is no hidden mechanism that prevents your understanding.
- **Well maintained**: Our [automated workflows](https://github.com/cunarist/rinf/actions) including build tests are always kept passing, thanks to the main branch protection rule. Also, the number of external dependencies is kept as low as possible and documentations are thoughtfully organized.
-- **Async interaction**: Rust operations will never block Flutter's main thread because they are spawned in a separate thread pool.
- **Convenient debugging**: All the debugging functionalities are provided by default, without the need for dealing with browsers or mobile emulators. Also, the whole Rust logic is automatically restarted on Dart's hot restart.
- **Reliable**: Each component is supported by huge communities, ensuring a strong emphasis on future safety. You can easily assure your team of stability since this framework's underlying concept is fairly simple.
diff --git a/rust_crate/README.md b/rust_crate/README.md
index c041a7db..448f1055 100644
--- a/rust_crate/README.md
+++ b/rust_crate/README.md
@@ -66,9 +66,7 @@ All the message classes and structs are generated by Rinf. You can simply define
- **Minimal**: This is not a bulky framework that requires you to install so many dependencies and use complicated CLI commands. Just focus on your code using your preferred Flutter and Rust libraries.
- **Scalable**: Creating hundreds or even thousands of message APIs between Dart and Rust feels smooth and clean. Additionally, you have the flexibility to utilize any number of Rust library crates, perhaps including those you might have been working on.
- **High-level interface**: No messing with sensitive build files, no concerns about memory safety. Stay with Dart and Rust that you're familiar with.
-- **Low-level control**: Though the hard things are kept beneath the surface, you are free to modify the underlying logic such as concurrency or debugging features. There is no hidden mechanism that prevents your understanding.
- **Well maintained**: Our [automated workflows](https://github.com/cunarist/rinf/actions) including build tests are always kept passing, thanks to the main branch protection rule. Also, the number of external dependencies is kept as low as possible and documentations are thoughtfully organized.
-- **Async interaction**: Rust operations will never block Flutter's main thread because they are spawned in a separate thread pool.
- **Convenient debugging**: All the debugging functionalities are provided by default, without the need for dealing with browsers or mobile emulators. Also, the whole Rust logic is automatically restarted on Dart's hot restart.
- **Reliable**: Each component is supported by huge communities, ensuring a strong emphasis on future safety. You can easily assure your team of stability since this framework's underlying concept is fairly simple.
From 623268684ca83ab75f1c03d2b5756d7101b051e6 Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 01:20:29 +0900
Subject: [PATCH 04/12] Improve comments
---
flutter_ffi_plugin/example/native/hub/src/lib.rs | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs
index b4ebe2f1..81062860 100755
--- a/flutter_ffi_plugin/example/native/hub/src/lib.rs
+++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs
@@ -1,4 +1,9 @@
+//! This `hub` crate is the
+//! entry point of the Rust logic.
+
// This `tokio` will be used by Rinf.
+// You can replace it with the original `tokio`
+// if you're not targeting the web.
use tokio_with_wasm::tokio;
mod messages;
@@ -6,8 +11,8 @@ mod sample_functions;
rinf::write_interface!();
-/// This `hub` crate is the entry point for the Rust logic.
-/// Always use non-blocking async functions such as `tokio::fs::File::open`.
+/// Always use non-blocking async functions
+/// such as `tokio::fs::File::open`.
async fn main() {
// Repeat `tokio::spawn` anywhere in your code
// if more concurrent tasks are needed.
From d420b907f9d7d5ffbb339dd3f239aeaea7e410b7 Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 01:26:31 +0900
Subject: [PATCH 05/12] Organize code
---
rust_crate/src/macros.rs | 253 ++++++++++++++++++---------------------
1 file changed, 119 insertions(+), 134 deletions(-)
diff --git a/rust_crate/src/macros.rs b/rust_crate/src/macros.rs
index 3299350a..03205371 100644
--- a/rust_crate/src/macros.rs
+++ b/rust_crate/src/macros.rs
@@ -7,152 +7,137 @@
/// at the root of the `hub` crate.
macro_rules! write_interface {
() => {
- mod interface {
- #[cfg(not(target_family = "wasm"))]
- pub use interface_os::*;
- #[cfg(target_family = "wasm")]
- pub use interface_web::*;
+ #[cfg(not(target_family = "wasm"))]
+ mod interface_os {
+ use crate::tokio::runtime::Builder;
+ use crate::tokio::runtime::Runtime;
+ use rinf::externs::os_thread_local::ThreadLocal;
+ use std::cell::RefCell;
+ use std::panic::catch_unwind;
+ use std::sync::OnceLock;
- #[cfg(not(target_family = "wasm"))]
- mod interface_os {
+ // 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();
- use crate::tokio::runtime::Builder;
- use crate::tokio::runtime::Runtime;
- use rinf::externs::os_thread_local::ThreadLocal;
- use std::cell::RefCell;
- use std::panic::catch_unwind;
- use std::sync::OnceLock;
+ #[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:?}");
+ }));
+ }
- // 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();
-
- #[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());
- 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));
- });
+ // Run the main function.
+ let tokio_runtime = Builder::new_multi_thread().enable_all().build().unwrap();
+ tokio_runtime.spawn(crate::main());
+ 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));
});
- }
+ });
+ }
- #[no_mangle]
- pub extern "C" fn stop_rust_logic_extern() {
- let _ = catch_unwind(|| {
- 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(None);
- });
+ #[no_mangle]
+ pub extern "C" fn stop_rust_logic_extern() {
+ let _ = catch_unwind(|| {
+ 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(None);
});
- }
+ });
+ }
- #[no_mangle]
- pub extern "C" fn send_dart_signal_extern(
- message_id: i64,
- message_pointer: *const u8,
- message_size: usize,
- blob_valid: bool,
- blob_pointer: *const u8,
- blob_size: usize,
- ) {
- let message_bytes = unsafe {
- Vec::from_raw_parts(message_pointer as *mut u8, message_size, message_size)
- };
- let blob = if blob_valid {
- unsafe {
- Some(Vec::from_raw_parts(
- blob_pointer as *mut u8,
- blob_size,
- blob_size,
- ))
- }
- } else {
- None
- };
- let _ = catch_unwind(|| {
- crate::messages::generated::handle_dart_signal(
- message_id as i32,
- message_bytes,
- blob,
- );
- });
- }
+ #[no_mangle]
+ pub extern "C" fn send_dart_signal_extern(
+ message_id: i64,
+ message_pointer: *const u8,
+ message_size: usize,
+ blob_valid: bool,
+ blob_pointer: *const u8,
+ blob_size: usize,
+ ) {
+ let message_bytes = unsafe {
+ Vec::from_raw_parts(message_pointer as *mut u8, message_size, message_size)
+ };
+ let blob = if blob_valid {
+ unsafe {
+ Some(Vec::from_raw_parts(
+ blob_pointer as *mut u8,
+ blob_size,
+ blob_size,
+ ))
+ }
+ } else {
+ None
+ };
+ let _ = catch_unwind(|| {
+ crate::messages::generated::handle_dart_signal(
+ message_id as i32,
+ message_bytes,
+ blob,
+ );
+ });
}
+ }
- #[cfg(target_family = "wasm")]
- mod interface_web {
- use crate::tokio;
- use std::panic::catch_unwind;
- use wasm_bindgen::prelude::wasm_bindgen;
+ #[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]
+ 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}");
+ }));
+ }
- // Run the main function.
- tokio::spawn(crate::main());
- });
- }
+ // Run the main function.
+ tokio::spawn(crate::main());
+ });
+ }
- #[wasm_bindgen]
- pub fn send_dart_signal_extern(
- message_id: i32,
- message_bytes: &[u8],
- blob_valid: bool,
- blob_bytes: &[u8],
- ) {
- let message_bytes = message_bytes.to_vec();
- let blob = if blob_valid {
- Some(blob_bytes.to_vec())
- } else {
- None
- };
- let _ = catch_unwind(|| {
- crate::messages::generated::handle_dart_signal(
- message_id,
- message_bytes,
- blob,
- );
- });
- }
+ #[wasm_bindgen]
+ pub fn send_dart_signal_extern(
+ message_id: i32,
+ message_bytes: &[u8],
+ blob_valid: bool,
+ blob_bytes: &[u8],
+ ) {
+ let message_bytes = message_bytes.to_vec();
+ let blob = if blob_valid {
+ Some(blob_bytes.to_vec())
+ } else {
+ None
+ };
+ let _ = catch_unwind(|| {
+ crate::messages::generated::handle_dart_signal(message_id, message_bytes, blob);
+ });
}
}
};
From d33cc1d46953fb6c735e4756904fb8782f685375 Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 01:29:22 +0900
Subject: [PATCH 06/12] Organize code
---
.../example/native/hub/src/sample_functions.rs | 10 +++++-----
1 file changed, 5 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 25e72299..f2e39956 100755
--- a/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs
+++ b/flutter_ffi_plugin/example/native/hub/src/sample_functions.rs
@@ -5,6 +5,11 @@ use crate::messages;
use crate::tokio;
use rinf::debug_print;
+#[cfg(debug_assertions)]
+const IS_DEBUG_MODE: bool = true;
+#[cfg(not(debug_assertions))]
+const IS_DEBUG_MODE: bool = false;
+
const SHOULD_DEMONSTRATE: bool = true; // Disabled when applied as template
pub async fn tell_numbers() {
@@ -91,11 +96,6 @@ pub async fn stream_fractal() {
}
pub async fn run_debug_tests() {
- #[cfg(debug_assertions)]
- const IS_DEBUG_MODE: bool = true;
- #[cfg(not(debug_assertions))]
- const IS_DEBUG_MODE: bool = false;
-
if !SHOULD_DEMONSTRATE || !IS_DEBUG_MODE {
return;
}
From a3fe6d7d2b799e7c610d8a628ebb538cee0aba7c Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 01:55:15 +0900
Subject: [PATCH 07/12] Organize Dart API
---
documentation/docs/writing-code.md | 4 +--
flutter_ffi_plugin/bin/src/helpers.dart | 10 ++----
flutter_ffi_plugin/bin/src/message.dart | 13 ++++----
flutter_ffi_plugin/example/lib/main.dart | 6 ++--
flutter_ffi_plugin/lib/rinf.dart | 32 ++++++++++++-------
flutter_ffi_plugin/lib/src/interface_os.dart | 4 ++-
flutter_ffi_plugin/lib/src/interface_web.dart | 4 ++-
7 files changed, 40 insertions(+), 33 deletions(-)
diff --git a/documentation/docs/writing-code.md b/documentation/docs/writing-code.md
index eb16e044..78c27518 100644
--- a/documentation/docs/writing-code.md
+++ b/documentation/docs/writing-code.md
@@ -69,7 +69,7 @@ debug_print!("My object is {my_object:?}");
## 🌅 Closing the App Gracefully
-When the Flutter app is closed, the whole `tokio` runtime on the Rust side will be terminated automatically. However, some error messages can appear in the console if the Rust side sends messages to the Dart side even after the Dart VM has stopped. To prevent this, you can call `Rinf.finalize()` in Dart to terminate all Rust tasks before closing the Flutter app.
+When the Flutter app is closed, the whole `tokio` runtime on the Rust side will be terminated automatically. However, some error messages can appear in the console if the Rust side sends messages to the Dart side even after the Dart VM has stopped. To prevent 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';
@@ -87,7 +87,7 @@ class _MyAppState extends State {
final _appLifecycleListener = AppLifecycleListener(
onExitRequested: () async {
// Terminate Rust tasks before closing the Flutter app.
- await Rinf.finalize();
+ finalizeRust();
return AppExitResponse.exit;
},
);
diff --git a/flutter_ffi_plugin/bin/src/helpers.dart b/flutter_ffi_plugin/bin/src/helpers.dart
index 11e794f4..2d656946 100644
--- a/flutter_ffi_plugin/bin/src/helpers.dart
+++ b/flutter_ffi_plugin/bin/src/helpers.dart
@@ -158,16 +158,10 @@ please refer to Rinf's [documentation](https://rinf.cunarist.com).
);
mainText = lines.join("\n");
}
- if (mainText.contains('main() {')) {
+ if (!mainText.contains('initializeRust()')) {
mainText = mainText.replaceFirst(
'main() {',
- 'main() async {',
- );
- }
- if (!mainText.contains('Rinf.initialize()')) {
- mainText = mainText.replaceFirst(
- 'main() async {',
- 'main() async { await Rinf.initialize();',
+ 'main() { initializeRust();',
);
}
await mainFile.writeAsString(mainText);
diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart
index 7ab4f78e..4c409b18 100644
--- a/flutter_ffi_plugin/bin/src/message.dart
+++ b/flutter_ffi_plugin/bin/src/message.dart
@@ -386,14 +386,13 @@ import 'dart:async';
import 'dart:typed_data';
import 'package:rinf/rinf.dart';
-class Rinf {
- static Future initialize() async {
- await initializeRinf(handleRustSignal);
- }
+void initializeRust() async {
+ prepareInterface(handleRustSignal);
+ startRustLogic();
+}
- static Future finalize() async {
- await finalizeRinf();
- }
+void finalizeRust() async {
+ stopRustLogic();
}
final signalHandlers = {
diff --git a/flutter_ffi_plugin/example/lib/main.dart b/flutter_ffi_plugin/example/lib/main.dart
index 1718fd2a..9e114bef 100755
--- a/flutter_ffi_plugin/example/lib/main.dart
+++ b/flutter_ffi_plugin/example/lib/main.dart
@@ -4,9 +4,9 @@ import 'package:example_app/messages/generated.dart';
import 'package:example_app/messages/counter_number.pb.dart';
import 'package:example_app/messages/fractal_art.pb.dart';
-void main() async {
+void main() {
// Wait for Rust initialization to be completed first.
- await Rinf.initialize();
+ initializeRust();
runApp(const MyApp());
}
@@ -21,7 +21,7 @@ class _MyAppState extends State {
final _appLifecycleListener = AppLifecycleListener(
onExitRequested: () async {
// Terminate Rust tasks before closing the Flutter app.
- await Rinf.finalize();
+ finalizeRust();
return AppExitResponse.exit;
},
);
diff --git a/flutter_ffi_plugin/lib/rinf.dart b/flutter_ffi_plugin/lib/rinf.dart
index 9faa249d..0bb6afb5 100755
--- a/flutter_ffi_plugin/lib/rinf.dart
+++ b/flutter_ffi_plugin/lib/rinf.dart
@@ -1,29 +1,34 @@
/// This module supports communication with Rust.
-import 'dart:async';
import 'dart:typed_data';
import 'src/exports.dart';
export 'src/interface.dart' show RustSignal;
-/// Makes sure that the Rust side is ready.
+/// Prepares the native interface
+/// needed to communicate with Rust.
+void prepareInterface(HandleRustSignal handleRustSignal) async {
+ prepareInterfaceExtern(handleRustSignal);
+}
+
+/// Starts the `main` function in Rust.
/// Don't forget to call this function in the `main` function of Dart.
-Future initializeRinf(HandleRustSignal handleRustSignal) async {
- await prepareNativeBridge(handleRustSignal);
+void startRustLogic() async {
+ startRustLogicExtern();
}
-/// Ensure that all Rust tasks are terminated
-/// by calling this function before closing the Flutter app.
-/// Doing so can prevent potential memory errors that may occur
+/// Terminates all Rust tasks.
+/// Doing so before closing the Flutter app
+/// can prevent potential memory errors that may occur
/// when Rust attempts to send data after the Dart VM has been turned off.
/// Please note that on the web, this function does not have any effect,
/// as tasks are managed by the JavaScript runtime, not Rust.
-Future finalizeRinf() async {
+void stopRustLogic() async {
stopRustLogicExtern();
}
-/// Send a signal to Rust.
-Future sendDartSignal(
+/// Sends a signal to Rust.
+void sendDartSignal(
int messageId,
Uint8List messageBytes,
Uint8List? blob,
@@ -37,5 +42,10 @@ Future sendDartSignal(
blobValid = true;
blobBytes = blob;
}
- sendDartSignalExtern(messageId, messageBytes, blobValid, blobBytes);
+ sendDartSignalExtern(
+ messageId,
+ messageBytes,
+ blobValid,
+ blobBytes,
+ );
}
diff --git a/flutter_ffi_plugin/lib/src/interface_os.dart b/flutter_ffi_plugin/lib/src/interface_os.dart
index 9c3b25be..e9294e6d 100644
--- a/flutter_ffi_plugin/lib/src/interface_os.dart
+++ b/flutter_ffi_plugin/lib/src/interface_os.dart
@@ -10,7 +10,9 @@ import 'dart:convert';
typedef StoreDartPostCObject = Pointer Function(
Pointer)>>);
-Future prepareNativeBridge(HandleRustSignal handleRustSignal) async {
+Future prepareInterfaceExtern(
+ HandleRustSignal handleRustSignal,
+) async {
/// This should be called once at startup
/// to enable `allo_isolate` to send data from the Rust side.
final rustFunction =
diff --git a/flutter_ffi_plugin/lib/src/interface_web.dart b/flutter_ffi_plugin/lib/src/interface_web.dart
index 84ec4576..56205610 100644
--- a/flutter_ffi_plugin/lib/src/interface_web.dart
+++ b/flutter_ffi_plugin/lib/src/interface_web.dart
@@ -7,7 +7,9 @@ import 'interface.dart';
import 'dart:async';
import 'dart:convert';
-Future prepareNativeBridge(HandleRustSignal handleRustSignal) async {
+Future prepareInterfaceExtern(
+ HandleRustSignal handleRustSignal,
+) async {
final isAlreadyPrepared = await loadJsFile();
if (isAlreadyPrepared) {
From 29e223a1e5bac910cd97b1711cf83b57b3d31164 Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 02:00:39 +0900
Subject: [PATCH 08/12] Organize code
---
rust_crate/src/lib.rs | 1 -
1 file changed, 1 deletion(-)
diff --git a/rust_crate/src/lib.rs b/rust_crate/src/lib.rs
index a7c1ed28..d3ee96c9 100644
--- a/rust_crate/src/lib.rs
+++ b/rust_crate/src/lib.rs
@@ -1,5 +1,4 @@
pub use interface::*;
-pub use macros::*;
pub mod externs;
mod interface;
From 7b92a1ac4fa34a072a66659457e61ff1b0961db9 Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 02:01:20 +0900
Subject: [PATCH 09/12] Organize code
---
rust_crate/src/lib.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/rust_crate/src/lib.rs b/rust_crate/src/lib.rs
index d3ee96c9..07b83979 100644
--- a/rust_crate/src/lib.rs
+++ b/rust_crate/src/lib.rs
@@ -1,9 +1,10 @@
pub use interface::*;
pub mod externs;
+mod macros;
+
mod interface;
#[cfg(not(target_family = "wasm"))]
mod interface_os;
#[cfg(target_family = "wasm")]
mod interface_web;
-mod macros;
From e602eeb8037bdc3de457d5fb90b1af499ab45fbe Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 02:02:17 +0900
Subject: [PATCH 10/12] Organize code
---
rust_crate/src/interface.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rust_crate/src/interface.rs b/rust_crate/src/interface.rs
index 9c861908..5717791f 100644
--- a/rust_crate/src/interface.rs
+++ b/rust_crate/src/interface.rs
@@ -3,9 +3,9 @@ use std::sync::Mutex;
use std::sync::OnceLock;
#[cfg(not(target_family = "wasm"))]
-pub use super::interface_os::*;
+use super::interface_os::*;
#[cfg(target_family = "wasm")]
-pub use super::interface_web::*;
+use super::interface_web::*;
/// This is a mutable cell type that can be shared across threads.
pub type SharedCell = OnceLock>>>;
From 77ae73c13b9e7d9c6ccd35e61cb77a8eb879dd6f Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 02:07:14 +0900
Subject: [PATCH 11/12] Handle the case when Dart `main` is async
---
flutter_ffi_plugin/bin/src/helpers.dart | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/flutter_ffi_plugin/bin/src/helpers.dart b/flutter_ffi_plugin/bin/src/helpers.dart
index 2d656946..589b1a35 100644
--- a/flutter_ffi_plugin/bin/src/helpers.dart
+++ b/flutter_ffi_plugin/bin/src/helpers.dart
@@ -163,6 +163,10 @@ please refer to Rinf's [documentation](https://rinf.cunarist.com).
'main() {',
'main() { initializeRust();',
);
+ mainText = mainText.replaceFirst(
+ 'main() async {',
+ 'main() async { initializeRust();',
+ );
}
await mainFile.writeAsString(mainText);
await Process.run('dart', ['format', './lib/main.dart']);
From b338b411907a479873049591ad5c25276b3c345b Mon Sep 17 00:00:00 2001
From: DongHyun Kim
Date: Fri, 2 Feb 2024 02:15:09 +0900
Subject: [PATCH 12/12] Fix a comment
---
flutter_ffi_plugin/example/native/hub/src/lib.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flutter_ffi_plugin/example/native/hub/src/lib.rs b/flutter_ffi_plugin/example/native/hub/src/lib.rs
index 81062860..8d1d4139 100755
--- a/flutter_ffi_plugin/example/native/hub/src/lib.rs
+++ b/flutter_ffi_plugin/example/native/hub/src/lib.rs
@@ -11,8 +11,8 @@ mod sample_functions;
rinf::write_interface!();
-/// Always use non-blocking async functions
-/// such as `tokio::fs::File::open`.
+// Always use non-blocking async functions
+// such as `tokio::fs::File::open`.
async fn main() {
// Repeat `tokio::spawn` anywhere in your code
// if more concurrent tasks are needed.