Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generic trait to combine UnixListener and TcpListener #4244

Closed
wants to merge 2 commits into from

Conversation

cecton
Copy link
Contributor

@cecton cecton commented Nov 18, 2021

Motivation

I would like to have a generic type for creating a socket from TCP or from a Unix socket so I don't need to duplicate code.

Solution

  1. Added a new type that combines the SocketAddr of TcpListener and the one of UnixListener. I called it ListenAddr.
  2. Added a new trait Listener with an accept() method and a local_addr() method to reflect the methods from TcpListener and UnixListener.
  3. Added a new trait AsyncReadWrite which combines AsyncRead and AsyncWrite. This is because I will need to box the stream.
  4. Added a method set_nodelay() to reflect the method set_nodelay() of TcpStream which I needed.

Problem encountered

There is a module "udp" at root of tokio-util. It should probably moved to the new module "net" I created. One alternative would be to rename the "unix" module I created to something else.

@cecton
Copy link
Contributor Author

cecton commented Nov 18, 2021

@Darksonn you suggested such a trait in tokio-util. Is this what you had in mind?

@cecton cecton marked this pull request as ready for review November 18, 2021 09:35
Comment on lines +30 to +40
/// Accepts a new incoming connection from this listener.
fn accept<'a>(
&'a self,
) -> Pin<
Box<
dyn Future<
Output = Result<(Box<dyn AsyncReadWrite + Send + Unpin + 'static>, ListenAddr)>,
> + Send
+ 'a,
>,
>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to add a trait, I think it should use a poll fn rather than a boxed future.

Comment on lines +93 to +96
pub trait AsyncReadWrite: tokio::io::AsyncRead + tokio::io::AsyncWrite {
/// Sets the value of the `TCP_NODELAY` option on this socket if this is a TCP socket.
fn set_nodelay(&self, nodelay: bool) -> Result<()>;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this trait doesn't make sense. It's not a trait for combining AsyncRead and AsyncWrite - its a trait for adding an set_nodelay method to a type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be called...SetNodelay, and not require AsyncRead and AsyncWrite...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used for boxing.

Box<dyn AsyncReadWrite + Send + Unpin + 'static>

You can't add 2 traits in a Box dyn like that. You have to create a third one that inherit the 2 others.

set_nodelay here is detail in the trait. It's there because I needed it from TcpListener but other functions could be there too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't add 2 traits in a Box dyn like that. You have to create a third one that inherit the 2 others.

Right...I think that the boxed trait object should probably be replaced with an associated type like

type Io = tokio::io::AsyncRead + tokio::io::AsyncWrite;

as Alice mentioned here #4244 (comment). That way, user code could define a SetNodelay trait, implement it for TcpStream and UnixStream, and have trait bounds like

async fn do_something_with_a_listener<L>(listener: L)
where
    L::Io: SetNodelay,
{
    // ...
}

This way, if other users need to expose other functionality on sockets, they can add similar traits and still use the Listener trait, rather than special-casing set_nodelay just because your application needs to disable Nagle's algorithm.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this should be an associated type, and the set_nodelay method should honestly just get taken out. It's too specific to your particular use-case.

) -> Pin<
Box<
dyn Future<
Output = Result<(Box<dyn AsyncReadWrite + Send + Unpin + 'static>, ListenAddr)>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than returning a boxed IO resource, I would prefer to use an associated type.

(And if we did want to return a boxed IO resource, it should have been a Pin<Box<...>> rather than an Box<... + Unpin>.)

>;

/// Returns the local address that this listener is bound to.
fn local_addr(&self) -> Result<ListenAddr>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also seems like this should be an associated type rather than return an enum with the two types hard-coded. Otherwise the trait is designed to only allow TcpListener and UnixListener, and people would not be able to implement it for their own listeners, e.g. maybe there's a listener for TLS streams.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea was to make it only for TcpListener and UnixListener 😁 it didn't even crossed my mind to support other things.

I don't mind working on making this more generic but I need to update the title of this issue then.

@Darksonn Darksonn added A-tokio-util Area: The tokio-util crate M-net Module: tokio/net labels Nov 18, 2021
@Darksonn
Copy link
Contributor

I'm closing this because the implementation is going in the wrong direction and there hasn't been any activity for a while. Feel free to reopen or open a new issue if you want to continue working on this.

@Darksonn Darksonn closed this Dec 10, 2021
@cecton
Copy link
Contributor Author

cecton commented Jan 7, 2022

I'm back on this! 😁 Unfortunately I can't reopen the ticket on my side. I already pushed one new commit that replaces the box with the associated type but it's not visible here for some reason. Should I open a new PR? cc @Darksonn

@Darksonn
Copy link
Contributor

Darksonn commented Jan 7, 2022

Yeah, just open a new PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio-util Area: The tokio-util crate M-net Module: tokio/net
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants