The main problem I am trying to solve is,
I have an implementation to read messages from stdin, parse them and call the appropriate handler. I have implemented send
and send_sync
. send
sends the messages and responses are handled asynchronously by the stdin loop. send_sync
waits for a response and returns it as Result<Message, Error>
.
To implement send_sync
, The program keeps a map of expected message id and callback fn in HashMap<i64, Arc<dyn Callback>>
where Callback
is, FnOnce(Message) -> Result<(), String> + Send + Sync + 'static
.
I am using oneshot channels and the code looks like this,
let (tx,rx) = tokio::sync::oneshot::channel();
self.callbacks.insert(expected_msg_id, Arc::new(move |msg: Message| -> Result<(), String> {
tx.send(msg);
Ok(())
}));
I was using Fn
instead of FnOnce
but it complains closure implements FnOnce
not Fn
(which makes sense I thinkk, Is it because I am moving tx
handle and it's dropped at the end?)
193 | let func = move |msg: Message| -> Result<(), String> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this closure implements `FnOnce`, not `Fn`
194 | tx.send(msg);
| -- closure is `FnOnce` because it moves the variable `tx` out of its environment
...
199 | .insert(msg.body.msg_id.unwrap_or(0) + 1, Arc::new(func));
| -------------- the requirement to implement `Fn` derives from here
So I changed the signature to FnOnce
and now it says,
error[E0161]: cannot move a value of type `dyn FnOnce(Message) -> Result<(), std::string::String> + Send + Sync`
--> src/lib.rs:123:37
|
123 | if let Err(e) = callback(message) {
| ^^^^^^^^ the size of `dyn FnOnce(Message) -> Result<(), std::string::String> + Send + Sync` cannot be statically determined
error[E0507]: cannot move out of an `Arc`
--> src/lib.rs:123:37
|
123 | if let Err(e) = callback(message) {
| ^^^^^^^^---------
| |
| value moved due to this call
| move occurs because value has type `dyn FnOnce(Message) -> Result<(), std::string::String> + Send + Sync`, which does not implement the `Copy` trait
I am not sure how to fix this problem. Please let me know if there is a cleaner/easy way to solve the original problem or if there is a good way to solve this particular problem? Thank you