Best way to write a generic approach for both Tcp and Domain sockets

Hi all,

I have 2 areas in my code dealing with Tcp and Domain sockets, and processing is almost the same. Because both of these are dealing with streams, I can't find a worthwhile way to implement some kind of genericity without resorting to macros.

I can for sure factor the part with streams, because they implement Write or Read traits. But I can't see how to move any further. TcpStream and UnixStream are 2 different structures, using the same connect() or set_write_timeout() methods, but I didn't find any way to factor these, other than using macros.

If you've got some hints, I'll be happy :slight_smile:

The trouble with abstracting over connect is that they take different types: TcpStream::connect accepts socket addresses whereas UnixStream::connect accepts paths. To abstract over them both (without any loss of efficiency), I think that you would need to use associated traits which don't really exist. You could constrain them to both accept strings, but that's really not ideal since its so limiting.

It would be possible to make a trait that abstracts over set_{read, write}_timeout though if you wanted:

trait NetStream: Read + Write {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()>;
    fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()>;
}
impl NetStream for TcpStream { /* ... */ }
impl NetStream for UnixStream { /* ... */ }

@Kestrer Thanks for your answer. That's what I feared, and you're right Tcp and Unix connect() method accept 2 different argument types. So it's difficult to implement some kind of abstraction.

Here's how sqlx supports both Tcp and Unix sockets:

It uses an enum that can be either one, and the enum implements AsyncRead and AsyncWrite.