Wrapping inner function call in trait impl with different generic bounds

// Imagine this is from my External crate
pub mod repo {
  pub trait Queryable: Send + Sync {}

  pub trait Repository {
    fn find<T:Queryable>(value: T);
  }
  
  // not necessary just to make it easier
  impl <T: Send + Sync> Queryable for T {}
}

// ================
// some concrete external lib trait example
pub mod sqlx {
  pub trait SqlxQuery: Send + Sync {}

  pub fn query<T: SqlxQuery>(_value: T) {
    //some db work
  }
}

// ================
// Concrete implementation
trait Wrapper: repo::Queryable {}

impl <T:sqlx::SqlxQuery> Wrapper for T {}


struct Pg;
impl repo::Repository for Pg {
    fn find<T:repo::Queryable>(value: T) {
        sqlx::query(value);
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `T: SqlxQuery` is not satisfied
  --> src/lib.rs:42:21
   |
42 |         sqlx::query(value);
   |         ----------- ^^^^^ the trait `SqlxQuery` is not implemented for `T`
   |         |
   |         required by a bound introduced by this call
   |
note: required by a bound in `query`
  --> src/lib.rs:18:19
   |
18 |   pub fn query<T: SqlxQuery>(_value: T) {
   |                   ^^^^^^^^^ required by this bound in `query`
help: consider further restricting this bound
   |
40 |     fn find<T:repo::Queryable + sqlx::SqlxQuery>(value: T) {
   |                               +++++++++++++++++

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (lib) due to 1 previous error

I would like to have independent Repository trait with "less" restriction. From concrete impl I would like to call method with different T bounds. Is it possible? I know in given example I can do something like:

  pub trait Repository {
    fn find<T:Queryable + sqlx::SqlxQuery>(value: T);
  }

But this defeats the idea of having, for ex. Mongo DB implementation...
I'm learning Rust so thanks for the any help

You can't call <T as repo::<Repository>>::find unless T: Queryable. Similarly with the sqlx bounds in the commented example. Perhaps you want to implement Repository for implementors of different backends?

In that case the limitation you're probably going to run into is having multiple blanket implementations:

// These conflict: what if `T: SqlxQuery + MongoDbQuery`?
impl<T: SqlxQuery> Repository for T { .. }
impl<T: MongoDbQuery> Repository for T { .. }

A parameterized wrapper type may be a way around that:

//                vv marker type parameter
struct Wrapper<T, Db>(T, PhantomData<Db>);

struct ToSql;
impl<T: SqlxQuery> Repository for Wrapper<T, ToSql> { .. }

struct ToMongo;
impl<T: MongoDbQuery> Repository for Wrapper<T, ToMongo> { .. }
2 Likes

Ah I see.. Yeah. I think that can work! Thank you! @quinedot

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.