have mobile rust lib working for txconfig

This commit is contained in:
Joe Ardent 2023-08-18 17:12:44 -07:00
parent 881d225202
commit d4de0a9e81
8 changed files with 179 additions and 151 deletions

View file

@ -9,22 +9,19 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
abstract class Native { abstract class Native {
Future<Platform> platform({dynamic hint}); Future<TxConfig?> getTxConfig({required Uint8List bytes, dynamic hint});
FlutterRustBridgeTaskConstMeta get kPlatformConstMeta; FlutterRustBridgeTaskConstMeta get kGetTxConfigConstMeta;
Future<bool> rustReleaseMode({dynamic hint});
FlutterRustBridgeTaskConstMeta get kRustReleaseModeConstMeta;
} }
enum Platform { class TxConfig {
Unknown, final int len;
AndroidBish, final int mtu;
Ios, final String description;
Windows,
Unix, const TxConfig({
MacIntel, required this.len,
MacApple, required this.mtu,
Wasm, required this.description,
});
} }

View file

@ -24,34 +24,20 @@ class NativeImpl implements Native {
/// Only valid on web/WASM platforms. /// Only valid on web/WASM platforms.
factory NativeImpl.wasm(FutureOr<WasmModule> module) => NativeImpl(module as ExternalLibrary); factory NativeImpl.wasm(FutureOr<WasmModule> module) => NativeImpl(module as ExternalLibrary);
NativeImpl.raw(this._platform); NativeImpl.raw(this._platform);
Future<Platform> platform({dynamic hint}) { Future<TxConfig?> getTxConfig({required Uint8List bytes, dynamic hint}) {
var arg0 = _platform.api2wire_uint_8_list(bytes);
return _platform.executeNormal(FlutterRustBridgeTask( return _platform.executeNormal(FlutterRustBridgeTask(
callFfi: (port_) => _platform.inner.wire_platform(port_), callFfi: (port_) => _platform.inner.wire_get_tx_config(port_, arg0),
parseSuccessData: _wire2api_platform, parseSuccessData: _wire2api_opt_box_autoadd_tx_config,
constMeta: kPlatformConstMeta, constMeta: kGetTxConfigConstMeta,
argValues: [], argValues: [bytes],
hint: hint, hint: hint,
)); ));
} }
FlutterRustBridgeTaskConstMeta get kPlatformConstMeta => const FlutterRustBridgeTaskConstMeta( FlutterRustBridgeTaskConstMeta get kGetTxConfigConstMeta => const FlutterRustBridgeTaskConstMeta(
debugName: "platform", debugName: "get_tx_config",
argNames: [], argNames: ["bytes"],
);
Future<bool> 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: [],
); );
void dispose() { void dispose() {
@ -59,21 +45,52 @@ class NativeImpl implements Native {
} }
// Section: wire2api // Section: wire2api
bool _wire2api_bool(dynamic raw) { String _wire2api_String(dynamic raw) {
return raw as bool; 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<dynamic>;
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; return raw as int;
} }
Platform _wire2api_platform(dynamic raw) { int _wire2api_u64(dynamic raw) {
return Platform.values[raw as int]; 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 // Section: api2wire
@protected
int api2wire_u8(int raw) {
return raw;
}
// Section: finalizer // Section: finalizer
class NativePlatform extends FlutterRustBridgeBase<NativeWire> { class NativePlatform extends FlutterRustBridgeBase<NativeWire> {
@ -81,6 +98,12 @@ class NativePlatform extends FlutterRustBridgeBase<NativeWire> {
// Section: api2wire // Section: api2wire
@protected
ffi.Pointer<wire_uint_8_list> 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: finalizer
// Section: api_fill_to_wire // Section: api_fill_to_wire
@ -164,28 +187,32 @@ class NativeWire implements FlutterRustBridgeWireBase {
_lookup<ffi.NativeFunction<ffi.IntPtr Function(ffi.Pointer<ffi.Void>)>>('init_frb_dart_api_dl'); _lookup<ffi.NativeFunction<ffi.IntPtr Function(ffi.Pointer<ffi.Void>)>>('init_frb_dart_api_dl');
late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr.asFunction<int Function(ffi.Pointer<ffi.Void>)>(); late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr.asFunction<int Function(ffi.Pointer<ffi.Void>)>();
void wire_platform( void wire_get_tx_config(
int port_, int port_,
ffi.Pointer<wire_uint_8_list> bytes,
) { ) {
return _wire_platform( return _wire_get_tx_config(
port_, port_,
bytes,
); );
} }
late final _wire_platformPtr = _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>('wire_platform'); late final _wire_get_tx_configPtr =
late final _wire_platform = _wire_platformPtr.asFunction<void Function(int)>(); _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64, ffi.Pointer<wire_uint_8_list>)>>('wire_get_tx_config');
late final _wire_get_tx_config =
_wire_get_tx_configPtr.asFunction<void Function(int, ffi.Pointer<wire_uint_8_list>)>();
void wire_rust_release_mode( ffi.Pointer<wire_uint_8_list> new_uint_8_list_0(
int port_, int len,
) { ) {
return _wire_rust_release_mode( return _new_uint_8_list_0(
port_, len,
); );
} }
late final _wire_rust_release_modePtr = late final _new_uint_8_list_0Ptr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>('wire_rust_release_mode'); _lookup<ffi.NativeFunction<ffi.Pointer<wire_uint_8_list> Function(ffi.Int32)>>('new_uint_8_list_0');
late final _wire_rust_release_mode = _wire_rust_release_modePtr.asFunction<void Function(int)>(); late final _new_uint_8_list_0 = _new_uint_8_list_0Ptr.asFunction<ffi.Pointer<wire_uint_8_list> Function(int)>();
void free_WireSyncReturn( void free_WireSyncReturn(
WireSyncReturn ptr, WireSyncReturn ptr,
@ -202,6 +229,13 @@ class NativeWire implements FlutterRustBridgeWireBase {
final class _Dart_Handle extends ffi.Opaque {} final class _Dart_Handle extends ffi.Opaque {}
final class wire_uint_8_list extends ffi.Struct {
external ffi.Pointer<ffi.Uint8> ptr;
@ffi.Int32()
external int len;
}
typedef DartPostCObjectFnType typedef DartPostCObjectFnType
= ffi.Pointer<ffi.NativeFunction<ffi.Bool Function(DartPort port_id, ffi.Pointer<ffi.Void> message)>>; = ffi.Pointer<ffi.NativeFunction<ffi.Bool Function(DartPort port_id, ffi.Pointer<ffi.Void> message)>>;
typedef DartPort = ffi.Int64; typedef DartPort = ffi.Int64;

View file

@ -1,16 +1,24 @@
import 'dart:async'; 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:camerawesome/camerawesome_plugin.dart';
import 'package:flutter/material.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:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'ffi.dart';
import 'utils/mlkit_utils.dart';
void main() { void main() {
runApp(const MyApp()); runApp(const MyApp());
} }
enum CuttleState {
unitialized,
receiving,
received,
}
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
const MyApp({super.key}); const MyApp({super.key});
@ -41,6 +49,10 @@ class _MyHomePageState extends State<MyHomePage> {
late final Stream<List<String>> _barcodesStream = _barcodesController.stream; late final Stream<List<String>> _barcodesStream = _barcodesController.stream;
final _scrollController = ScrollController(); final _scrollController = ScrollController();
final TxConfig? _txConfig = null;
final _rxData = <Uint8>[];
final _cuttleState = CuttleState.unitialized;
@override @override
void dispose() { void dispose() {
_barcodesController.close(); _barcodesController.close();

View file

@ -6,8 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib] [lib]
crate-type = ["cdylib", "lib"] crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
cuttle = { path = "../../", default-features = false }
flutter_rust_bridge = "1" flutter_rust_bridge = "1"
raptorq = "1.7.0"
rkyv = { version = "0.7.42", features = ["validation"] }

View file

@ -1,59 +1,29 @@
// This is the entry point of your Rust library. use rkyv::Deserialize;
// When adding new code to your project, note that only items used
// here will be transformed to their Dart equivalents.
// A plain enum without any fields. This is similar to Dart- or C-style enums. #[derive(Debug, Clone)]
// flutter_rust_bridge is capable of generating code for enums with fields pub struct TxConfig {
// (@freezed classes in Dart and tagged unions in C). pub len: u64,
pub enum Platform { pub mtu: u16,
Unknown, pub description: String,
AndroidBish,
Ios,
Windows,
Unix,
MacIntel,
MacApple,
Wasm,
} }
// A function definition in Rust. Similar to Dart, the return type must always be named impl From<cuttle::TxConfig> for TxConfig {
// and is never inferred. fn from(value: cuttle::TxConfig) -> Self {
pub fn platform() -> Platform { TxConfig {
// This is a macro, a special expression that expands into code. In Rust, all macros len: value.len,
// end with an exclamation mark and can be invoked with all kinds of brackets (parentheses, mtu: value.mtu,
// brackets and curly braces). However, certain conventions exist, for example the description: value.description,
// 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
} }
} }
// The convention for Rust identifiers is the snake_case, pub fn get_tx_config(bytes: Vec<u8>) -> Option<TxConfig> {
// and they are automatically converted to camelCase on the Dart side. if let Ok(archive) = rkyv::check_archived_root::<cuttle::TxConfig>(&bytes) {
pub fn rust_release_mode() -> bool { if let Ok::<cuttle::TxConfig, _>(conf) = archive.deserialize(&mut rkyv::Infallible) {
cfg!(not(debug_assertions)) return Some(conf.into());
} else {
return None;
}
}
None
} }

View file

@ -2,23 +2,42 @@ use super::*;
// Section: wire functions // Section: wire functions
#[no_mangle] #[no_mangle]
pub extern "C" fn wire_platform(port_: i64) { pub extern "C" fn wire_get_tx_config(port_: i64, bytes: *mut wire_uint_8_list) {
wire_platform_impl(port_) wire_get_tx_config_impl(port_, bytes)
}
#[no_mangle]
pub extern "C" fn wire_rust_release_mode(port_: i64) {
wire_rust_release_mode_impl(port_)
} }
// Section: allocate functions // 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: related functions
// Section: impl Wire2Api // Section: impl Wire2Api
impl Wire2Api<Vec<u8>> for *mut wire_uint_8_list {
fn wire2api(self) -> Vec<u8> {
unsafe {
let wrap = support::box_from_leak_ptr(self);
support::vec_from_leak_ptr(wrap.ptr, wrap.len)
}
}
}
// Section: wire structs // Section: wire structs
#[repr(C)]
#[derive(Clone)]
pub struct wire_uint_8_list {
ptr: *mut u8,
len: i32,
}
// Section: impl NewWithNullPtr // Section: impl NewWithNullPtr
pub trait NewWithNullPtr { pub trait NewWithNullPtr {

View file

@ -22,24 +22,17 @@ use crate::api::*;
// Section: wire functions // Section: wire functions
fn wire_platform_impl(port_: MessagePort) { fn wire_get_tx_config_impl(port_: MessagePort, bytes: impl Wire2Api<Vec<u8>> + UnwindSafe) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, Platform>( FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, Option<TxConfig>>(
WrapInfo { WrapInfo {
debug_name: "platform", debug_name: "get_tx_config",
port: Some(port_), port: Some(port_),
mode: FfiCallMode::Normal, mode: FfiCallMode::Normal,
}, },
move || move |task_callback| Ok(platform()), move || {
) let api_bytes = bytes.wire2api();
} move |task_callback| Ok(get_tx_config(api_bytes))
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 || move |task_callback| Ok(rust_release_mode()),
) )
} }
// Section: wrapper structs // Section: wrapper structs
@ -64,25 +57,26 @@ where
(!self.is_null()).then(|| self.wire2api()) (!self.is_null()).then(|| self.wire2api())
} }
} }
impl Wire2Api<u8> for u8 {
fn wire2api(self) -> u8 {
self
}
}
// Section: impl IntoDart // Section: impl IntoDart
impl support::IntoDart for Platform { impl support::IntoDart for TxConfig {
fn into_dart(self) -> support::DartAbi { fn into_dart(self) -> support::DartAbi {
match self { vec![
Self::Unknown => 0, self.len.into_into_dart().into_dart(),
Self::AndroidBish => 1, self.mtu.into_into_dart().into_dart(),
Self::Ios => 2, self.description.into_into_dart().into_dart(),
Self::Windows => 3, ]
Self::Unix => 4,
Self::MacIntel => 5,
Self::MacApple => 6,
Self::Wasm => 7,
}
.into_dart() .into_dart()
} }
} }
impl support::IntoDartExceptPrimitive for Platform {} impl support::IntoDartExceptPrimitive for TxConfig {}
impl rust2dart::IntoIntoDart<Platform> for Platform { impl rust2dart::IntoIntoDart<TxConfig> for TxConfig {
fn into_into_dart(self) -> Self { fn into_into_dart(self) -> Self {
self self
} }

View file

@ -33,19 +33,18 @@ dependencies:
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2 camerawesome: ^1.4.0
ffi: ^2.0.1 ffi: ^2.0.1
flutter_rust_bridge: ^1.45.0 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 google_mlkit_barcode_scanning: ^0.5.0
rxdart: ^0.27.7
image: ^4.0.17
google_mlkit_commons: ^0.2.0 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: dev_dependencies:
flutter_test: flutter_test: