isar / isar

Extremely fast, easy to use, and fully async NoSQL database for Flutter
https://isar.dev
Apache License 2.0
3.54k stars 322 forks source link

Utilizing flutter_rust_bridge to make code safer and more auto-generated? #911

Closed fzyzcjy closed 1 year ago

fzyzcjy commented 1 year ago

Hi thanks for the project :) It seems that the ffi is currently handwritten (e.g. https://github.com/isar/isar/blob/main/packages/isar_core_ffi/src/crud.rs), and there is a lot of unsafe functions there as well as manual conversion between unsafe C pointers and Rust structs.

So, if we use https://github.com/fzyzcjy/flutter_rust_bridge, all of these can be automatically generated, and there is no unsafe code or any manual conversion from C things to Rust things at all.

simc commented 1 year ago

Hey! Your package looks really cool and I'd love to use it.

Unfortunately there are some blockers for me:

fzyzcjy commented 1 year ago

Hi, thanks for your reply :)

I didn't find a lot of unit tests which makes confident releases difficult

We have a ton of e2e tests. e.g. https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/frb_example/pure_dart/dart/lib/main.dart and https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/frb_example/pure_dart/rust/src/api.rs

As well as CI: https://github.com/fzyzcjy/flutter_rust_bridge/actions/runs/3483889157

Also with valgrind check in CI, etc

flutter_rust_bridge has a lot of dependencies. Isar only has 3 and all of them created by the Dart team. Adding so many transitive third party dependencies would impose a lot of difficulties on Isars users for no apparent reason

The dependency that will be introduced is here: https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/frb_dart/pubspec.yaml

Looks like most, if not all, of them can be removed. They are mainly there for frb_dart/bin/* etc, so it should not be hard to separate frb_dart package into two packages and make the core have few dep.

It is unclear to me how performance would be affected. It would almost certainly be a negative effect since they important ffi methods are highly optimized. A benchmark would be helpful comparing hand written to generated performance

/cc @Roms1383 who is doing the work of (a prototype) benchmarking: https://github.com/fzyzcjy/flutter_rust_bridge/pull/755

simc commented 1 year ago

Cool thanks! I'll start thinking about this a little more 👍

fzyzcjy commented 1 year ago

You are welcome!

By the way, frb supports Dart to async call Rust, so even though the Rust side is slow to execute (e.g. a slow db query), the Dart thread will not be blocked so UI is smooth.

And also have zero-copy feature, thus if you want to transfer a huge block of bytes, do not need to copy at all

simc commented 1 year ago

All Isar ffi functions support both synchronous and asynchronous calls depending on what kind of transaction is provided 🙂

Zero copy is very important for Isar so that's good.

showurl commented 1 year ago

All Isar ffi functions support both synchronous and asynchronous calls depending on what kind of transaction is provided 🙂

Zero copy is very important for Isar so that's good.

Hey bro, how's the investigation going?

simc commented 1 year ago

I don't feel like this will reduce the complexity of Isar in a significant way. The FFI bridge hasn't ever been a problem so I won't add more dependencies or codegen. Still love your package and I'll definitely use it for other projects 💪

fzyzcjy commented 8 months ago

@simc Hi, I have just released flutter_rust_bridge v2. I am NOT speaking to persuade you into using FRB, since your package is already quite mature, and I appreciate the highly optimized ffi layer; just want to share some updates and thoughts and discusses here, since your package is quite popular and is also Rust+Flutter/Dart :)

When writing flutter_rust_bridge, the thing that worries me the most is that, I accidentally run into any Undefined Behavior of rust :/ And one of the reasons why I write a code generator is also that, I am afraid that if I write all those C glues manually in my app, one day when I am sleepy, I will introduce a subtle undefined behavior bug and is super hard to be debugged.

Thus, when seeing similar things (e.g. this Rust FFI package), I often go and look at how other people deal with the details. I briefly looked at Isar's code and infra, and wonder how do you ensure there is no memory safety bugs, undefined behaviors, etc?

For example, it seems that there is no Valgrind or sanitizers (ASAN/MSAN/LSAN). In addition, there are many raw pointers in the Rust ffi layer. Thus, as an instance, we need to ensure there does not exist any possibilities of aliasing scenario, i.e. two mutable pointer to same object.

By the way, I am curious, does the "create new isolate and initialize dynamic library (~250us on my test) + use highly optimized sync calls" be faster than "do not create isolate or init dylib + use async calls (Dart's PostCObject)"? The former is definitely faster because of the optimized sync calls, but I am worried about the speed of initialization.

P.S. About flutter_rust_bridge: