Returning a struct with a generic associated type (ws::WebSocket)

I'm trying to create a helper function to assist in creating a WebSocket struct from the ws crate and I'd like to return this constructed WebSocket struct but I can't for the life of me figure this out. I've gone down the rabbit hole of everything suggested by the compiler without success.

pub fn create_server<F>(bind_addr: String, ssl_certs: &SSLCert) -> WebSocket<F>
{
    let web_socket = ws::Builder::new()
    .with_settings(
        ws::Settings {
            queue_size: 100,
            encrypt_server: true,
            tcp_nodelay: true,
            ..ws::Settings::default()
        }
    )
    .build(|out: ws::Sender| WSServer {
        out: out,
        ssl: ssl_certs.acceptor(SSLConfiguration::Modern).unwrap(),
    })
    .unwrap();

    web_socket
}

struct WSServer {
    out: ws::Sender,
    ssl: Rc<SslAcceptor>,
}

Error Message:

error[E0277]: expected a `FnMut<(ws::Sender,)>` closure, found `F`
   --> src\server.rs:102:68
    |
102 | pub fn create_server<F>(bind_addr: String, ssl_certs: &SSLCert) -> WebSocket<F>
    |                                                                    ^^^^^^^^^^^^ expected an `FnMut<(ws::Sender,)>` closure, found `F`
    |
    = note: required because of the requirements on the impl of `Factory` for `F`
note: required by a bound in `WebSocket`
   --> C:\Users\...\.cargo\registry\src\github.com-1ecc6299db9ec823\ws-0.9.2\src\lib.rs:276:8
    |
276 |     F: Factory,
    |        ^^^^^^^ required by this bound in `WebSocket`
help: consider restricting type parameter `F`
    |
102 | pub fn create_server<F: std::ops::FnMut<(ws::Sender,)>>(bind_addr: String, ssl_certs: &SSLCert) -> WebSocket<F>
    |                       ++++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0277`.

This has nothing to do with GATs. Your mistake is that you are using a generic, but generic type parameters are chosen by the caller. Whereas you actually want the function implementation itself to choose the F type. That'd be spelled -> WebSocket<impl FnMut(…) -> …>.

1 Like

Thanks, you helped me out a lot here.

Here is the final code that works:

pub fn create_web_socket<'a>(
    ssl_certs: &'a SSLCert,
) -> WebSocket<impl FnMut(ws::Sender) -> WSServer + 'a> {
    ws::Builder::new()
        .with_settings(ws::Settings {
            queue_size: 100,
            encrypt_server: true,
            tcp_nodelay: true,
            ..ws::Settings::default()
        })
        .build(|out: ws::Sender| WSServer {
            out: out,
            ssl: ssl_certs.acceptor(SSLConfiguration::Modern).unwrap(),
        })
        .unwrap()
}

I renamed create_server to create_web_socket and dropped the bind_addr. Having to specify impl is what threw me off as I have had no exposure to it yet. (Plus perfect example of trying to code with no sleep). I'm not sure why I was thinking F: Factory in the WebSocket struct was a GAT...

Thanks for your help!