How to use Rust futures in callbacks? - asynchronous

Is there any way to use futures in callbacks? For example...
// Send message on multiple channels while removing ones that are closed.
use smol::channel::Sender;
...
// (expecting bool, found opaque type)
vec_of_sender.retain( |sender| async {
sender.send(msg.clone()).await.is_ok()
});
My work-around is to loop twice: On the first pass I delete closed senders (non-async) and on the second I do the actual send (async using for sender in ...). But it seems like I should be able to do it all in a single retain() call.

You can't use retain in this way. The closure that retain accepts must implement FnMut(&T) -> bool, but every async function returns an implementation of Future.
You can turn an async function into a synchronous one by blocking on it. For example, if you were using tokio, you could do this:
use tokio::runtime::Runtime;
let rt = Runtime::new().unwrap();
vec_of_sender.retain(|sender| {
rt.block_on(async { sender.send().await.is_ok() })
});
However, there is overhead to adding an async runtime, and I have a feeling that you are trying to solve the wrong problem.

The closure passed to retain must return a bool, but every async function returns impl Future. Instead, you can use Stream, which is the asynchronous version of Iterator. You can convert the vector into a Stream:
let stream = stream::iter(vec_of_sender);
And then use the filter method, which accepts an asynchronous closure and returns a new Stream:
let vec_of_sender = stream.filter(|sender| async {
sender.send(msg.clone()).await.is_ok()
}).collect::<Vec<Sender>>();

To avoid creating a new Vec, you can also use swap_remove:
let mut i = 0usize;
while i < vec_of_sender.len() {
if vec_of_sender[i].send(msg.clone()).await.is_ok() {
i += 1;
} else {
vec_of_sender.swap_remove(i);
}
}
Note that this will change the order of the vector.

Related

How does rust simply get a return from a closure

Here's the problem I'm having with tauri.
'return' shows you the return value I need, and I know for a fact that writing it this way does not work at all.
'pick_file' is called asynchronously, and I know that message passing seems to work, but is there an easier way to get the value I need.
#[tauri::command]
fn open_file() -> String {
dialog::FileDialogBuilder::default()
.add_filter("data", &["json"])
.pick_file(|path_buf| match path_buf {
Some(p) => return format!("{}", p.to_str().unwrap()),
_ => return "".into()
});
}
First, return in a closure returns from the closure and not from the function that contains it.
The more fundamental issue is that you can't return a String from open_file() if you use FileDialogBuilder::pick_file(). According to the documentation, pick_file() is non-blocking and returns immediately without waiting for the user to pick the file. What you can do in the closure is send the file down a channel, and pick it up elsewhere.

Understanding how to implement a Wrapper type for a Stream

I was wondering if anyone could give me any pointers on the best way to go about handling wake ups when writing a wrapper for a Stream.
For context I've got a Byte stream coming in via a HTTP request (using reqwest) and I'm doing some filtering and mapping on that stream to handle validation and deserialization. Effectively whenever the inner stream produces a value I want this stream to (potentially) emit a value.
** Edit **
An additional caveat is the stream needs to also hold a small amount of state (A Vec<String>) that it needs to be able to reference on each poll - (the columns property)
The Solution
This turned out to be me just not understanding how the stream was working under the hood. Rodrigo's answer below was completely correct. I did just need to return Poll::Pending from the inner stream, however I was making the mistake of matching on that and returning my own Poll::Pending which was why the stream wasn't being appropriately woken up.
If it's useful to anyone, instead of matching on the output of inner_stream.poll_next(), I ended up just mapping the Some value and returning that to ensure that I was building off the Polls of the inner stream eg:
return Pin::new(&mut this.stream).poll_next(cx).map(|data| { ... })
Thanks for everyone who commented and helped out!
Context for the original question
The wrapper type:
pin_project! {
#[derive(Default)]
struct QueryStream<T, S> where S: Stream, T: DeserializeOwned {
columns: Vec<String>,
#[pin]
stream: S,
has_closed: bool,
_marker: PhantomData<T>
}
}
The only implementation of Stream that I've managed to get to work on the wrapper type is one that spins on the inner stream when it returns Poll::Pending. This doesn't seem ideal though as I believe it would block until a value is emitted?
impl<T, S> Stream for QueryStream<T, S>
where
T: DeserializeOwned,
S: Stream<Item = std::result::Result<Bytes, reqwest::Error>>,
{
type Item = Result<T>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut this = self.project();
loop {
if *this.has_closed {
return Poll::Ready(None);
}
match Pin::new(&mut this.stream).poll_next(cx) {
Poll::Ready(Some(data)) => {
// Parsing Logic Here
return Poll::Ready(Some(Ok::<_, Error>(resp)));
}
Poll::Ready(None) => return Poll::Ready(None),
Poll::Pending => {}
}
}
}
}
Trying to remove the loop (and changing the Poll::Pending match arm to Poll::Pending => Poll::Pending) generally results in poll only being called once before hanging, from my very rough understanding of why this is, it's because I'm dropping the reference to the waker when I return from this function, as it's not stored anywhere.
However I'm struggling to work out how to arrange my struct/code to enable the storage of that reference or alternatively what the best way to enable the use of that waker is? Is anyone able to explain how this problem can be solved?
Many thanks in advance!

Should I return await in Rust?

In JavaScript, async code is written with Promises and async/await syntax similar to that of Rust. It is generally considered redundant (and therefore discouraged) to return and await a Promise when it can simply be returned (i.e., when an async function is executed as the last thing in another function):
async function myFn() { /* ... */ }
async function myFn2() {
// do setup work
return await myFn()
// ^ this is not necessary when we can just return the Promise
}
I am wondering whether a similar pattern applies in Rust. Should I prefer this:
pub async fn my_function(
&mut self,
) -> Result<()> {
// do synchronous setup work
self.exec_command(
/* ... */
)
.await
}
Or this:
pub fn my_function(
&mut self,
) -> impl Future<Output = Result<()>> {
// do synchronous setup work
self.exec_command(
/* ... */
)
}
The former feels more ergonomic to me, but I suspect that the latter might be more performant. Is this the case?
One semantic difference between the two variants is that in the first variant the synchronous setup code will run only when the returned future is awaited, while in the second variant it will run as soon as the function is called:
let fut = x.my_function();
// in the second variant, the synchronous setup has finished by now
...
let val = fut.await; // in the first variant, it runs here
For the difference to be noticeable, the synchronous setup code must have side effects, and there needs to be a delay between calling the async function and awaiting the future it returns.
Unless you have specific reason to execute the preamble immediately, go with the async function, i.e. the first variant. It makes the function slightly more predictable, and makes it easier to add more awaits later as the function is refactored.
There is no real difference between the two since async just resolves down to impl Future<Output=Result<T, E>>. I don't believe there is any meaningful performance difference between the two, at least in my empirical usage of both.
If you are asking for preference in style then in my opinion the first one is preferred as the types are clearer to me and I agree it is more ergonomic.

A function to read data from FireBase but requires Unit instead

I've made a function that calls on the FireBase database and will return a MutableList. However, when I try to make it return on a specific line, it says it requires a Unit instead of the MutableList.
fun firebaseCollect(key: String): MutableList<CustomList> {
var ref = FirebaseDatabase.getInstance().getReference(key)
var lessonList = mutableListOf<CustomList>()
ref.addValueEventListener(object: ValueEventListener{
override fun onCancelled(p0: DatabaseError?) {
}
override fun onDataChange(p0: DataSnapshot?) {
if (p0!!.exists()) {
lessonList.clear()
for (index in p0.children) {
val lesson = index.getValue(CustomList::class.java)
lessonList.add(lesson!!)
}
return lessonList
}
}
})
return lessonList
}
Type mismatch. Required: Unit, Found: MutableList< CustomList > is found at the first return lessonList since what I am asking for it to return is a MutableList not a Unit. I am confused as to why this happens. The last return would give an empty list. It is currently my first jab at FireBase and this is a practice I am doing. The rules for read and write have been set to public as well. How should I recode the function that I am able to return the data from FireBase into the function and passed back to the caller?
Firebase APIs are asynchronous. For your case, that means addValueEventListener returns immediately. Then, some time later, the listener you passed to it will be invoked with the data you're looking for. Your return statement in the callback doesn't actually return any data to the caller. In fact, you can't return anything from that callback. At the bottom of your function, when you return lessonList, you're actually returning an initially empty list to the caller, which may change later when the data finally arrives.
To get a better sense of how your code works, put log lines in various places, and see for yourself the order in which the code is invoked. You can read more about why Firebase APIs are asynchronous by reading this article. The bottom line is that you'll need to interact with the asynchronous APIs using asynchronous programming techniques. Don't try to make them synchronous.
Data is loaded asynchronously from Firebase. Once the data is fetched the method onDatachange() is invoked.
You are returning lessonList inside onDatachange(). Return type of onDatachange() is void(Unit in kotlin). This is the reason for the type mismatch error.
For returning the result from the method onDatachange() try this.

async/await / assignments from function returns

Currently having a simple funtion :
async function getItem(id) {
const item = await ... doing a bunch of time consuming stuff
return item;
}
Coming from synchronous languages, and still understanding async/awaits from the surface; i'd expected the following to return the resolved item :
const item = getItem('items-8');
console.log(item); // Just getting a promise
The question is a bit 'cosmetic', but as async/await kind of solves callbacks, i'd be looking to get further and even avoid thenables things.
Is it possible to get such one-liner variable assignment with async/awaits ? What would be the syntax/code structure ?
async..await is syntactic sugar for ES6 promises, it allows to write asynchronous code in synchrounous-like manner. The code that uses promises cannot be synchronous, because promises are asynchronous.
In order to be written in synchronous manner, the code that uses getItem should reside in async function, too. If it is top-level and doesn't reside in another function (like application initialization code), it can reside in async IIFE.
It's either
getItem('items-8').then(item => {
...
});
Or
// inside `async` function
const item = await getItem('items-8');
...

Resources