diff --git a/mobile/lib/bridge_definitions.dart b/mobile/lib/bridge_definitions.dart index a82851a..bd62891 100644 --- a/mobile/lib/bridge_definitions.dart +++ b/mobile/lib/bridge_definitions.dart @@ -9,22 +9,19 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; import 'package:uuid/uuid.dart'; abstract class Native { - Future platform({dynamic hint}); + Future getTxConfig({required Uint8List bytes, dynamic hint}); - FlutterRustBridgeTaskConstMeta get kPlatformConstMeta; - - Future rustReleaseMode({dynamic hint}); - - FlutterRustBridgeTaskConstMeta get kRustReleaseModeConstMeta; + FlutterRustBridgeTaskConstMeta get kGetTxConfigConstMeta; } -enum Platform { - Unknown, - AndroidBish, - Ios, - Windows, - Unix, - MacIntel, - MacApple, - Wasm, +class TxConfig { + final int len; + final int mtu; + final String description; + + const TxConfig({ + required this.len, + required this.mtu, + required this.description, + }); } diff --git a/mobile/lib/bridge_generated.dart b/mobile/lib/bridge_generated.dart index bdbc6a2..e251d34 100644 --- a/mobile/lib/bridge_generated.dart +++ b/mobile/lib/bridge_generated.dart @@ -24,34 +24,20 @@ class NativeImpl implements Native { /// Only valid on web/WASM platforms. factory NativeImpl.wasm(FutureOr module) => NativeImpl(module as ExternalLibrary); NativeImpl.raw(this._platform); - Future platform({dynamic hint}) { + Future getTxConfig({required Uint8List bytes, dynamic hint}) { + var arg0 = _platform.api2wire_uint_8_list(bytes); return _platform.executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => _platform.inner.wire_platform(port_), - parseSuccessData: _wire2api_platform, - constMeta: kPlatformConstMeta, - argValues: [], + callFfi: (port_) => _platform.inner.wire_get_tx_config(port_, arg0), + parseSuccessData: _wire2api_opt_box_autoadd_tx_config, + constMeta: kGetTxConfigConstMeta, + argValues: [bytes], hint: hint, )); } - FlutterRustBridgeTaskConstMeta get kPlatformConstMeta => const FlutterRustBridgeTaskConstMeta( - debugName: "platform", - argNames: [], - ); - - Future rustReleaseMode({dynamic hint}) { - return _platform.executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => _platform.inner.wire_rust_release_mode(port_), - parseSuccessData: _wire2api_bool, - constMeta: kRustReleaseModeConstMeta, - argValues: [], - hint: hint, - )); - } - - FlutterRustBridgeTaskConstMeta get kRustReleaseModeConstMeta => const FlutterRustBridgeTaskConstMeta( - debugName: "rust_release_mode", - argNames: [], + FlutterRustBridgeTaskConstMeta get kGetTxConfigConstMeta => const FlutterRustBridgeTaskConstMeta( + debugName: "get_tx_config", + argNames: ["bytes"], ); void dispose() { @@ -59,21 +45,52 @@ class NativeImpl implements Native { } // Section: wire2api - bool _wire2api_bool(dynamic raw) { - return raw as bool; + String _wire2api_String(dynamic raw) { + return raw as String; } - int _wire2api_i32(dynamic raw) { + TxConfig _wire2api_box_autoadd_tx_config(dynamic raw) { + return _wire2api_tx_config(raw); + } + + TxConfig? _wire2api_opt_box_autoadd_tx_config(dynamic raw) { + return raw == null ? null : _wire2api_box_autoadd_tx_config(raw); + } + + TxConfig _wire2api_tx_config(dynamic raw) { + final arr = raw as List; + if (arr.length != 3) throw Exception('unexpected arr length: expect 3 but see ${arr.length}'); + return TxConfig( + len: _wire2api_u64(arr[0]), + mtu: _wire2api_u16(arr[1]), + description: _wire2api_String(arr[2]), + ); + } + + int _wire2api_u16(dynamic raw) { return raw as int; } - Platform _wire2api_platform(dynamic raw) { - return Platform.values[raw as int]; + int _wire2api_u64(dynamic raw) { + return castInt(raw); + } + + int _wire2api_u8(dynamic raw) { + return raw as int; + } + + Uint8List _wire2api_uint_8_list(dynamic raw) { + return raw as Uint8List; } } // Section: api2wire +@protected +int api2wire_u8(int raw) { + return raw; +} + // Section: finalizer class NativePlatform extends FlutterRustBridgeBase { @@ -81,6 +98,12 @@ class NativePlatform extends FlutterRustBridgeBase { // Section: api2wire + @protected + ffi.Pointer api2wire_uint_8_list(Uint8List raw) { + final ans = inner.new_uint_8_list_0(raw.length); + ans.ref.ptr.asTypedList(raw.length).setAll(0, raw); + return ans; + } // Section: finalizer // Section: api_fill_to_wire @@ -164,28 +187,32 @@ class NativeWire implements FlutterRustBridgeWireBase { _lookup)>>('init_frb_dart_api_dl'); late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr.asFunction)>(); - void wire_platform( + void wire_get_tx_config( int port_, + ffi.Pointer bytes, ) { - return _wire_platform( + return _wire_get_tx_config( port_, + bytes, ); } - late final _wire_platformPtr = _lookup>('wire_platform'); - late final _wire_platform = _wire_platformPtr.asFunction(); + late final _wire_get_tx_configPtr = + _lookup)>>('wire_get_tx_config'); + late final _wire_get_tx_config = + _wire_get_tx_configPtr.asFunction)>(); - void wire_rust_release_mode( - int port_, + ffi.Pointer new_uint_8_list_0( + int len, ) { - return _wire_rust_release_mode( - port_, + return _new_uint_8_list_0( + len, ); } - late final _wire_rust_release_modePtr = - _lookup>('wire_rust_release_mode'); - late final _wire_rust_release_mode = _wire_rust_release_modePtr.asFunction(); + late final _new_uint_8_list_0Ptr = + _lookup Function(ffi.Int32)>>('new_uint_8_list_0'); + late final _new_uint_8_list_0 = _new_uint_8_list_0Ptr.asFunction Function(int)>(); void free_WireSyncReturn( WireSyncReturn ptr, @@ -202,6 +229,13 @@ class NativeWire implements FlutterRustBridgeWireBase { final class _Dart_Handle extends ffi.Opaque {} +final class wire_uint_8_list extends ffi.Struct { + external ffi.Pointer ptr; + + @ffi.Int32() + external int len; +} + typedef DartPostCObjectFnType = ffi.Pointer message)>>; typedef DartPort = ffi.Int64; diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 00a3f3f..6716d37 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -1,16 +1,24 @@ import 'dart:async'; +import 'dart:ffi'; +import 'dart:typed_data'; -import 'package:cuttle/utils/mlkit_utils.dart'; import 'package:camerawesome/camerawesome_plugin.dart'; import 'package:flutter/material.dart'; -import 'ffi.dart' if (dart.library.html) 'ffi_web.dart'; import 'package:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart'; import 'package:rxdart/rxdart.dart'; +import 'ffi.dart'; +import 'utils/mlkit_utils.dart'; void main() { runApp(const MyApp()); } +enum CuttleState { + unitialized, + receiving, + received, +} + class MyApp extends StatelessWidget { const MyApp({super.key}); @@ -41,6 +49,10 @@ class _MyHomePageState extends State { late final Stream> _barcodesStream = _barcodesController.stream; final _scrollController = ScrollController(); + final TxConfig? _txConfig = null; + final _rxData = []; + final _cuttleState = CuttleState.unitialized; + @override void dispose() { _barcodesController.close(); diff --git a/mobile/native/Cargo.toml b/mobile/native/Cargo.toml index fdf3002..1638c65 100644 --- a/mobile/native/Cargo.toml +++ b/mobile/native/Cargo.toml @@ -6,8 +6,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -crate-type = ["cdylib", "lib"] +crate-type = ["cdylib", "rlib"] [dependencies] anyhow = "1" +cuttle = { path = "../../", default-features = false } flutter_rust_bridge = "1" +raptorq = "1.7.0" +rkyv = { version = "0.7.42", features = ["validation"] } diff --git a/mobile/native/src/api.rs b/mobile/native/src/api.rs index 366517e..2639527 100644 --- a/mobile/native/src/api.rs +++ b/mobile/native/src/api.rs @@ -1,59 +1,29 @@ -// This is the entry point of your Rust library. -// When adding new code to your project, note that only items used -// here will be transformed to their Dart equivalents. +use rkyv::Deserialize; -// A plain enum without any fields. This is similar to Dart- or C-style enums. -// flutter_rust_bridge is capable of generating code for enums with fields -// (@freezed classes in Dart and tagged unions in C). -pub enum Platform { - Unknown, - AndroidBish, - Ios, - Windows, - Unix, - MacIntel, - MacApple, - Wasm, +#[derive(Debug, Clone)] +pub struct TxConfig { + pub len: u64, + pub mtu: u16, + pub description: String, } -// A function definition in Rust. Similar to Dart, the return type must always be named -// and is never inferred. -pub fn platform() -> Platform { - // This is a macro, a special expression that expands into code. In Rust, all macros - // end with an exclamation mark and can be invoked with all kinds of brackets (parentheses, - // brackets and curly braces). However, certain conventions exist, for example the - // vector macro is almost always invoked as vec![..]. - // - // The cfg!() macro returns a boolean value based on the current compiler configuration. - // When attached to expressions (#[cfg(..)] form), they show or hide the expression at compile time. - // Here, however, they evaluate to runtime values, which may or may not be optimized out - // by the compiler. A variety of configurations are demonstrated here which cover most of - // the modern oeprating systems. Try running the Flutter application on different machines - // and see if it matches your expected OS. - // - // Furthermore, in Rust, the last expression in a function is the return value and does - // not have the trailing semicolon. This entire if-else chain forms a single expression. - if cfg!(windows) { - Platform::Windows - } else if cfg!(target_os = "android") { - Platform::AndroidBish - } else if cfg!(target_os = "ios") { - Platform::Ios - } else if cfg!(all(target_os = "macos", target_arch = "aarch64")) { - Platform::MacApple - } else if cfg!(target_os = "macos") { - Platform::MacIntel - } else if cfg!(target_family = "wasm") { - Platform::Wasm - } else if cfg!(unix) { - Platform::Unix - } else { - Platform::Unknown +impl From for TxConfig { + fn from(value: cuttle::TxConfig) -> Self { + TxConfig { + len: value.len, + mtu: value.mtu, + description: value.description, + } } } -// The convention for Rust identifiers is the snake_case, -// and they are automatically converted to camelCase on the Dart side. -pub fn rust_release_mode() -> bool { - cfg!(not(debug_assertions)) +pub fn get_tx_config(bytes: Vec) -> Option { + if let Ok(archive) = rkyv::check_archived_root::(&bytes) { + if let Ok::(conf) = archive.deserialize(&mut rkyv::Infallible) { + return Some(conf.into()); + } else { + return None; + } + } + None } diff --git a/mobile/native/src/bridge_generated.io.rs b/mobile/native/src/bridge_generated.io.rs index a4ec960..97bfe87 100644 --- a/mobile/native/src/bridge_generated.io.rs +++ b/mobile/native/src/bridge_generated.io.rs @@ -2,23 +2,42 @@ use super::*; // Section: wire functions #[no_mangle] -pub extern "C" fn wire_platform(port_: i64) { - wire_platform_impl(port_) -} - -#[no_mangle] -pub extern "C" fn wire_rust_release_mode(port_: i64) { - wire_rust_release_mode_impl(port_) +pub extern "C" fn wire_get_tx_config(port_: i64, bytes: *mut wire_uint_8_list) { + wire_get_tx_config_impl(port_, bytes) } // Section: allocate functions +#[no_mangle] +pub extern "C" fn new_uint_8_list_0(len: i32) -> *mut wire_uint_8_list { + let ans = wire_uint_8_list { + ptr: support::new_leak_vec_ptr(Default::default(), len), + len, + }; + support::new_leak_box_ptr(ans) +} + // Section: related functions // Section: impl Wire2Api +impl Wire2Api> for *mut wire_uint_8_list { + fn wire2api(self) -> Vec { + unsafe { + let wrap = support::box_from_leak_ptr(self); + support::vec_from_leak_ptr(wrap.ptr, wrap.len) + } + } +} // Section: wire structs +#[repr(C)] +#[derive(Clone)] +pub struct wire_uint_8_list { + ptr: *mut u8, + len: i32, +} + // Section: impl NewWithNullPtr pub trait NewWithNullPtr { diff --git a/mobile/native/src/bridge_generated.rs b/mobile/native/src/bridge_generated.rs index 0ede1cf..a556e89 100644 --- a/mobile/native/src/bridge_generated.rs +++ b/mobile/native/src/bridge_generated.rs @@ -22,24 +22,17 @@ use crate::api::*; // Section: wire functions -fn wire_platform_impl(port_: MessagePort) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, Platform>( +fn wire_get_tx_config_impl(port_: MessagePort, bytes: impl Wire2Api> + UnwindSafe) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, Option>( WrapInfo { - debug_name: "platform", + debug_name: "get_tx_config", port: Some(port_), mode: FfiCallMode::Normal, }, - move || move |task_callback| Ok(platform()), - ) -} -fn wire_rust_release_mode_impl(port_: MessagePort) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, bool>( - WrapInfo { - debug_name: "rust_release_mode", - port: Some(port_), - mode: FfiCallMode::Normal, + move || { + let api_bytes = bytes.wire2api(); + move |task_callback| Ok(get_tx_config(api_bytes)) }, - move || move |task_callback| Ok(rust_release_mode()), ) } // Section: wrapper structs @@ -64,25 +57,26 @@ where (!self.is_null()).then(|| self.wire2api()) } } +impl Wire2Api for u8 { + fn wire2api(self) -> u8 { + self + } +} + // Section: impl IntoDart -impl support::IntoDart for Platform { +impl support::IntoDart for TxConfig { fn into_dart(self) -> support::DartAbi { - match self { - Self::Unknown => 0, - Self::AndroidBish => 1, - Self::Ios => 2, - Self::Windows => 3, - Self::Unix => 4, - Self::MacIntel => 5, - Self::MacApple => 6, - Self::Wasm => 7, - } + vec![ + self.len.into_into_dart().into_dart(), + self.mtu.into_into_dart().into_dart(), + self.description.into_into_dart().into_dart(), + ] .into_dart() } } -impl support::IntoDartExceptPrimitive for Platform {} -impl rust2dart::IntoIntoDart for Platform { +impl support::IntoDartExceptPrimitive for TxConfig {} +impl rust2dart::IntoIntoDart for TxConfig { fn into_into_dart(self) -> Self { self } diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index d8ed8f4..aae02f8 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -33,19 +33,18 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 + camerawesome: ^1.4.0 ffi: ^2.0.1 flutter_rust_bridge: ^1.45.0 - meta: ^1.8.0 - uuid: ^3.0.7 - path_provider: ^2.1.0 - path: ^1.8.3 - mobile_scanner: ^3.4.1 - camerawesome: ^1.4.0 google_mlkit_barcode_scanning: ^0.5.0 - rxdart: ^0.27.7 - image: ^4.0.17 google_mlkit_commons: ^0.2.0 + image: ^4.0.17 + meta: ^1.8.0 + mobile_scanner: ^3.4.1 + path: ^1.8.3 + path_provider: ^2.1.0 + rxdart: ^0.27.7 + uuid: ^3.0.7 dev_dependencies: flutter_test: