1

I am trying to write a trait describing a client for an HTTP server where I can tie the response to the query type:

trait Query {
  type Output;
}

trait ApiClient {
  fn send<Q: Query>(&self, q: &Q) -> Q::Output
  where
    Self: Sized;
}

I am able to write and use it when it is implemented for a type known at compile time. However I would like to use it from a trait object:

fn test_api_client(client: &dyn ApiClient) {
  impl Query for u32 {
    type Output = u32;
  }

  let query: u32 = 10;
  let output = client.send(&query);
  dbg!(output);
}

Playground link

The playground code fails with the following error:

error: the `send` method cannot be invoked on a trait object
  --> src/main.rs:38:23
   |
12 |     Self: Sized;
   |           ----- this has a `Sized` requirement
...
38 |   let output = client.send(&query);
   |                       ^^^^

Is there a workaround to wrap this generic method so it can be used through a trait object? I tried implementing it on &T where T: ApiClient because &dyn ApiClient is sized even if dyn ApiClient is not but wasn't able to use it.

I found that I can use Iterator::map through a trait object, despite this method being generic:

fn test(it: &mut dyn Iterator<Item = u8>) {
  for i in it.map(|x| x + 1) {
    dbg!(i);
  }
}

This is the Iterator::map implementation:

    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    fn map<B, F>(self, f: F) -> Map<Self, F>
    where
        Self: Sized,
        F: FnMut(Self::Item) -> B,
    {
        Map::new(self, f)
    }

How can I achieve a similar result as the standard library for Iterator?

Demurgos
  • 1,568
  • 18
  • 40
  • 1
    The usual workaround is to redesign the trait to support object safe methods. The example with the iterator works because the trait `Iterator` [is explicitly implemented for `&mut I` where `I` can be an unsized type](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#impl-Iterator-13), and that implementation does not depend on the non-object-safe methods of the trait object internally. – E_net4 Aug 28 '21 at 12:01

0 Answers0