flutter_rust_bridge icon indicating copy to clipboard operation
flutter_rust_bridge copied to clipboard

How to call dart functions in rust?

Open m-haisham opened this issue 2 years ago • 16 comments

I noticed the documentation was missing how a dart function can be called in rust.

m-haisham avatar May 06 '22 01:05 m-haisham

Hi! Thanks for opening your first issue here! :smile:

welcome[bot] avatar May 06 '22 01:05 welcome[bot]

This is not directly supported yet, but you can always use some callback-map-like approach. Feel free to make a PR!

fzyzcjy avatar May 06 '22 01:05 fzyzcjy

callback-map-like approach

Could you perhaps describe this approach.

m-haisham avatar May 06 '22 01:05 m-haisham

You can look here (https://github.com/sunshine-protocol/frusty-logger) at how you can do that, I made a log crate compatible logger that works with flutter and dart. So, in Rust the log crate you can build/implement the back-end logging, and I made a way to bind the print and debugPrint from dart to rust, so rust whenever you use log::info!("....") it will call the print function in dart.

shekohex avatar May 11 '22 16:05 shekohex

Hi there! I'm new to flutter+dart & rust. I'd like to be able to log from rust to flutter.

As far as I understand it, http://cjycode.com/flutter_rust_bridge/feature/stream.html is the basis best used for that purpose.

@fzyzcjy wrote about including a logging facility directly into the flutter_rust_bridge here: https://github.com/fzyzcjy/flutter_rust_bridge/issues/348 But said it was blocked by the same reason as cancelable tasks: https://github.com/fzyzcjy/flutter_rust_bridge/pull/333#issuecomment-1037079219

I did manage to incoperate @Desdaemon's example from https://gist.github.com/Desdaemon/be5da0a1c6b4724f20093ef434959744 into my playground app.

Since the counter starts from 0 again every time I get back to the page where I display it, I'm quite certain I created a memory leak with this, because as discussed @ https://github.com/fzyzcjy/flutter_rust_bridge/issues/347 the Rust side doesn't know when Dart stops listening and keeps on churning out integers anyway. And Flutter creates new instances whenever that page get's opened again.

Also from that sample I don't see how I could push data into that sink from other places in my rust code, outside of the tick function.

There is an incomplete "Simplified for demonstration" example for pushing LogEntries from Rust to Dart @ http://cjycode.com/flutter_rust_bridge/feature/stream.html - But I couldn't find out yet how to use OnceCell or Mutex or RwLock to get that sample to compile & run. There are some more snippets @ https://github.com/fzyzcjy/flutter_rust_bridge/issues/398 but I can't use OnceCell like @LambdaMan2K as this seems to be an unstable feature you would need to switch to the nightly Rust compiler for (which I'd prefer not to as a Rust newbie..)

I also cloned https://github.com/sunshine-protocol/frusty-logger referenced by @shekohex but could neither get it running nor understand how it should work. Also I'd prefer a minimal sample that helps me understand the basics to using a library.

Can somebody help please? Thank you!

thomas725 avatar Jun 06 '22 09:06 thomas725

@thomas725 Let's discuss in https://github.com/fzyzcjy/flutter_rust_bridge/issues/486 since I guess this is a common question people may face.

fzyzcjy avatar Jun 06 '22 09:06 fzyzcjy

Thank you @fzyzcjy for documenting your rust->flutter logging setup and allowing me to copy it :)

A question concerning the more generic topic of this thread: If I use a Stream to get data continuously generated in a loop in rust (as in @Desdaemon's gist) into flutter for displaying, how can I make the rust loop stop, when the flutter screen displaying the data is closed?

thomas725 avatar Jun 09 '22 13:06 thomas725

how can I make the rust loop stop

I guess not supported yet? Feel free to make a PR!

fzyzcjy avatar Jun 09 '22 13:06 fzyzcjy

how can I make the rust loop stop, when the flutter screen displaying the data is closed?

Try using an atomic bool, and expose a function from Rust to dart to set the value of it to be false. so that in your loop in each iteration you check if you should stop or not.

shekohex avatar Jun 09 '22 13:06 shekohex

@shekohex yes, I thought of something like that too, but where in flutter do I put the call to rust to set that "continue" boolean to false? All the code on the flutter side for my screen is in a method Widget build(BuildContext context). Is there a deconstructor or something like that which I can override?

thomas725 avatar Jun 09 '22 13:06 thomas725

I guess depends on your code, but the dispose method on the state should do it.

shekohex avatar Jun 09 '22 13:06 shekohex

@shekohex thank you, exactly what I've been looking for!

Now how do I write this in rust without the compiler complaining that it's unsafe and telling me I need an unsafe block whenever I access KEEP_TICKING?

static mut KEEP_TICKING: bool = false;

// can't omit the return type yet, this is a bug
pub fn tick(sink: StreamSink<u16>) -> Result<()> {
    let mut ticks = 0;
    KEEP_TICKING = true;
    while KEEP_TICKING {
        sink.add(ticks);
        info!("sunk tick: {}", ticks);
        sleep(ONE_SECOND);
        if ticks == u16::MAX {
            break;
        }
        ticks += 1;
    }
    Ok(())
}

pub fn stopTicking() {
    KEEP_TICKING = false;
}

thomas725 avatar Jun 09 '22 14:06 thomas725

Do not use just bool you will need to use AtomicBool and also remove mut from that, static mut is not good IMO.

shekohex avatar Jun 09 '22 14:06 shekohex

Ah, okey, thanks for the hint!

EDIT: I think now I got it:

static KEEP_TICKING: AtomicBool = AtomicBool::new(false);

// can't omit the return type yet, this is a bug
pub fn tick(sink: StreamSink<u16>) -> Result<()> {
    let mut ticks = 0;
    KEEP_TICKING.store(true, Ordering::Relaxed);
    while KEEP_TICKING.load(Ordering::Relaxed) {
        sink.add(ticks);
        info!("sunk tick: {}", ticks);
        sleep(ONE_SECOND);
        if ticks == u16::MAX {
            break;
        }
        ticks += 1;
    }
    Ok(())
}

pub fn stopTicking() {
    KEEP_TICKING.store(false, Ordering::Relaxed);
}

thomas725 avatar Jun 09 '22 14:06 thomas725

IMHO you should use store(https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.store) requires &self and does atomic things internally. The get_mut requires &mut self instead of doing real atomic operations.

fzyzcjy avatar Jun 09 '22 14:06 fzyzcjy

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Aug 08 '22 20:08 stale[bot]

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new issue.

github-actions[bot] avatar Aug 30 '22 00:08 github-actions[bot]