'Problem with generic parameters and Self keyword in Trait methods. the trait RequestBuilderTrait cannot be made into an object

I'm trying to mock some structs by making them implement traits but I encounter an error when I define a trait as return type for a method:

the trait RequestBuilderTrait cannot be made into an object.

consider moving send_form to another trait. consider moving send_body to another trait. consider moving method to another trait. consider moving post to another trait. consider moving get to another trait. consider moving put to another trait. consider moving delete to another trait. consider moving query to another trait. consider moving headers to another trait. consider moving header to another trait. consider moving basic_auth to another trait. consider moving bearer_auth to another trait.

for a trait to be "object safe" it needs to allow building a vtable to allow the call to be >resolvable dynamically.

After some research I found that traits use a vtable where all of their methods signature are stated so those methods need to be sized to make trait objects safe. So I think the problem is that some of my methods have generic parameters and use Self keyword as return type. I thought that if I was using a Box type and simple reference it would solve the problem but this is not the case, I have the feeling there is no solution for this situation. Do you think there is any solution ? I know that I could use where Self: Sized for methods which return Self but it makes that method unusable later.

The error appears on the method which have Box<dyn RequestBuilderTrait> as return type

My code :

#[async_trait]
pub trait HttpClientTrait: Send + Sync {
    fn builder(&self) -> Box<dyn RequestBuilderTrait>;
    fn get_client(&self) -> &Client<HttpsConnector<HttpConnector>>;
}

#[derive(Debug, Clone)]
pub struct HttpClient {
    http_client: Client<HttpsConnector<HttpConnector>>,
}
impl HttpClient {
    pub fn new() -> Self {
        HttpClient {
            http_client: Client::builder().build::<_, Body>(HttpsConnector::with_native_roots()),
        }
    }
}

impl HttpClientTrait for HttpClient{
    fn builder(&self) -> Box<dyn RequestBuilderTrait> {
        RequestBuilder::new(&self.http_client)
    }

    fn get_client(&self) -> &Client<HttpsConnector<HttpConnector>> {
        &self.http_client
    }
}

#[async_trait]
pub trait RequestBuilderTrait {
    async fn send_and_get_hyper_response_future(mut self) -> Result<ResponseFuture, RequestError>;
    async fn send(mut self) -> Result<RequestResponse, RequestError>;
    async fn send_form<T: Serialize + Send + Sync>(mut self, form: &T) -> Result<RequestResponse, RequestError> ;
    async fn send_body<T: Serialize + Send + Sync>(mut self, object: &T) -> Result<RequestResponse, RequestError>;
    async fn send_multipart(mut self, multipart: MultipartForm) -> Result<RequestResponse, RequestError>;
    fn method( self, url: &str, method: Method) -> Box<Self>;
    fn post( self, url: &str) -> Box<Self>;
    fn get( self, url: &str) -> Box<Self>;
    fn put( self, url: &str) -> Box<Self>;
    fn delete( self, url: &str) -> Box<Self>;
    fn query<P: Serialize>( self, parameters: &P) -> Result<Box<Self>, ResponseError>;
    fn headers<K: Clone + IntoHeaderName>( self, headers: &[(K, &str)]) -> Result<Box<Self>, ResponseError>;
    fn header<K: IntoHeaderName>(self, key: K, val: &str) -> Result<Box<Self>, ResponseError>;
    fn basic_auth( self, username: &str, password: &str) -> Result<Box<Self>, ResponseError>;
    fn bearer_auth( self, token: &str) -> Result<Box<Self>, ResponseError>;
}

pub struct RequestBuilder<'a> {
    client: &'a Client<HttpsConnector<HttpConnector>, Body>,
    builder: Option<Builder>,
    request: Option<Request<Body>>,
}

#[async_trait]
impl<'a> RequestBuilderTrait for RequestBuilder<'a>{
...
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source