Cast struct object to dynamic trait object - struct

This is a simpler version of my code:
type Res = Result<(), Box<dyn std::error::Error + Send + Sync>>;
// defined before-hand
pub trait Attr {
fn method(&self) -> Res;
}
// a struct, a block of code provided by user
// which is unknown by far
pub struct S;
// the trait implemented for provided struct
// user does this manually
// which is unknown by far
impl Attr for S {
fn method(&self) -> Res {
Ok(())
}
}
// in order to use the struct and its implemented method
// a possible way may be cast struct type to dynamic trait object
type Item = dyn Fn(&dyn Attr) -> Res;
pub fn use_method(f: &Item) {}
fn main() {
// casting happens here
// and do this job in macro, here is simplified version
let m = &(<S as Attr>::method) as &Item;
use_method(m);
}
It is required to tackle a struct, a block of code and its implementation both of which are unknown and provided by user. A rough direction may be using a trait as dynamic trait bounds which converted from struct object, but the compiler complain:
error[E0631]: type mismatch in function arguments
--> src/main.rs:30:13
|
4 | fn method(&self) -> Res;
| ------------------------ found signature of `for<'r> fn(&'r S) -> _`
...
30 | let m = &(<S as Attr>::method) as &Item;
| ^^^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r (dyn Attr + 'r)) -> _`
|
= note: required for the cast to the object type `dyn for<'r> Fn(&'r (dyn Attr + 'r)) -> std::result::Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>`
How can I get it done? Is there any other way?

Related

how to save a function pointer with dyn parameters in a structure

I'm getting
error[E0308]: mismatched types
--> src/main.rs:38:39
|
37 | fn set_source_outcome<S: Source, O: Outcome>(&mut self, selector: fn(s: &S) -> &O) {
| - this type parameter
38 | self.selector = Some(Box::new(selector));
| ^^^^^^^^ expected trait object `dyn Source`, found type parameter `S`
|
= note: expected fn pointer `for<'r> fn(&'r (dyn Source + 'r)) -> &'r (dyn Outcome + 'r)`
found fn pointer `for<'r> fn(&'r S) -> &'r O`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
when trying to save a function with dyn parameters in a structure, like this:
struct X {
selector: Option<Box<fn(s: &dyn Source) -> &dyn Outcome>>,
}
impl X {
fn set_source_outcome<S: Source, O: Outcome>(&mut self, selector: fn(s: &S) -> &O) {
self.selector = Some(Box::new(selector));
}
}
Is there any way to do so?
playground: here
ok, looks somewhat like but still works playground
a more straightforward solution is most welcome

Traits returning a trait: In some cases works, in others it doesn't

I need to implement a trait that is returning the futures::StreamExt trait.
In general this sounds easy and there are several answers to this e.g. this here.
I tried this with StreamExt but this does - for some reason - not work. Here my sample code:
// [dependencies]
// futures = "0.3.6"
// async-std = { version = "1.6.5", features = ["attributes", "unstable"] } // interval function is unstable atm.
use std::time::Duration;
use futures::StreamExt;
trait StreamProvidingTrait {
fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>>;
}
struct StreamProvider {}
impl StreamProvidingTrait for StreamProvider {
fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>> {
return Box::new(async_std::stream::interval(Duration::from_millis(1000)).map(|_| 1));
}
}
#[async_std::main]
async fn main() {
let mut counter = 0;
let object = StreamProvider {};
// creates a stream
let worx = object.returnastream();
// mappes the stream into something....
let mut mapped_stream = worx.map(|_| {
counter = counter + 1;
counter
});
// subscribing to the items
while let item = mapped_stream.next().await {
match item {
Some(value) => println!("{}", value),
_ => {}
}
}
}
And here the error:
Compiling traittest v0.1.0 (/Users/andre/repos/traittest)
warning: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:1326:8
|
1326 | fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
| ^^^^^^^^^^^^^^^ the trait cannot be made into an object because method `poll_next_unpin` references the `Self` type in its `where` clause
|
= note: `#[warn(where_clauses_object_safety)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
error[E0038]: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> src/main.rs:6:36
|
6 | fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
|
::: /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:226:8
|
226 | fn next(&mut self) -> Next<'_, Self>
| ---- the trait cannot be made into an object because method `next` references the `Self` type in its return type
...
976 | fn by_ref(&mut self) -> &mut Self {
| ------ the trait cannot be made into an object because method `by_ref` references the `Self` type in its return type
...
1381 | fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
| ---------------- the trait cannot be made into an object because method `select_next_some` references the `Self` type in its return type
error[E0038]: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> src/main.rs:12:36
|
12 | fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
|
::: /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:226:8
|
226 | fn next(&mut self) -> Next<'_, Self>
| ---- the trait cannot be made into an object because method `next` references the `Self` type in its return type
...
976 | fn by_ref(&mut self) -> &mut Self {
| ------ the trait cannot be made into an object because method `by_ref` references the `Self` type in its return type
...
1381 | fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
| ---------------- the trait cannot be made into an object because method `select_next_some` references the `Self` type in its return type
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0038`.
error: could not compile `traittest`.
To learn more, run the command again with --verbose.
Process finished with exit code 101
When I exchange the StreamExt trait with my own one, this code works perfectly.
trait SomeTrait {
fn returnatrait(self: &Self) -> Box<dyn SomeOtherTrait>;
}
trait SomeOtherTrait {
fn sayHelloWorld(&self);
}
struct DummyStruct {}
impl SomeOtherTrait for DummyStruct {
fn sayHelloWorld(&self) {
println!("hello world");
}
}
struct Implementation {}
impl SomeTrait for Implementation {
fn returnatrait(self: &Self) -> Box<dyn SomeOtherTrait> {
return Box::new(DummyStruct{});
}
}
fn main() {
let implementation = Implementation{};
let worx = implementation.returnatrait();
worx.sayHelloWorld();
}
What's wrong here? There's obviously something I don't understand. Please help me understand this!
A function returning a trait can use the impl Trait syntax to return an opaque type that implements the trait. A trait method returning a trait currently doesn't support this feature and requires the trait to be returned as a trait object - a dynamically dispatched reference or smart pointer such as Box or Rc. Not all traits are object-safe, though, and the bad news is that StreamExt is among those that aren't, for reasons pointed out by the compiler, such as referencing Self in method return types and where clauses.
The good news, however, is that this is not a problem: StreamExt is an extension trait, one that provides a blanket implementation for all types that implement Stream. So you don't need to bother returning a dyn StreamExt trait object, you can return a dyn Stream one, and you'll still get access to StreamExt methods simply by requesting them with use StreamExt. In other words, you can just replace Box<dyn StreamExt> with Box<dyn Stream> in the return type of your trait.
Another issue you might encounter is that Box<dyn Stream> doesn't work on methods that need to move the stream, which includes many methods provided by StreamExt. Those will require the stream to be pinned, which can be fixed by returning Pin<Box<dyn Stream>> instead of Box<dyn Stream>. There is even a boxed() method on StreamExt that pins and boxes the stream in one operation; code that uses it would look like this (playground):
use futures::stream::{Stream, StreamExt};
use std::pin::Pin;
trait StreamProvidingTrait {
fn returnastream(&self) -> Pin<Box<dyn Stream<Item = i32>>>;
}
struct StreamProvider {}
impl StreamProvidingTrait for StreamProvider {
fn returnastream(&self) -> Pin<Box<dyn Stream<Item = i32>>> {
return tokio::stream::once(0).boxed();
}
}
fn main() {
let provider = StreamProvider {};
let stream = provider.returnastream();
let _fut = stream.into_future();
}

How do I resolve the compilation error "Unpin not implemented for GenFuture" resulting from adapting a stream using a combinator?

I'm unable to work out how to resolve the compilation error resulting from adapting a stream using a combinator.
The following Rust Playground demonstrates a fairly minimal example:
use futures::prelude::*;
use futures::StreamExt;
#[derive(Debug)]
pub enum Input {
A,
B(i32),
C(u16),
}
#[derive(Debug)]
enum Output {
Int(i32),
Short(u16),
}
pub struct StreamMaker;
impl StreamMaker {
/// make a stream with a series of inputs
pub fn create(self) -> impl Stream<Item = Input> {
stream::iter(vec![Input::A, Input::C(1u16), Input::B(2)])
}
}
/// consume the creator, and make output messages for a subset
pub fn adapt_stream(creator: StreamMaker) -> impl Stream<Item = Output> {
let mut upstream = creator.create();
upstream.filter_map(|message| async move {
match message {
Input::A => None,
Input::B(v) => Some(Output::Int(v)),
Input::C(v) => Some(Output::Short(v)),
}
})
}
#[tokio::main]
async fn main() -> Result<(), ()> {
let creator = StreamMaker {};
let mut stream = adapt_stream(creator);
while let Some(message) = stream.next().await {
println!("message: {:?}", message)
}
Ok(())
}
Compilation fails with:
error[E0277]: the trait bound `std::future::GenFuture<[static generator#src/main.rs:29:46: 35:6 message:Input {}]>: std::marker::Unpin` is not satisfied in `impl core::future::future::Future`
--> src/main.rs:43:38
|
43 | while let Some(message) = stream.next().await {
| ^^^^ within `impl core::future::future::Future`, the trait `std::marker::Unpin` is not implemented for `std::future::GenFuture<[static generator#src/main.rs:29:46: 35:6 message:Input {}]>`
|
= help: the following implementations were found:
<std::future::GenFuture<T> as std::marker::Unpin>
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `futures_util::stream::stream::filter_map::FilterMap<impl futures_core::stream::Stream, impl core::future::future::Future, [closure#src/main.rs:29:25: 35:6]>`
= note: required because it appears within the type `impl futures_core::stream::Stream`
error[E0277]: the trait bound `std::future::GenFuture<[static generator#src/main.rs:29:46: 35:6 message:Input {}]>: std::marker::Unpin` is not satisfied in `impl core::future::future::Future`
--> src/main.rs:43:31
|
43 | while let Some(message) = stream.next().await {
| ^^^^^^^^^^^^^^^^^^^ within `impl core::future::future::Future`, the trait `std::marker::Unpin` is not implemented for `std::future::GenFuture<[static generator#src/main.rs:29:46: 35:6 message:Input {}]>`
|
= help: the following implementations were found:
<std::future::GenFuture<T> as std::marker::Unpin>
= note: required because it appears within the type `impl core::future::future::Future`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `futures_util::stream::stream::filter_map::FilterMap<impl futures_core::stream::Stream, impl core::future::future::Future, [closure#src/main.rs:29:25: 35:6]>`
= note: required because it appears within the type `impl futures_core::stream::Stream`
= note: required because of the requirements on the impl of `core::future::future::Future` for `futures_util::stream::stream::next::Next<'_, impl futures_core::stream::Stream>`
I can put a pin_mut!(stream); in the main, but I'd like to be able to push that upstream.
If you do not want the consumer of your stream to have to pin it themselves, you need to return a stream that implements the Unpin trait, meaning that it is safe to move around in memory even after is has been pinned.
pub fn adapt_stream(creator: StreamMaker) -> impl Stream<Item = Output> + Unpin {
// add Unpin trait --^
Adding this, your compiler should complain that the return value doesn't implement Unpin. This is because async move { ... } blocks don't implement Unpin, since they may be self-referential (e.g. contain references to variables they own). The most general way to work around this is to pin the stream to the heap with a Pin<Box<_>>, using the Box::pin constructor:
pub fn adapt_stream(creator: StreamMaker) -> impl Stream<Item = Output> + Unpin {
let mut upstream = creator.create();
Box::pin(upstream.filter_map(|message| async move {
// ^-- pin stream to heap
match message {
Input::A => None,
Input::B(v) => Some(Output::Int(v)),
Input::C(v) => Some(Output::Short(v)),
}
}))
}
Since we're now returning a Pin<Box<_>> pointer to the stream, that pointer can be safely moved around in memory while the inner stream is kept at the same location.
Full playground example

Function pointer with a reference argument cannot derive Debug

I have a enum where I want to generalize an function pointer. As soon as I add a reference inside the function pointer definition. it fails to compile because it cannot print it with Debug:
fn div1(t: i64, b: i64) -> i64 {
t / b
}
fn div2(t: i64, b: &i64) -> i64 {
t / b
}
#[derive(Debug)]
enum Enum {
FnTest1(fn(i64, i64) -> i64),
FnTest2(fn(i64, &i64) -> i64),
}
fn main() {
println!("{:?}", Enum::FnTest1(div1));
println!("{:?}", Enum::FnTest2(div2));
}
The error I get is this
error[E0277]: `for<'r> fn(i64, &'r i64) -> i64` doesn't implement `std::fmt::Debug`
--> src/main.rs:12:13
|
12 | FnTest2(fn(i64, &i64) -> i64),
| ^^^^^^^^^^^^^^^^^^^^ `for<'r> fn(i64, &'r i64) -> i64` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
= help: the trait `std::fmt::Debug` is not implemented for `for<'r> fn(i64, &'r i64) -> i64`
= note: required because of the requirements on the impl of `std::fmt::Debug` for `&for<'r> fn(i64, &'r i64) -> i64`
= note: required for the cast to the object type `dyn std::fmt::Debug`
It only shows an error for FnTest2 which has a reference argument while FnTest1 works fine.
Is this a bug in Rust or is there a solution or an alternative method to this issue?
I am running Rust nightly (rustup says: rustc 1.30.0-nightly (ae7fe84e8 2018-09-26)).
Is this a bug in Rust
No, but it is a limitation:
Cannot derive(Debug) for a struct with a function with a reference parameter (#45048)
#[derive] Debug, PartialEq, Hash, etc. for any function pointers, regardless of type signature (#54508)
is there a solution or an alternative method
Yes, you must implement Debug for the type Enum yourself.

Force/coerce evaluation of closure signature

Here is a contrived example of what I am trying to do:
use std::boxed::Box;
#[derive(Debug)]
pub struct Foo<'a>(pub &'a str);
pub trait IntoBox {
fn into_box<'a>(self) -> Box<Fn(Foo) -> String>;
}
impl<B> IntoBox for B where B: Fn(Foo) -> String + 'static {
fn into_box(self) -> Box<Fn(Foo) -> String> { Box::new(self) }
}
fn direct_into_box<B: Fn(Foo) -> String + 'static>(b: B) -> Box<Fn(Foo) -> String> {
Box::new(b)
}
fn main() {
// Doesn't work
let x = IntoBox::into_box(|i| format!("{:?}", i) );
// Works
let y = IntoBox::into_box(|i: Foo| format!("{:?}", i) );
// Also works
let z = direct_into_box(|i| format!("{:?}", i) );
}
How do I get my trait impl to do the same evaluation of the closure as is done by my direct_into_box? I would have expected direct_into_box and my trait impl to behave in the same way.
The error on x:
error[E0271]: type mismatch resolving `for<'r> <[closure#<anon>:20:31: 20:53] as std::ops::FnOnce<(Foo<'r>,)>>::Output == std::string::String`
--> <anon>:20:13
|
20 | let x = IntoBox::into_box(|i| format!("{:?}", i) );
| ^^^^^^^^^^^^^^^^^ expected bound lifetime parameter , found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#29r
= note: required because of the requirements on the impl of `IntoBox` for `[closure#<anon>:20:31: 20:53]`
= note: required by `IntoBox::into_box`
error[E0281]: type mismatch: the type `[closure#<anon>:20:31: 20:53]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(Foo<'r>,)>` is required (expected concrete lifetime, found bound lifetime parameter )
--> <anon>:20:13
|
20 | let x = IntoBox::into_box(|i| format!("{:?}", i) );
| ^^^^^^^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `IntoBox` for `[closure#<anon>:20:31: 20:53]`
= note: required by `IntoBox::into_box`
Sounds like an inference bug in the compiler. What seems to happen is that the compiler implements Fn(Foo<'x>) for one specific lifetime 'x instead of Fn(Foo<'a>) for any lifetime 'a on your closure.
Let's see if we can replicate the error by defining a struct by hand (this requires a nightly compiler), so we can better understand what's going on. First, let's define the struct the correct way:
#![feature(fn_traits)]
#![feature(unboxed_closures)]
// Foo and IntoBox unchanged
struct Func;
impl<'a> FnOnce<(Foo<'a>,)> for Func {
type Output = String;
extern "rust-call" fn call_once(self, args: (Foo<'a>,)) -> String {
self.call(args)
}
}
impl<'a> FnMut<(Foo<'a>,)> for Func {
extern "rust-call" fn call_mut(&mut self, args: (Foo<'a>,)) -> String {
self.call(args)
}
}
impl<'a> Fn<(Foo<'a>,)> for Func {
extern "rust-call" fn call(&self, (i,): (Foo<'a>,)) -> String {
format!("{:?}", i)
}
}
fn main() {
let x = IntoBox::into_box(Func);
}
This Func struct compiles fine and behaves just like your original closure.
Now, let's break it:
impl FnOnce<(Foo<'static>,)> for Func {
type Output = String;
extern "rust-call" fn call_once(self, args: (Foo<'static>,)) -> String {
self.call(args)
}
}
impl FnMut<(Foo<'static>,)> for Func {
extern "rust-call" fn call_mut(&mut self, args: (Foo<'static>,)) -> String {
self.call(args)
}
}
impl Fn<(Foo<'static>,)> for Func {
extern "rust-call" fn call(&self, (i,): (Foo<'static>,)) -> String {
format!("{:?}", i)
}
}
What I've done here is that I've removed the <'a> on each impl, so that the impls are no longer generic over a lifetime, and I've replaced Foo<'a> with Foo<'static>. This means that now, the traits are only implemented when the "closure"'s argument is a Foo<'static>.
This fails to compile with the following errors:
error[E0271]: type mismatch resolving `for<'r> <Func as std::ops::FnOnce<(Foo<'r>,)>>::Output == std::string::String`
--> <anon>:51:13
|
51 | let x = IntoBox::into_box(Func);
| ^^^^^^^^^^^^^^^^^ expected bound lifetime parameter , found concrete lifetime
|
= note: concrete lifetime that was found is the static lifetime
= note: required because of the requirements on the impl of `IntoBox` for `Func`
= note: required by `IntoBox::into_box`
error[E0277]: the trait bound `for<'r> Func: std::ops::Fn<(Foo<'r>,)>` is not satisfied
--> <anon>:51:13
|
51 | let x = IntoBox::into_box(Func);
| ^^^^^^^^^^^^^^^^^ the trait `for<'r> std::ops::Fn<(Foo<'r>,)>` is not implemented for `Func`
|
= help: the following implementations were found:
= help: <Func as std::ops::Fn<(Foo<'static>,)>>
= note: required because of the requirements on the impl of `IntoBox` for `Func`
= note: required by `IntoBox::into_box`
The first error is the same, but instead of an internal name like '_#29r, the compiler mentions the static lifetime, because that's what I used here. I suspect that what the compiler is doing with the closure that doesn't compile in your code is similar to my second set of impls, just that instead of 'static, it's some other concrete lifetime that we can't name in Rust. The second error is different but means pretty much the same thing.

Resources