slavamnemonic
slavamnemonic

Reputation: 53

Return Traits from function

I've take a look to rust lib: https://github.com/cyderize/rust-websocket/ In source file https://github.com/cyderize/rust-websocket/blob/master/src/client/response.rs I seen method begin():

pub fn begin(self) -> Client<DataFrame, Sender<W>, Receiver<R>> {
    let (reader, writer) = self.into_inner();
    let sender = Sender::new(writer);
    let receiver = Receiver::new(reader);
    Client::new(sender, receiver)
}

So... I've decide to create some simple wrapper function:

fn get_transport(url: &str)  ->  Client<DataFrame, Sender<Write>, Receiver<Read>> {
    let url = Url::parse(url).unwrap();
    let request = Client::connect(url).unwrap();
    let response = request.send().unwrap();
    let mut ws = response.begin();

    ws
}

But unfortunately I've got error result:

error: the trait `core::marker::Sized` is not implemented for the type `websocket::ws::sender::Sender<std::io::Write>` [E0277]
src/lib.rs:36 fn get_transport(url: &str)  ->  Client<DataFrame, Sender<Write>, Receiver<Read>> {

Could some one please describe me why I could not return value in this way. What the difference with begin() method in the response.rs? How should I return value in my case?

UPD1: After @ker recommendations I've have next code:

fn get_transport<W: Write, R: Read, S: Sender<W>, RE: Receiver<R>>(url: &str) -> Client<DataFrame, S, RE> {

    let url = Url::parse(url).unwrap();
    let request = Client::connect(url).unwrap();
    let response = request.send().unwrap();
    let mut ws = response.begin();

    ws
}

But next error received in next compilation:

src/lib.rs:45:5: 45:7 error: mismatched types:
 expected `websocket::client::Client<websocket::dataframe::DataFrame, S, RE>`,
    found `websocket::client::Client<websocket::dataframe::DataFrame, websocket::client::sender::Sender<websocket::stream::WebSocketStream>, websocket::client::receiver::Receiver<websocket::stream::WebSocketStream>>`
(expected type parameter,
    found struct `websocket::client::sender::Sender`) [E0308]
src/lib.rs:45     ws
                  ^~
src/lib.rs:45:5: 45:7 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error

Seems I'v use wrong Sender and wrong Receiver :\ After corrections to use section I've have got result code:

fn get_transport(url: &str) -> Client<DataFrame, Sender<WebSocketStream>, Receiver<WebSocketStream>> {
    let url = Url::parse(url).unwrap();
    let request = Client::connect(url).unwrap();
    let response = request.send().unwrap();
    let mut ws = response.begin();

    ws
}

Unfortunately I could not found out why I could not use generics as result value. Like this:

fn get_transport<R: Read, W: Write>(url: &str) -> Client<DataFrame, Sender<W>, Receiver<R>>

In this caseI receive error message:

expected `websocket::client::Client<websocket::dataframe::DataFrame, websocket::client::sender::Sender<W>, websocket::client::receiver::Receiver<R>>`,
    found `websocket::client::Client<websocket::dataframe::DataFrame, websocket::client::sender::Sender<websocket::stream::WebSocketStream>, websocket::client::receiver::Receiver<websocket::stream::WebSocketStream>>`
(expected type parameter,
    found enum `websocket::stream::WebSocketStream`) [E0308]
src/lib.rs:45     ws
                  ^~

Upvotes: 4

Views: 775

Answers (2)

oli_obk
oli_obk

Reputation: 31163

Since any type may implment a trait, you can never know the size of an object by knowing just about the traits it implements. What you can do, is make your function generic over the types that implement Write and Read respectively. This way you can return the object, while not knowing what the actual type of the object is.

fn get_transport<W: Write, R: Read, S: Sender<W>, RE: Receiver<R>>(url: &str) -> Client<DataFrame, S, RE> {
    let url = Url::parse(url).unwrap();
    let request = Client::connect(url).unwrap();
    let response = request.send().unwrap();
    let mut ws = response.begin();

    ws
}

The reason why adding generics works, is because the generic labels point to the actual types, without knowing anything about the type except which traits they implement.

Upvotes: 3

A.B.
A.B.

Reputation: 16630

You want to replace Write and Send in the return type with concrete types.

Try changing the line let mut ws = response.begin(); to let mut ws: () = response.begin() and you will see an error message that will tell you what concrete types are being returned from the begin function.

Upvotes: 1

Related Questions