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 movingsend_body
to another trait. consider movingmethod
to another trait. consider movingpost
to another trait. consider movingget
to another trait. consider movingput
to another trait. consider movingdelete
to another trait. consider movingquery
to another trait. consider movingheaders
to another trait. consider movingheader
to another trait. consider movingbasic_auth
to another trait. consider movingbearer_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>{
...
}