thlorenz / rid

Rust integrated Dart framework providing an easy way to build Flutter apps with Rust.
63 stars 4 forks source link

The right way to send a large buffer Vec<u8> from rust to dart #5

Closed chertov closed 2 years ago

chertov commented 3 years ago

For example, in my use case i need to connect to backend via websockets from rust. I start the connection process in Store::create() function in a new thread, i want to load jpeg pictures and render them with flutter. I can't create #[rid::reply] enum Replay with variant contains Vec<u8> field error: For replies with a single field it needs to be a u64 or String, i.e. 'Started(u64) or Started(String)' to use it like here https://github.com/thlorenz/rid-examples/blob/49de40408064833823aad08dbd4e03b928ff3265/flutter/todo_cubit/lib/blocs/cubit/todo_cubit.dart#L31 And #[rid::replay] can't be a struct: error: rid::reply attribute can only be applied to enums I can keep data in the state, but it's not very convenient.. i need to send 'update' message and get replay back to clear the buffer in the store. How to do this right way? Is this possible today? Thanks!

chertov commented 3 years ago

seems Vec<u8> fields in the state don't work now

plugin/lib/generated/rid_api.dart:321:20: Error: Type 'ffigen_bind.Vec_Rawu8' not found.
  dart_ffi.Pointer<ffigen_bind.Vec_Rawu8> get jpeg_data => rid_ffi.rid_store_jpeg_data(this);
                   ^^^^^^^^^^^^^^^^^^^^^

only vectors of struct #[rid::model] are working

chertov commented 3 years ago

seems Vec<u8> fields in the state don't work now

the problem is here: https://github.com/thlorenz/rid/blob/0a5f33a80735bd3c13f4da989ebdf603315c9b53/rid-macro-impl/src/model/dart.rs#L72

my dirty little hack for Vec:

            DartType::Vec(inner) => {
                let raw = if inner == "u8" {
                    ""
                } else {
                    "Raw"
                };
                format!(
                    "{dart_ffi}.Pointer<{ffigen_bind}.Vec_{raw}{ty}>",
                    dart_ffi = DART_FFI,
                    ffigen_bind = FFI_GEN_BIND,
                    raw = raw,
                    ty = inner
                )
            },

it might be better to do this with recursively nested types, but I haven't learned enough of the structure of the codegen yet

thlorenz commented 3 years ago

I'm sorry you're running into these problems, but I'm happy you're digging in and are encountering work arounds. rid is still in somewhat early stage (which is why I'm happy to have sponsors so I can dig in more).

The whole Raw business may go away soon since Dart 2.13 added typedefs which we could use to rename dangerous types on the Dart side. I think having this in Rust makes things a lot more complex.

If you want to share the code you're working on so I can use it to extract test cases to fix please do.

thlorenz commented 3 years ago

I fixed a lot of field access cases for vecs. Which means a vec attached to a struct like the store can now be sent if the item is a primitive or String as well as the cases that worked before. If you want to see which specifically, please consult this test.

For exported functions not all of those are supported yet since that is a different case as the returned Vec is no longer accessible from the Rust side and also needs to be cleaned up from Dart.

I'm looking into adding support for HashMap and similar data types yet. In order to address the case you need first could you please provide a small sample of code that you would like to work with Rid @chertov ?

chertov commented 3 years ago

I haven't tried the updated version yet and I don't fully understand the concept of my app using rid. This will change a lot of things in my app. Initially, I had a Flutter application and only a small part of the cryptography was in Rust. I was sending data from rust to dart via callbacks (ffi, wasm). But now with rid I don't need to implement logic and connections in dart. It looks like in dart, I need to leave only the rendering of the state, and transfer everything else to rust.

My library is used by several applications. It looks like I can't do several different states in the same code right now. With cfg! it is possible with cargo features, but in one application you cannot have several states now.

thlorenz commented 3 years ago

See https://github.com/thlorenz/rid/pull/13 which adds lots more types you can return from an export. Namely Vec<&u8> is supported as you're expected to hold on to the actual data (the u8s) on the rust side. LMK if that addressed part of your needs and if not which return type you'd need.