'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
RequestBuilderTraitcannot be made into an object.
consider moving
send_formto another trait. consider movingsend_bodyto another trait. consider movingmethodto another trait. consider movingpostto another trait. consider movinggetto another trait. consider movingputto another trait. consider movingdeleteto another trait. consider movingqueryto another trait. consider movingheadersto another trait. consider movingheaderto another trait. consider movingbasic_authto another trait. consider movingbearer_authto 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 |
|---|
