Passing in method reference to a struct - rust

I have a struct other_struct that has a bunch of methods that I need to call depending on certain situations (in this example there is only foo(). I'd like to have a field in other_struct called fmap that stores a HashMap of other_struct methods.
use std::collections::HashMap;
pub struct fn_struct {
pub func: Option<fn(&other_struct) -> ()>,
}
pub struct other_struct<'a> {
fmap: HashMap<String, fn_struct>,
some_str: &'a str,
}
impl<'a> other_struct<'a> {
fn new(some_str: &str) -> other_struct {
let mut new_struct = other_struct {
fmap: HashMap::new(),
some_str: some_str,
};
new_struct.fmap.insert(
String::from("foo"),
fn_struct {
func: Some(other_struct::foo),
},
);
new_struct
}
pub fn foo(&self) {
println!("Do some stuff foo");
}
}
fn main() {
let test_str = "test";
let mut new_o = other_struct::new(test_str);
new_o.fmap.get("foo").unwrap().func.unwrap()(&new_o);
}
I'm struggling with dealing with the lifetimes, as I get the following error:
error[E0308]: mismatched types
--> src/main.rs:22:28
|
22 | func: Some(other_struct::foo),
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's> fn(&'r other_struct<'s>)`
found fn pointer `for<'r> fn(&'r other_struct<'_>)`
I've been reading the high ranked trait bound documentation but it's unclear to me what's happening here. Does this mean the compiler wants me to specify the lifetime of the instance of other_struct somehow in relation to the lifetime of the pointer to the method?

The fn(&other_struct) -> () part of fn_struct is a function pointer that must be able to accept other_structs of any lifetime for<'r, 's> fn(&'r other_struct<'s>) -> (). However, other_struct::foo only accepts a specific lifetime for other_struct<'_>.
You can fix it by specifying that lifetime in some manner, here basically saying its always going to pass in itself:
pub struct fn_struct<'a> {
pub func: Option<fn(&other_struct<'a>) -> ()>,
}
pub struct other_struct<'a> {
fmap: HashMap<String, fn_struct<'a>>,
some_str: &'a str,
}
Or by making foo more generic by unbinding it from 'a.
pub fn foo(_self: &other_struct) {
println!("Do some stuff foo");
}
The difference is subtle, but the original is other_struct<'a>::foo<'b>(&'b other_struct<'a>) -> () and the fixed version is other_struct<'a>::foo<'b, 'c>(&'b other_struct<'c>) -> ().

Related

Why am I getting recursion when trying to implement trait for all reference types

I'm new to rust and having trouble implementing traits. Let me know if I'm going about this the wrong way. I'm trying to setup a trait with two functions for accessing a value. The get_value seems to function properly but when trying to setup the set_value with the &mut self reference, I'm getting the following error
warning: function cannot return without recursing
--> src\main.rs:7:5
|
7 | fn set_value(&mut self, new_value: bool) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
8 | (*self).set_value(new_value);
| ---------------------------- recursive call site
|
= note: `#[warn(unconditional_recursion)]` on by default
= help: a `loop` may express intention better if this is on purpose
warning: 1 warning emitted
Example code:
trait Trait1 {
fn set_value(&mut self, new_value: bool);
fn get_value(&self) -> bool;
}
impl<'a, T> Trait1 for &'a T where T: Trait1 {
fn set_value(&mut self, new_value: bool) {
(*self).set_value(new_value);
}
fn get_value(&self) -> bool {
(*self).get_value()
}
}
impl<'a, T> Trait1 for &'a mut T where T: Trait1 {
fn set_value(&mut self, new_value: bool) {
(**self).set_value(new_value)
}
fn get_value(&self) -> bool {
(**self).get_value()
}
}
struct Foo {
value: bool
}
impl Trait1 for Foo {
fn set_value(&mut self, new_value: bool) {
self.value = new_value;
}
fn get_value(&self) -> bool {
self.value
}
}
fn main() {
}
You're getting the recursion error, because you only deref self once, turning it into a &T -- the type you're currently trying to implement the trait for -- while you want to get at a T. You don't get that error if you deref it twice like you do in the impl for &mut T.
You'll get another error, though, namely that that implementation won't work. You can't just deref a shared reference and then borrow a mutable reference from the referent. *self is a &T. You can't get a &mut T from that no matter how much you deref it.

Can I store an `impl Future` as a concrete type?

tokio::net::TcpStream::connect is an async function, meaning it returns an existential type, impl Future. I would like to store a Vec of these futures in a struct. I've found many questions where someone wants to store multiple different impl Futures in a list, but I only want to store the return type of one. I feel like this should be possible without Box<dyn Future> as I am really only storing a single concrete type, but I cannot figure out how without getting found opaque type errors.
It is possible with the nightly feature min_type_alias_impl_trait. The trick is to create a type alias, and a dummy function from which the compiler can infer a defining use.
#![feature(min_type_alias_impl_trait)]
use tokio::net::TcpStream;
use core::future::Future;
type TcpStreamConnectFut = impl Future<Output = std::io::Result<TcpStream>>;
fn __tcp_stream_connect_defining_use() -> TcpStreamConnectFut {
TcpStream::connect("127.0.0.1:8080")
}
struct Foo {
connection_futs: Vec<TcpStreamConnectFut>,
}
This compiles, but does not work as expected:
impl Foo {
fn push(&mut self) {
self.connection_futs.push(TcpStream::connect("127.0.0.1:8080"));
}
}
error[E0308]: mismatched types
--> src/lib.rs:18:35
|
6 | type TcpStreamConnectFut = impl Future<Output = std::io::Result<TcpStream>>;
| ------------------------------------------------ the expected opaque type
...
18 | self.connection_futs.push(TcpStream::connect("127.0.0.1:8080"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
|
= note: while checking the return type of the `async fn`
= note: expected opaque type `impl Future` (opaque type at <src/lib.rs:6:28>)
found opaque type `impl Future` (opaque type at </playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.7.1/src/net/tcp/stream.rs:111:56>)
= help: consider `await`ing on both `Future`s
= note: distinct uses of `impl Trait` result in different opaque types
Using the dummy function we created does work:
impl Foo {
fn push(&mut self) {
self.connection_futs.push(__tcp_stream_connect_defining_use());
}
}
So we can just create wrapper functions:
fn tcp_stream_connect<A: ToSocketAddrs>(addr: A) -> TcpStreamConnectFut {
TcpStream::connect(addr)
}
Except...
error: type parameter `A` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> src/main.rs:9:74
|
9 | fn tcp_stream_connect<A: ToSocketAddrs>(addr: A) -> TcpStreamConnectFut {
| __________________________________________________________________________^
10 | | TcpStream::connect(addr)
11 | | }
| |_^
We could just use String or &'static str, and the entire thing compiles:
type TcpStreamConnectFut = impl Future<Output = std::io::Result<TcpStream>>;
fn tcp_stream_connect(addr: &'static str) -> TcpStreamConnectFut {
TcpStream::connect(addr)
}
struct Foo {
connection_futs: Vec<TcpStreamConnectFut>,
}
impl Foo {
fn push(&mut self) {
self.connection_futs.push(tcp_stream_connect("..."));
}
}
You can also add a generic parameter to the type alias itself, but that probably doesn't make sense in this case:
type TcpStreamConnectFut<A> = impl Future<Output = std::io::Result<TcpStream>>;
fn tcp_stream_connect<A: ToSocketAddrs>(addr: A) -> TcpStreamConnectFut<A> {
TcpStream::connect(addr)
}
struct Foo {
connection_futs: Vec<TcpStreamConnectFut<&'static str>>,
}
impl Foo {
fn push(&mut self) {
self.connection_futs.push(tcp_stream_connect("..."));
}
}
So it is possible, but there are a couple of restrictions. I'm not sure how many of these are bugs, and how much of it is intentional behavior. There has been discussion about a typeof operator to make this easier, but this is what we've got at the moment.
You can just use a good old Vec, just like that:
use core::future::Future;
use tokio::net::TcpStream;
fn just_vec() -> Vec<impl Future<Output = std::io::Result<TcpStream>>> {
let mut v = Vec::new();
// connect to several streams
v.push(TcpStream::connect("127.0.0.1:8080"));
v.push(TcpStream::connect("127.0.0.2:8080"));
v
}
However, it gets more tricky if you want to store it in a struct, because unlike above, where concrete type can be inferred, you need to be more explicit with structs.
One stable way to do this, is to use a generic struct. This actually very similar to storing a closure (where you don't have a concrete type either).
use core::future::Future;
use tokio::net::TcpStream;
use tokio::io::AsyncWriteExt;
struct Foo<T> {
connections: Vec<T>,
}
/// This is just like any other vec-wrapper
impl<T> Foo<T> {
pub fn new() -> Self {
Self {
connections: Vec::new(),
}
}
pub fn push(&mut self, conn: T) {
self.connections.push(conn);
}
}
/// Some more specific functios that actually need the Future
impl<T> Foo<T> where T: Future<Output = std::io::Result<TcpStream>> {
pub async fn broadcast(self, data: &[u8]) -> std::io::Result<()> {
for stream in self.connections {
stream.await?.write_all(data).await?
}
Ok(())
}
}
async fn with_struct() -> std::io::Result<()> {
let mut foo = Foo::new();
// connect to several streams
foo.push(TcpStream::connect("127.0.0.1:8080"));
foo.push(TcpStream::connect("127.0.0.2:8080"));
// Do something with the connections
foo.broadcast(&[1,2,3]).await
}

Why does SmallVec have different behaviour when storing types with lifetimes compared to Vec?

I've got three examples, one using Vec one using SmallVec, and one with my own implementation of SmallVec. The ones using Vec and my own SmallVec compile but the one using the real SmallVec does not.
Working example using Vec
use std::borrow::Cow;
use std::collections::HashMap;
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: `Vec<Cow<'a, str>>`
pub struct ItemTraitReturns<'a>(Vec<Cow<'a, str>>);
/// this implementation only takes items with static lifetime (but other implementations also might have different lifetimes)
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
// Works as expected: I expect that I can return `&ItemTraitReturns<'_>`
// when I have `&ItemTraitReturns<'static>` (since 'static outlives everything).
temp
// Will return `&ItemTraitReturns<'_>`
}
}
Failing example with SmallVec
Uses SmallVec instead of Vec with no other changes.
use smallvec::SmallVec;
use std::borrow::Cow;
use std::collections::HashMap;
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: Uses SmallVec instead of Vec
pub struct ItemTraitReturns<'a>(SmallVec<[Cow<'a, str>; 2]>);
/// this implementation only takes items with static lifetime (but other implementations also might have different lifetimes)
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
temp
}
}
error[E0308]: mismatched types
--> src/lib.rs:23:9
|
23 | temp
| ^^^^ lifetime mismatch
|
= note: expected type `&ItemTraitReturns<'_>`
found type `&ItemTraitReturns<'static>`
note: the anonymous lifetime #1 defined on the method body at 18:5...
--> src/lib.rs:18:5
|
18 | / fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
19 | | let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
20 | | // Error:
21 | | // = note: expected type `&demo2::ItemTraitReturns<'_>`
22 | | // found type `&demo2::ItemTraitReturns<'static>`
23 | | temp
24 | | }
| |_____^
= note: ...does not necessarily outlive the static lifetime
Working example with my own SmallVec
When I implement my own (very naive) SmallVec<[T; 2]> (called NaiveSmallVec2<T>) the code also compiles... Very strange!
use std::borrow::Cow;
use std::collections::HashMap;
/// This is a very naive implementation of a SmallVec<[T; 2]>
pub struct NaiveSmallVec2<T> {
item1: Option<T>,
item2: Option<T>,
more: Vec<T>,
}
impl<T> NaiveSmallVec2<T> {
pub fn push(&mut self, item: T) {
if self.item1.is_none() {
self.item1 = Some(item);
} else if self.item2.is_none() {
self.item2 = Some(item);
} else {
self.more.push(item);
}
}
pub fn element_by_index(&self, index: usize) -> Option<&T> {
match index {
0 => self.item1.as_ref(),
1 => self.item2.as_ref(),
_ => self.more.get(index - 2),
}
}
}
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: Uses NaiveSmallVec2
pub struct ItemTraitReturns<'a>(NaiveSmallVec2<Cow<'a, str>>);
/// only takes items with static lifetime
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
// astonishingly this works!
temp
}
}
I expect the SmallVec version to compile like the Vec version does. I don't understand why in some cases (in the case of Vec) &ItemTraitReturns<'static> can be converted to &ItemTraitReturns<'_> and in some cases (SmallVec) it's not possible (I don't see the influence of Vec / SmallVec).
I don't want to change lifetimes of this trait:
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
... since when using the trait I don't care about lifetimes (this should be an implementation detail) ... but still would like to use SmallVec.
This difference appears to be caused by a difference in variance between Vec and SmallVec. While Vec<T> is covariant in T, SmallVec appears to be invariant. As a result, SmallVec<[&'a T; 1]> can't be converted to SmallVec<[&'b T; 1]> even when lifetime 'a outlives 'b and the conversion should be safe. Here is a minimal example triggering the compiler error:
fn foo<'a, T>(x: SmallVec<[&'static T; 1]>) -> SmallVec<[&'a T; 1]> {
x // Compiler error here: lifetime mismatch
}
fn bar<'a, T>(x: Vec<&'static T>) -> Vec<&'a T> {
x // Compiles fine
}
This appears to be a shortcoming of SmallVec. Variance is automatically determined by the compiler, and it is sometimes cumbersome to convince the compiler that it is safe to assume that a type is covariant.
There is an open Github issue for this problem.
Unfortunately, I don't know a way of figuring out the variance of a type based on its public interface. Variance is not included in the documentation, and depends on the private implementation details of a type. You can read more on variance in the language reference or in the Nomicon.

Why is the failure::Fail trait bound not satisfied by my Result type alias?

I'm trying to implement event hooks as demonstrated by "simple event hooks in Rust" while also using the Error + ErrorKind pattern of the failure crate.
This is a stripped down version of my code:
#[macro_use]
extern crate failure;
use failure::{Backtrace, Context, Error, Fail};
use std::fmt;
#[derive(Debug)]
pub struct PortalError {
inner: Context<PortalErrorKind>,
}
impl Fail for PortalError {
fn cause(&self) -> Option<&Fail> {
self.inner.cause()
}
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl fmt::Display for PortalError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
#[derive(Copy, Clone, PartialEq, Debug, Fail)]
pub enum PortalErrorKind {
#[fail(display = "Unknown Error")]
Unknown,
}
//----------------------------------------------------------
pub type PortalResult<T> = Result<PortalError, T>;
pub trait Portal {
fn get_something(&self) -> PortalResult<Vec<u32>>;
}
//----------------------------------------------------------
pub trait FeedApi<'a> {
type T: FeedApi<'a>;
fn new<P: Portal + 'a>(portal: P) -> Result<Self::T, Error>;
}
//----------------------------------------------------------
pub struct Feedly<'a> {
portal: Box<Portal + 'a>,
}
impl<'a> FeedApi<'a> for Feedly<'a> {
type T = Feedly<'a>;
fn new<P: Portal + 'a>(portal: P) -> Result<Self::T, Error> {
Ok(Feedly {
portal: Box::new(portal),
})
}
}
impl<'a> Feedly<'a> {
pub fn demo_function(&self) -> Result<(), Error> {
let _ = self.portal.get_something().context(PortalErrorKind::Unknown)?;
Ok(())
}
}
fn main() {
println!("Hello, world!");
}
[dependencies]
failure = "0.1.1"
In a method of 'Feedly' I want to use the portal:
self.portal.get_something().context(PortalErrorKind::Unknown)?
But I get the following error:
error[E0599]: no method named `context` found for type `std::result::Result<PortalError, std::vec::Vec<u32>>` in the current scope
--> src/main.rs:67:45
|
67 | let _ = self.portal.get_something().context(PortalErrorKind::Unknown)?;
| ^^^^^^^
|
= note: the method `context` exists but the following trait bounds were not satisfied:
`std::result::Result<PortalError, std::vec::Vec<u32>> : failure::Fail`
`&std::result::Result<PortalError, std::vec::Vec<u32>> : failure::Fail`
`&mut std::result::Result<PortalError, std::vec::Vec<u32>> : failure::Fail`
Looking through the docs the failure::Fail trait has a bound 'static. And the method context has a bound Self: Sized.
I'm not sure which trait is not satisfied here. The boxed Portal is neither Sized nor 'static, but the returned result should be, right?
This is the first time I'm handling boxes and lifetimes in Rust.
pub type PortalResult<T> = Result<PortalError, T>;
Result has two type parameters: the success type and the error type. You have transposed them; you want:
pub type PortalResult<T> = Result<T, PortalError>;

How do you write a trait that returns an iterator?

Broadly speaking my goal is this:
For some known type Bar...
Have a trait Foo with a function: get_iterator<T>() -> T where T: Iterator<Item = Bar>
The instance of the iterator borrows the original object Foo is implemented on.
I imagine it working like this:
let mut foo = Foo;
let bar = foo.get_iterator();
foo.mutable_call(); // <-- This fails, because foo is borrowed in bar
for x in bar {
...
}
So, that's the goal, and here's my attempt, which I can't seem to get working:
struct ValsFromT<'a, T: 'a> {
parent:&'a T,
offset: usize,
}
struct Val;
trait HasValsIterator<T> {
fn val_iterator(&self) -> T where T: Iterator<Item = Val>;
}
struct Foo;
impl<'a> Iterator for ValsFromT<'a, Foo> {
type Item = Val;
fn next(&mut self) -> Option<Val> {
return None;
}
}
impl<'a> HasValsIterator<ValsFromT<'a, Foo>> for Foo {
fn val_iterator(&'a self) -> ValsFromT<'a, Foo> {
return ValsFromT {
offset: 0usize,
parent: self
};
}
}
fn takes_vals<T>(instance:T) where T: HasValsIterator<T> {
// ...
}
#[test]
fn test_foo() {
let x = Foo;
takes_vals(x);
}
(playpen: http://is.gd/wys3fx)
We're getting the dreaded concrete/bound lifetime error here, because of trying to return an iterator instance that references self from the trait function:
<anon>:22:3: 27:4 error: method `val_iterator` has an incompatible type for trait:
expected bound lifetime parameter ,
found concrete lifetime [E0053]
<anon>:22 fn val_iterator(&'a self) -> ValsFromT<'a, Foo> {
<anon>:23 return ValsFromT {
<anon>:24 offset: 0usize,
<anon>:25 parent: self
<anon>:26 };
<anon>:27 }
<anon>:22:3: 27:4 help: see the detailed explanation for E0053
Is there some way of doing this?
Unfortunately, Veedrac's suggestion doesn't work directly. You will get the following error if you'd try to use val_iterator() method on instance inside takes_vals():
<anon>:31:25: 31:39 error: the trait `core::iter::Iterator` is not implemented for the type `U` [E0277]
<anon>:31 let iter = instance.val_iterator();
^~~~~~~~~~~~~~
<anon>:31:25: 31:39 help: see the detailed explanation for E0277
<anon>:31:25: 31:39 note: `U` is not an iterator; maybe try calling `.iter()` or a similar method
error: aborting due to previous error
playpen: application terminated with error code 101
This (and some other further errors) requires changing the signature of the function to this one:
fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U>
However, even this doesn't work yet:
<anon>:31:16: 31:24 error: `instance` does not live long enough
<anon>:31 let iter = instance.val_iterator();
^~~~~~~~
<anon>:30:97: 32:2 note: reference must be valid for the lifetime 'a as defined on the block at 30:96...
<anon>:30 fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U> {
<anon>:31 let iter = instance.val_iterator();
<anon>:32 }
<anon>:30:97: 32:2 note: ...but borrowed value is only valid for the scope of parameters for function at 30:96
<anon>:30 fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U> {
<anon>:31 let iter = instance.val_iterator();
<anon>:32 }
Remember that the trait requires that val_iterator() accepts the target by reference with lifetime 'a. This lifetime in this function is an input parameter. However, when val_iterator() is called on instance, the only lifetime which can be specified for the reference is the one of instance which is strictly smaller than any possible 'a as a parameter, because it is a local variable. Therefore, it is not possible to pass instance by value; you can only pass it by reference for lifetimes to match:
fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: &'a T) where T: HasValsIterator<'a, U> {
let iter = instance.val_iterator();
}
This works.
I'd like to add that using associated types instead of type parameters would be more correct semantically:
trait HasValsIterator<'a> {
type Iter: Iterator<Item=Val> + 'a;
fn val_iterator(&'a self) -> Self::Iter;
}
impl<'a> HasValsIterator<'a> for Foo {
type Iter = ValsFromT<'a, Foo>;
fn val_iterator(&'a self) -> ValsFromT<'a, Foo> { ... }
}
fn takes_vals<'a, T: 'a>(instance: &'a T) where T: HasValsIterator<'a> {
...
}
I say that this is more correct because the type of the iterator is determined by the implementor, that is, it is "output" type, which are modeled by associated types. As you can see, takes_vals() signature also shrank considerably.
Ideally, HasValsIterator trait should have been defined like this:
trait HasValsIterator {
type Iter<'a>: Iterator<Item=Val> + 'a
fn val_iterator<'a>(&'a self) -> Iter<'a>;
}
This way, val_iterator() would in any situation, including when HasValsIterator implementor is passed by value. However, Rust is not there yet.

Resources