How can I put an async function with a reference variable inside a function? - asynchronous

The title should have already suggest you I have noticed How can I put an async function into a map in Rust? and I have failed to proceed my work. Here is my sample code based on above link:
extern crate async_std;
use async_std::task;
use std::future::Future;
use std::pin::Pin;
use std::boxed::Box;
type VarIn = &String;
type VarOut = String;
type FnType = Box< dyn Fn(VarIn) -> Pin<Box<dyn Future<Output=VarOut>>> >;
async fn test(v: FnType) {
println!("{}", v("hi".to_string()).await)
}
async fn var(s: &String) -> String {
format!("var:{}", s)
}
fn main() {
task::block_on(test(Box::new(|s| Box::pin(var(s)))));
}
If VarIn is replaced by String instead of &String then everything is fine. However, my use case needs me to pass a reference instead to fulfill my usage (I use it in an infinite loop, so I can't pass the ownership to this function). What should I do to successfully pass the reference to async function, or there is some design to circumvent this?

You have to specify in the type definitions that are used in the function test what the lifetime of the reference is and how it relates to the Future.
VarIn<'a> = &'a String;
VarOut = String;
FnType<'a> = Box<dyn Fn(VarIn<'a>) -> Pin<Box<dyn Future<Output=VarOut> + 'a>>>;
This won't ultimately work, because the String created in test will be dropped at the bottom of the function, while the &String will be returned with the Future. You can use an &str and get this example to work, and that is what I suggest.
VarIn<'a> = &'a str
VarOut = String
FnType<'a> = Box<dyn Fn(VarIn<'a>) -> Pin<Box<dyn Future<Output=VarOut> + 'a>>>;
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d86d8b57b556c3d4c4e0282f890a2228

Related

Rust: What is the output of Some(Option<T>)?

In the Learning Rust by examples website, there is a following code:
use std::fmt::Debug;
trait PrintInOption {
fn print_in_option(self);
}
// Because we would otherwise have to express this as `T: Debug` or
// use another method of indirect approach, this requires a `where` clause:
impl<T> PrintInOption for T where
Option<T>: Debug {
// We want `Option<T>: Debug` as our bound because that is what's
// being printed. Doing otherwise would be using the wrong bound.
fn print_in_option(self) {
println!("{:?}", Some(self));
}
}
fn main() {
let vec = vec![1, 2, 3];
vec.print_in_option();
}
Question:
In println!("{:?}", Some(self));, self is of type Option, what does Some(self) returns in this case? When I ran the code, it prints the vector.
In the line
println!("{:?}", Some(self));
self has type T (not Option). Some() is a constructor of the Option enum, so the expression
Some(self)
has the type Option<T>. In the main() function, T = Vec<i32>, so the type that gets printed is an Option<Vec<i32>>.

Using async functions that borrow arguments in contexts where trait object is needed

I've recently started playing with async streams in Rust, and I keep finding myself in situations where I want to use async functions in the implementation of a Stream. The async functions often come from libraries I don't control, but for the sake of example suppose they look like this:
async fn bar_str(s: &str) -> String {
s.to_string()
}
async fn bar_string(s: String) -> String {
s
}
Also to keep things simple suppose I'm just trying to use these functions to implement a trait like the following (no actual stream stuff involved):
use std::future::Future;
trait Foo {
fn bar(self) -> Box<dyn Future<Output = String>>;
}
For the String case this just works as you'd expect:
impl Foo for String {
fn bar(self) -> Box<dyn Future<Output = String>> {
Box::new(bar_string(self))
}
}
For the case where the async function borrows, it doesn't.
impl Foo for &str {
fn bar(self) -> Box<Future<Output = String>> {
Box::new(bar_str(self))
}
}
This fails to compile:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter '_ in function call due to conflicting requirements
--> foo.rs:23:18
|
23 | Box::new(bar_str(self))
| ^^^^^^^^^^^^^
|
...
I can understand why this is a problem, and I understand that the async fn syntax provides special handling for borrowed arguments like this (although I don't know anything about how it's actually checked, desugared, etc.).
My question is about what the best thing is to do in these situations generally. Is there some way I can reproduce the magic async fn is doing in my non-async fn code? Should I just avoid borrowing in async functions (when I can, since that's often a decision I didn't make)? In the code I'm currently writing I'm happy to use experimental or not-necessarily-future-proof solutions if they make reading and writing this kind of thing nicer.
I think that the problem is not so much in the async but in the Box<dyn Trait> thing. In fact it can be reproduced with a simple trait:
use std::fmt::Debug;
trait Foo {
fn foo(self) -> Box<dyn Debug>;
}
impl Foo for String {
fn foo(self) -> Box<dyn Debug> {
Box::new(self)
}
}
impl Foo for &str {
fn foo(self) -> Box<dyn Debug> {
Box::new(self) // <--- Error here (line 15)
}
}
The full error message is:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:15:18
|
15 | Box::new(self)
| ^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the impl at 13:14...
--> src/lib.rs:13:14
|
13 | impl Foo for &str {
| ^
note: ...so that the expression is assignable
--> src/lib.rs:15:18
|
15 | Box::new(self)
| ^^^^
= note: expected `&str`
found `&str`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> src/lib.rs:15:9
|
15 | Box::new(self)
| ^^^^^^^^^^^^^^
= note: expected `std::boxed::Box<(dyn std::fmt::Debug + 'static)>`
found `std::boxed::Box<dyn std::fmt::Debug>`
There is a nice hint about what is going on in the last two lines... what is this Box<(dyn Debug + 'static)> thing?
When you write dyn Trait there is actually an implicit 'static constraint to the type that implements that trait, so these two are the same thing:
Box<dyn Debug>
Box<(dyn Debug + 'static)>
But that means that we can only box a value whose type is 'static. And &'a str is not a static type, so it cannot be boxed that way.
The easy solution is, as usual, to clone, if at all possible. This compiles and it's not too ugly:
impl Foo for &str {
fn foo(self) -> Box<dyn Debug> {
Box::new(self.to_owned())
}
}
Or if you only use static strings, then &'static str is actually static and you can write:
impl Foo for &'static str {
fn foo(self) -> Box<dyn Debug> {
Box::new(self)
}
}
If you actually want or need to borrow, then the boxed dyn object has to be generic over some lifetime. You have to change the return type of your trait, something like this:
use std::fmt::Debug;
trait Foo<'a> {
fn foo(self) -> Box<dyn Debug + 'a>;
}
impl Foo<'static> for String {
fn foo(self) -> Box<dyn Debug> {
Box::new(self)
}
}
impl<'a> Foo<'a> for &'a str {
fn foo(self) -> Box<dyn Debug + 'a> {
Box::new(self)
}
}
But beware now that Box<dyn Debug + 'a> is not a static type by itself, but the type itself has a lifetime of 'a.

It is possible to collect a &mut from an iterator?

I am trying to learn more about ownership. Here is some code that doesn't work because collect doesn't let you get a &mut String:
fn search(word: &str, data: &mut Vec<String>) {
data = data
.iter()
.filter(|x| x.contains(word))
.collect::<&mut Vec<String>>();
}
I think I could just return a cloned version, but is this the only/preferred way to do it?
No, it is not possible. For this to be possible, collect would have to return a reference to something it created, and that's not possible.
You are looking for Vec::retain:
fn search(word: &str, data: &mut Vec<String>) {
data.retain(|x| x.contains(word));
}
If you didn't want to mutate the passed-in data, you would indeed need to return a new Vec:
fn search<'a>(word: &str, data: &'a [String]) -> Vec<&'a String> {
data.iter().filter(|x| x.contains(word)).collect()
}
See also:
Is there any way to return a reference to a variable created in a function?
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec) or Box (&Box) as a function argument?

Is it safe to use a raw pointer to access the &T of a RefCell<HashMap<T>>?

I have a cache-like structure which internally uses a HashMap:
impl Cache {
fn insert(&mut self, k: u32, v: String) {
self.map.insert(k, v);
}
fn borrow(&self, k: u32) -> Option<&String> {
self.map.get(&k)
}
}
Playground with external mutability
Now I need internal mutability. Since HashMap does not implement Copy, my guess is that RefCell is the path to follow. Writing the insert method is straight forward but I encountered problems with the borrow-function. I could return a Ref<String>, but since I'd like to cache the result, I wrote a small Ref-wrapper:
struct CacheRef<'a> {
borrow: Ref<'a, HashMap<u32, String>>,
value: &'a String,
}
This won't work since value references borrow, so the struct can't be constructed. I know that the reference is always valid: The map can't be mutated, because Ref locks the map. Is it safe to use a raw pointer instead of a reference?
struct CacheRef<'a> {
borrow: Ref<'a, HashMap<u32, String>>,
value: *const String,
}
Am I overlooking something here? Are there better (or faster) options? I'm trying to avoid RefCell due to the runtime overhead.
Playground with internal mutability
I'll complement #Shepmaster's safe but not quite as efficient answer with the unsafe version. For this, we'll pack some unsafe code in a utility function.
fn map_option<'a, T, F, U>(r: Ref<'a, T>, f: F) -> Option<Ref<'a, U>>
where
F: FnOnce(&'a T) -> Option<&'a U>
{
let stolen = r.deref() as *const T;
let ur = f(unsafe { &*stolen }).map(|sr| sr as *const U);
match ur {
Some(u) => Some(Ref::map(r, |_| unsafe { &*u })),
None => None
}
}
I'm pretty sure this code is correct. Although the compiler is rather unhappy with the lifetimes, they work out. We just have to inject some raw pointers to make the compiler shut up.
With this, the implementation of borrow becomes trivial:
fn borrow<'a>(&'a self, k: u32) -> Option<Ref<'a, String>> {
map_option(self.map.borrow(), |m| m.get(&k))
}
Updated playground link
The utility function only works for Option<&T>. Other containers (such as Result) would require their own modified copy, or else GATs or HKTs to implement generically.
I'm going to ignore your direct question in favor of a definitely safe alternative:
impl Cache {
fn insert(&self, k: u32, v: String) {
self.map.borrow_mut().insert(k, v);
}
fn borrow<'a>(&'a self, k: u32) -> Option<Ref<'a, String>> {
let borrow = self.map.borrow();
if borrow.contains_key(&k) {
Some(Ref::map(borrow, |hm| {
hm.get(&k).unwrap()
}))
} else {
None
}
}
}
Ref::map allows you to take a Ref<'a, T> and convert it into a Ref<'a, U>. The ugly part of this solution is that we have to lookup in the hashmap twice because I can't figure out how to make the ideal solution work:
Ref::map(borrow, |hm| {
hm.get(&k) // Returns an `Option`, not a `&...`
})
This might require Generic Associated Types (GATs) and even then the return type might be a Ref<Option<T>>.
As mentioned by Shepmaster, it is better to avoid unsafe when possible.
There are multiple possibilities:
Ref::map, with double look-up (as illustrated by Shepmaster's answer),
Ref::map with sentinel value,
Cloning the return value.
Personally, I'd consider the latter first. Store Rc<String> into your map and your method can easily return a Option<Rc<String>> which completely sidesteps the issues:
fn get(&self, k: u32) -> Option<Rc<String>> {
self.map.borrow().get(&k).cloned()
}
As a bonus, your cache is not "locked" any longer while you use the result.
Or, alternatively, you can work-around the fact that Ref::map does not like Option by using a sentinel value:
fn borrow<'a>(&'a self, k: u32) -> Ref<'a, str> {
let borrow = self.map.borrow();
Ref::map(borrow, |map| map.get(&k).map(|s| &s[..]).unwrap_or(""))
}

How can I invoke an unknown Rust function with some arguments using reflection?

I'm having a lot of fun playing around with Rust having been a C# programmer for a long time but I have a question around reflection. Maybe I don't need reflection in this case but given that Rust is strongly typed I suspect I do (I would definitely need it in good ol' C#, bless its cotton socks).
I have this situation:
use std::collections::HashMap;
fn invoke_an_unknown_function(
hashmap: HashMap<String, String>,
// Something to denote a function I know nothing about goes here
) {
// For each key in the hash map, assign the value
// to the parameter argument whose name is the key
// and then invoke the function
}
How would I do that? I'm guessing I need to pass in some sort of MethodInfo as the second argument to the function and then poke around with that to get the arguments whose name is the key in the hash map and assign the values but I had a look around for the reflection API and found the following pre-Rust 1.0 documentation:
Module std::reflect
Module std::repr
[rust-dev] Reflection system
None of these give me enough to go on to get started. How would I implement the function I describe above?
Traits are the expected way to implement a fair amount of what reflection is (ab)used for elsewhere.
trait SomeInterface {
fn exposed1(&self, a: &str) -> bool;
fn exposed2(&self, b: i32) -> i32;
}
struct Implementation1 {
value: i32,
has_foo: bool,
}
impl SomeInterface for Implementation1 {
fn exposed1(&self, _a: &str) -> bool {
self.has_foo
}
fn exposed2(&self, b: i32) -> i32 {
self.value * b
}
}
fn test_interface(obj: &dyn SomeInterface) {
println!("{}", obj.exposed2(3));
}
fn main() {
let impl1 = Implementation1 {
value: 1,
has_foo: false,
};
test_interface(&impl1);
}

Resources