Documentation
use core::net::SocketAddr;

use futures::{AsyncRead, AsyncWrite};

use crate::linux::net::NetworkError;

// Separate traits for different socket types

pub type Result<T> = core::result::Result<T, NetworkError>;

pub mod tcp {

    use super::Result;
    use crate::runtime::{Runtime, Share};
    use core::net::SocketAddr;
    use futures::{AsyncRead, AsyncWrite};

    pub trait Stream<R: Runtime<S>, S: Share>:
        AsyncRead + AsyncWrite + Send + Sync + 'static
    {
        fn connect(addr: SocketAddr) -> impl Future<Output = Result<Self>>
        where
            Self: Sized;
        fn local_addr(&self) -> Result<SocketAddr>;
        fn peer_addr(&self) -> Result<SocketAddr>;
    }

    pub trait Listener<R: Runtime<S>, S: Share>: Send + Sync + 'static {
        fn bind(addr: SocketAddr) -> impl Future<Output = Result<Self>>
        where
            Self: Sized;
        fn accept(&self) -> impl Future<Output = Result<(R::TcpStream, SocketAddr)>>;
        fn local_addr(&self) -> Result<SocketAddr>;
    }
}
pub mod udp {

    use super::Result;
    use crate::runtime::{Runtime, Share};
    use core::net::SocketAddr;
    use futures::{AsyncRead, AsyncWrite};

    // UDP is different - it's message-based, not stream-based
    pub trait Socket<R: Runtime<S>, S: Share>: Send + Sync + 'static {
        fn bind(addr: SocketAddr) -> impl Future<Output = Result<Self>>
        where
            Self: Sized;

        // Accept incoming "connections" (first packet from a new peer)
        fn accept(&self) -> impl Future<Output = Result<(R::UdpEndpoint, SocketAddr)>>;

        // Create an endpoint for a specific peer
        fn connect_to(&self, peer: SocketAddr) -> impl Future<Output = Result<R::UdpEndpoint>>;

        fn local_addr(&self) -> Result<SocketAddr>;
    }

    // Endpoint is the actual communication channel - like a connected UDP socket
    pub trait Endpoint<R: Runtime<S>, S: Share>:
        AsyncRead + AsyncWrite + Send + Sync + 'static
    {
        fn local_addr(&self) -> Result<SocketAddr>;
        fn peer_addr(&self) -> Result<SocketAddr>;
    }
}