Converting trait object to impl expression - rust

This question is related with this one opened previously for me, but summarizing "the big deal".
Given this:
pub trait TraitA {}
Is it possible in Rust, having a &dyn TraitA as argument of a function, "casting it" or convert it in some way to an impl expr?
Like this:
fn a<'a>(param: &'a dyn TraitA) {
b( param ) // param should be converted
}
where b is a external function which has a signature like this:
fn b(param: impl IntoSql<'a> + 'a);

Yes, this is possible if &dyn TraitA implements IntoSql. See here:
trait IntoSql<'a> {}
trait TraitA {}
impl<'a> IntoSql<'a> for &'a dyn TraitA {}
fn a<'a>(param: &'a dyn TraitA) { b(param) }
fn b<'a>(param: impl IntoSql<'a> + 'a) {}

Related

How to return a box to self?

I'm new to rust and I experience difficulties to develop my personal first project.
To get the essential my code looks like this:
pub trait MyTrait {
type Out: MyTrait;
fn foo(&self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self <>;
fn foo(&self) -> Box<Self::Out> {
Box::new(self)
}
}
The error message I get is :
expected struct MyStruct<T> found reference &MyStruct<T>
I tried many things but I can't find how to return a box to self...
I have another question: actually MyTrait extends another trait and I have many struct that implement MyTrait so in my code I have many impl, one for each trait by struct and I find it really verbose, isn't it possible to implement all methods (from a trait and all its parents) at once (like in java) ? Or is there syntactic sugar to implement methods with closures ?
Thanks
Box needs to own self. You cannot pass a reference into it, it has to be the actual self object.
This works:
pub trait MyTrait {
type Out: MyTrait;
fn foo(self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self;
fn foo(self) -> Box<Self::Out> {
Box::new(self)
}
}
Further remarks:
I'm unsure why you need that function, but it seems to me like you are trying to downcast from a boxed dyn trait to an actual type.
Sadly, this won't work this way. It's impossible for the compiler to figure out which type was the original type if your Box<dyn MyTrait> doesn't contain that information any more. That's why you need the Out associated type here, but you probably didn't yet realize that this means you can no longer store a Box<dyn MyTrait> object. It's now a Box<dyn MyTrait<Out = MyStruct>> object, which cannot be mixed with other MyTrait types any more.
If you really want to achieve that, there are several options. RTTI is one option, with the Any trait.
Another one would be a Visitor pattern, which could resolve this:
pub trait Visitor {
fn visit_mystruct(&mut self, s: &mut MyStruct);
}
pub struct MyVisitor;
impl Visitor for MyVisitor {
fn visit_mystruct(&mut self, s: &mut MyStruct) {
println!("Visited MyStruct: {:?}", s.0);
}
}
pub trait MyTrait {
fn visit(&mut self, visitor: &mut dyn Visitor);
}
pub struct MyStruct(i32);
impl MyTrait for MyStruct {
fn visit(&mut self, visitor: &mut dyn Visitor) {
visitor.visit_mystruct(self);
}
}
fn main() {
let mut obj: Box<dyn MyTrait> = Box::new(MyStruct(42)) as Box<dyn MyTrait>;
let mut visitor = MyVisitor;
// Here is no information any more about the actual type of `obj`.
// Visitor gets the type resolved again
obj.visit(&mut visitor);
}
Visited MyStruct: 42
A visitor pattern is especially useful in cases like tree structures, because it can be recursively applied to children. It is commonly used in compilers.
Another alternative would be to use an Enum instead of a Box<dyn Trait>.
Although those are all just based on assumptions now.

Trait for conversion of references and owned values to Cow

I have a function that can handle both owned and borrowed values of some type Foo by accepting a Cow<'_, Foo>. However, I'd like to make it more convenient by allowing to pass in owned or borrowed Foos directly.
Is it possible to have a conversion trait to Cow that's implemented both on a reference type and its owned version?
This is what I tried:
trait Convert<'a> : Clone {
fn into_cow(self) -> Cow<'a, Self>;
}
// Works
impl<'a> Convert<'a> for Foo {
fn into_cow(self) -> Cow<'a, Self> {
println!("owned");
Cow::Owned(self)
}
}
// Doesn't work
impl<'a> Convert<'a> for &'a Foo {
fn into_cow(self) -> Cow<'a, Self> {
println!("borrowed");
Cow::Borrowed(self)
}
}
The borrowed version says that Borrowed expected a &&'a Foo but found a &'a Foo.
Self in the implementation of a trait for &Foo is &Foo, so into_cow() doesn't return the same type in both impls.
One solution would be to change the return type to Cow<'a, Foo>, but that of course limits the trait to only work on Foo.
A better way is to make the owned type a generic parameter of Convert like this:
trait Convert<'a, T: Clone> {
fn into_cow(self) -> Cow<'a, T>;
}
impl<'a, T: Clone> Convert<'a, T> for T {
fn into_cow(self) -> Cow<'a, T> {
println!("owned");
Cow::Owned(self)
}
}
impl<'a, T: Clone> Convert<'a, T> for &'a T {
fn into_cow(self) -> Cow<'a, T> {
println!("borrowed");
Cow::Borrowed(self)
}
}
fn take_foo<'a>(foo: impl Convert<'a, Foo>) {
let cow = foo.into_cow();
}
fn main() {
take_foo(&Foo{});
take_foo(Foo{});
}
Do you ever make use of the ownership, or always reborrow it? If only reborrowing, is std::convert::AsRef what you're looking for?
fn take_foo(foo: impl AsRef<Foo>) {
let foo: &Foo = foo.as_ref();
todo!();
}

Can I define a trait that has a generic function returning a trait object?

Is it possible to have a trait function that returns any trait object?
Or, can a generic parameter be a trait object type?
trait ToVec<T> {
fn to_vec(&self) -> Vec<&dyn T>;
}
trait TraitA {}
trait TraitB {}
// etc
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=92008c3e799f9c2f9189a0100daa4e1a
You can't have &dyn T, as T is not a trait. But &dyn ToVec<T> (or &dyn SomeOtherTrait) is fine.
In your playground example, Vec<T> is actually correct because you already have T as a trait object &dyn TraitA in the impls; but as the error message says, you need to fix lifetimes. E.g. this compiles
trait TraitA {}
trait ToVec<T> {
fn to_vec(&self) -> Vec<T>;
}
impl<'a, T: TraitA> ToVec<&'a dyn TraitA> for (&'a str, &'a T) {
fn to_vec(&self) -> Vec<&'a dyn TraitA> {
vec![
self.1 as &dyn TraitA
]
}
}
but may or may not be what you intended.

Generic Trait for SQLx and reference

I have created a generic trait, and I am implementing it in a sqlx query, but I get an error
what am I doing wrong?
#[async_trait]
pub trait ITodoRepo<P> {
async fn list(pool:&P) -> Result<Vec<TodoType>>;
}
pub struct TodoRepo;
#[async_trait]
impl<P: sqlx::Executor<'static, Database = sqlx::Postgres>> ITodoRepo<P> for TodoRepo {
async fn list(pool: &P) -> Result<Vec<TodoType>> {
let rowset = sqlx::query_as!(
TodoSchema,
r#"SELECT * FROM todo"#)
.fetch_all(pool)
.await?
.iter()
.map(|row| hydrate(row))
.collect();
Ok(rowset)
}
}
How can I implement the Executor?
error[E0637]: `'_` cannot be used here
--> src/todo.rs:21:24
|
21 | .fetch_all(pool)
| ^^^^ the trait `sqlx::Executor<'_>` is not implemented for `&P`
In you question, as per fn list(pool: &P), the type of pool is &P. But the fetch_all() method seems to require an argument that implement trait sqlx::Executor<'_>. P implements that trait as per your impl but &P doesn't.
Here is a minimal reproducible code for your question:
trait MyTrait {}
struct MyStruct;
impl MyTrait for MyStruct {}
fn func<T: MyTrait>(arg: T) {
todo!()
}
fn main() {
let var = MyStruct;
let ref_to_var = &var;
func(ref_to_var);
}
Playground
Basically your function is expecting a type T that implements some trait MyTrait but you are passing &T.
To fix this, you can either change to function to accept a reference. Like in the above example:
fn func<T: MyTrait>(arg: &T) {
todo!()
}
Playground
Or you could implement the trait for the reference itself:
impl MyTrait for &MyStruct {}
Playground

Why is a cast needed when a closure is passed as a trait object argument?

I'm trying to create a trait that should abstract over functions/closures with a different number of arguments. Something like this:
trait MyTrait {}
impl MyTrait for Box<Fn() -> &'static str> {}
impl MyTrait for Box<Fn(u8) -> u8> {}
Initially I planned to use it like this:
fn myf<F: MyTrait>(_fun: F) {}
fn main() {
myf(Box::new(|i: u8| i + 2))
}
But this code fails with error:
error[E0277]: the trait bound `std::boxed::Box<[closure#src/main.rs:11:18: 11:31]>: MyTrait` is not satisfied
When I cast the box like this, everything compiles correctly:
myf(Box::new(|i: u8| i + 2) as Box<Fn(_) -> _>)
Playground
Why can't the Rust compiler infer this trait without a cast? Is my approach (using cast) correct, or is there a simpler way? I prefer to enable trivial_casts warning for my projects and this syntax triggers it.
This is a thing that one tends to forget: each closure is a different struct that implements Fn: Fn is a trait, not a struct, and trait implementations are not transitive.
Here is a little example that shows this point:
trait Base {}
trait Derived {}
struct Foo {}
impl Base for Derived {}
impl Derived for Foo {}
fn myf<T>(_t: Box<T>)
where
T: Base + ?Sized,
{
}
fn main() {
let foo = Box::new(Foo {});
//myf(foo) // does not compile
myf(foo as Box<Derived>)
}
The thing you really wanted to do is:
trait MyTrait {}
impl<T> MyTrait for T
where
T: Fn() -> &'static str,
{
}
impl<T> MyTrait for T
where
T: Fn(u8) -> u8,
{
}
fn myf<F>(_fun: Box<F>)
where
F: MyTrait,
{
}
fn main() {
myf(Box::new(|i: u8| i + 2))
}
But this cannot compile because there are two conflicting implementations.

Resources