Generic Trait for SQLx and reference - rust

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

Related

Implement methods for trait without additional traits

Looking for "blanket" implementation of the method(s) for trait.
Let's say for a trait
pub trait A {
fn do_a(&self);
}
want to have boxed method that wraps with box, without introducing any additional traits:
fn boxed(self) -> Box<Self>;
I can have another trait to achieve that (playground)
pub trait A {
fn do_a(&self);
}
pub trait Boxed {
fn boxed(self) -> Box<Self>;
}
impl<T> Boxed for T
where
T: A,
{
fn boxed(self) -> Box<Self> {
Box::new(self)
}
}
However, new trait Boxed is required for that.
You can add boxed directly to A with a default implementation so that structs won't need to implement it themselves:
trait A {
fn do_a(&self);
fn boxed (self) -> Box<Self>
where Self: Sized
{
Box::new (self)
}
}
struct Foo{}
impl A for Foo {
fn do_a (&self) {
todo!();
}
// No need to redefine `boxed` here
}
fn main() {
let foo = Foo{};
let _object: Box<dyn A> = foo.boxed();
}
Playground

Passing boxed trait object to function accepting generic parameter implementing the trait

I have a function which returns a boxed trait object, and another function that accepts a reference to an object implementing the same trait. I would like to pass a reference to the boxed trait object to the second function, but I am unable to figure out how to do this.
Example simplified code:
trait MyTrait {
fn foo(&self);
}
struct A {}
impl MyTrait for A {
fn foo(&self) {
println!("A");
}
}
struct B {}
impl MyTrait for B{
fn foo(&self) {
println!("B");
}
}
enum MyEnum {
A,
B,
}
fn create_object(my_enum: MyEnum) -> Box<dyn MyTrait> {
let boxed_value: Box<dyn MyTrait> = match my_enum {
MyEnum::A => Box::new(A{}),
MyEnum::B => Box::new(B{}),
};
boxed_value
}
fn do_something<T: MyTrait>(obj: &T) {
obj.foo();
}
fn main() {
use std::borrow::BorrowMut;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow_mut());
}
The error I get:
error[E0282]: type annotations needed
--> src\main.rs:42:5
|
42 | do_something(boxed_value.borrow_mut());
| ^^^^^^^^^^^^ ------------------------ this method call resolves to `&mut Borrowed`
| |
| cannot infer type for type parameter `T` declared on the function `do_something`
Intuitively, I would have hoped that in this case Rust would use dynamic dispatch and wouldn't care about the concrete type T (similarly to what happens in C++ when you pass a reference to a base class), but this seems not to be the case.
How do I pass a reference to the boxed trait object (Box<dyn MyTrait>) to the second function (do_something)? Is this possible in some way? A solution requiring a change to do_something would also be acceptable.
Intuitively, I would have hoped that in this case Rust would use dynamic dispatch and wouldn't care about the concrete type T (similarly to what happens in C++ when you pass a reference to a base class), but this seems not to be the case.
You can make that happen with a cast (or just type ascription, eventually) and by relaxing the default requirement for T to be Sized:
fn do_something<T: MyTrait + ?Sized>(obj: &T) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow() as &dyn MyTrait);
But if you’re not otherwise using T, you can opt into dynamic dispatch on the function side much more simply:
fn do_something(obj: &dyn Borrow) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow());
And if you don’t care that obj is a borrow and want to leave the option of static dispatch open, you can implement MyTrait for &dyn MyTrait:
impl MyTrait for &dyn MyTrait {
fn foo(&self) {
(*self).foo();
}
}
fn do_something<T: MyTrait>(obj: T) {
obj.foo();
}
// or, again, if not otherwise using T:
fn do_something(obj: impl MyTrait) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow());
No matter what, you'll need to add ?Sized to the trait bound in do_something, and then I think you have one of three options:
(Least general) Use as_ref() on the Box when you call do_something.
fn do_something<T: MyTrait + ?Sized>(obj: &T) {
obj.foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.as_ref());
}
(Most general) Replace the type of obj in do_something with impl AsRef<T>. This will make do_something work with anything convertible to a &T.
fn do_something<T: MyTrait + ?Sized>(obj: impl AsRef<T>) {
obj.as_ref().foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value);
}
(Medium general) Replace the type of obj in do_something with impl Deref<Target=T>. This will make do_something work with any smart pointer holding a T (which is a bit more restrictive than AsRef<T> — a type can implement AsRef<T> for as many values of T as it wants, but only gets to have one Deref implementation).
use std::ops::Deref;
fn do_something<T: MyTrait + ?Sized>(obj: impl Deref<Target=T>) {
obj.deref().foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value);
}
Instead of trying to unbox the value
you can instead implement MyTrait on Box<dyn MyTrait>
and forward to the boxed value.
impl MyTrait for Box<dyn MyTrait> {
fn foo(&self) {
self.deref().foo()
}
}
Then you don't even need to call borrow_mut.
fn main() {
use std::borrow::BorrowMut;
let boxed_value = create_object(MyEnum::A);
do_something(&boxed_value);
}
There's a working example in the playground

note: cannot satisfy `_: DecoderRunnable<u8>`

On this simple sketch I made, I'm trying to do use a trait called Runnable to run an Arc<dyn LockableOption<T>>:
use std::sync::{Arc, LockResult, Mutex, MutexGuard, PoisonError};
pub type LockableArc<T> = Arc<Mutex<Option<T>>>;
pub struct MutexGuardOptionRef<'a, T: ?Sized> {
pub mutex_guard: MutexGuard<'a, Option<Box<T>>>,
}
pub trait LockableOption<T: ?Sized>: Send + Sync {
fn lock(&self) -> LockResult<MutexGuardOptionRef<T>>;
}
impl<T: ?Sized + Send> LockableOption<T> for LockableArc<Box<T>> {
fn lock(&self) -> LockResult<MutexGuardOptionRef<T>> {
unimplemented!()
}
}
pub trait Decoder<T>: Send {
}
pub struct FfmpegDecoder<T> {
x: T,
}
impl<T: 'static + Send> Decoder<T> for FfmpegDecoder<T> {
}
trait DecoderRunnable<T> {
fn run(s: Arc<dyn LockableOption<dyn Decoder<T>>>);
}
impl<T: 'static + Send> DecoderRunnable<T> for FfmpegDecoder<T> {
fn run(s_lockable: Arc<dyn LockableOption<dyn Decoder<T>>>) {
unimplemented!()
}
}
fn main() {
let r: LockableArc<Box<dyn Decoder<u8>>> = Arc::new(Mutex::new(Some(Box::new(FfmpegDecoder{x: 0u8}))));
let rr: Arc<dyn LockableOption<dyn Decoder<u8>>> = Arc::new(r);
DecoderRunnable::<u8>::run(rr.clone());
}
Playground
I get the error:
error[E0283]: type annotations needed
--> src/main.rs:42:5
|
30 | fn run(s: Arc<dyn LockableOption<dyn Decoder<T>>>);
| --------------------------------------------------- required by `DecoderRunnable::run`
...
42 | DecoderRunnable::<u8>::run(rr.clone());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
= note: cannot satisfy `_: DecoderRunnable<u8>`
which I don't get. Why anything here should satisfy DecoderRunnable? DecoderRunnable is a trait that has a run function that expects Arc<dyn LockableOption<dyn Decoder<T>>> and I'm passing rr which is exactly that.
Traits have to be implemented types so the compiler can figure out which implementation to run. In your example, DecoderRunnable is only implemented for FfmpegDecoder<T> and you're trying to call it on an Arc<dyn LockableOption<dyn Decoder<u8>>>, which has no implementation.
You can always specify which implementation needs to be called by using this syntax:
<FfmpegDecoder<u8> as DecoderRunnable::<u8>>::run(rr);
Although it doesn't seem like what you're trying to do . It's not clear what you're trying to abstract, since you also have the decoder deeply nested inside LockableArc<T>.
If you just want to add convenience methods to LockableArc<Box<dyn Decoder<u8>>>, you can add an impl block for Arc<dyn ...> , and make the run method take &self instead of Arc<dyn ...> as its first parameter.

Implementing a trait for Option<T> and Option<&T>

Suppose there is a trait, whose methods all only take a reference of self, such as
trait Trait {
fn foo(&self) -> i32;
}
I'd like to have this trait implemented for both Option<T> and Option<&T> (as I can't always afford ownership), with a trivial implementation such as
impl<T: Trait> Trait for Option<T> {
fn foo(&self) -> i32 {
if let Some(inner) = self { return inner.foo(); }
0
}
}
impl<T: Trait> Trait for Option<&T> {
fn foo(&self) -> i32 {
if let Some(inner) = self { return inner.foo(); }
0
}
}
However, doing so produces the following error:
error[E0119]: conflicting implementations of trait `Trait` for type `std::option::Option<&_>`:
--> option.rs:12:1
|
5 | impl<T: Trait> Trait for Option<T> {
| ---------------------------------- first implementation here
...
12 | impl<T: Trait> Trait for Option<&T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::option::Option<&_>`
|
= note: downstream crates may implement trait `Trait` for type `&_`
Moreover, the implementations are literally the same. Is it possible to do this in a more compact way?
This does not compile because I, as a user of your trait could do something like this:
struct Yo;
impl Trait for Yo {
fn foo(&self) -> i32 { 0 }
}
impl Trait for &Yo {
fn foo(&self) -> i32 { 1 }
}
fn main() {
let a = Yo;
let b: Option<&Yo> = Some(&a);
b.foo(); // ambiguous call!
}
And there are two conflicting implementations of your trait for Option<&Yo>! Unfortunately trait specialization is still unstable, so that is probably not an option.
In your particular case you may solve with this generic impl, if you are willing:
impl<T: Trait> Trait for &T {
fn foo(&self) -> i32 {
(*self).foo()
}
}
This, combined with your generic impl for Option<T>, will give an unambiguous implementation for Option<&T>.

Why do I get "use of undeclared type or module" error when calling a struct's function?

I have the following code in Rust:
trait MyTrait {
fn get_value() -> &'static str;
}
#[derive(Debug)]
struct MyStruct;
impl MyTrait for MyStruct {
fn get_value() -> &'static str {
"has value"
}
}
fn main() {
println!("My value: {}", MyStruct::get_value());
has_trait(MyStruct);
}
fn has_trait<T>(trt: T) where T: MyTrait + std::fmt::Debug {
println!("{:?}", trt)
}
This code is fine. It defines a trait and a struct. The struct implements the trait; which requires to implement a function. Everything is fine until now. But if I try the following code:
trait MyTrait {
fn get_value() -> &'static str;
}
#[derive(Debug)]
struct MyStruct;
impl MyTrait for MyStruct {
fn get_value() -> &'static str {
"has value"
}
}
fn main() {
println!("My value: {}", MyStruct::get_value());
has_trait(MyStruct);
}
fn has_trait<T>(trt: T) where T: MyTrait + std::fmt::Debug {
println!("{:?}", trt::get_value())
}
I get the following error:
error[E0433]: failed to resolve: use of undeclared type or module `trt`
--> src/main.rs:21:22
|
21 | println!("{:?}", trt::get_value())
| ^^^ use of undeclared type or module `trt`
Now, I don't really understand very well why that wouldn't work. trt should represent a copy of myStruct and then it should have its own functions, right?
Interestingly, this following code will compile:
trait MyTrait {
fn get_value(&self) -> &'static str;
}
#[derive(Debug)]
struct MyStruct;
impl MyTrait for MyStruct {
fn get_value(&self) -> &'static str {
"has value"
}
}
fn main() {
println!("My value: {}", MyStruct.get_value());
has_trait(MyStruct);
}
fn has_trait<T>(trt: T) where T: MyTrait + std::fmt::Debug {
println!("{:?}", trt.get_value())
}
So what is exactly wrong with the code that doesn't compile?
Now, I don't really understand very well why that wouldn't work. trt should represent a copy of MyStruct and then it should have its own functions, right?
It doesn't quite work that way for associated functions in Rust.
With the identifier trt, you can call methods where trt is the receiver (self or one of its variations such as &self or &mut self). However, get_value() does not have a receiver, so it is an associated function. This resembles a static method in some languages such as Java. Unlike Java, associated functions in Rust can only be called by specifying the type or type parameter with that function:
fn has_trait<T>(trt: T) where T: MyTrait + std::fmt::Debug {
println!("{:?}", T::get_value())
}
This will now work, and would not even need the parameter trt, because we're just calling an associated function of the type T, rather than a method.
Although trt is an identifier to a function parameter in this context, the compiler will actually try to interpret it as something else (module name, type name, ...) once combined with the :: token, hence the given error message.

Resources