diff --git a/crates/bevnet/src/lib.rs b/crates/bevnet/src/lib.rs index 78b3ff3..db0d6b4 100644 --- a/crates/bevnet/src/lib.rs +++ b/crates/bevnet/src/lib.rs @@ -2,9 +2,48 @@ use std::collections::LinkedList; use std::io::{self, Read, Write}; -use std::net::{TcpStream, ToSocketAddrs}; +use std::net::{TcpListener, TcpStream, ToSocketAddrs}; /// A non-blocking tcp connection. +/// +/// # Example +/// +/// ```rust +/// use std::io; +/// +/// use bevnet::{Connection, Listener}; +/// +/// # fn main() -> io::Result<()> { +/// let listener = Listener::bind("127.0.0.1:23732")?; +/// let mut connection = Connection::connect("127.0.0.1:23732")?; +/// +/// // The accept operation is not blocking. So we need to loop here. +/// let mut server_connection; +/// loop { +/// if let Some(new_connection) = listener.accept()? { +/// server_connection = new_connection; +/// break; +/// } +/// } +/// +/// // We don't need to loop here because the send operation just appends to the send buffer. +/// connection.send(b"Hello, world!")?; +/// +/// // To be sure the message has been sent, we need to update the connection. +/// while !connection.update()? { +/// // Wait until the connection is updated. +/// } +/// +/// // The receive operation is not blocking. So we need to loop here. +/// loop { +/// if let Some(message) = server_connection.receive()? { +/// assert_eq!(message, b"Hello, world!"); +/// break; +/// } +/// } +/// # Ok(()) +/// # } +/// ``` pub struct Connection { /// The underlying [TcpStream] used for the connection. stream: TcpStream, @@ -49,8 +88,11 @@ impl Connection { /// Sends a message over the connection. /// + /// Returns `true` if the message has been sent directly and `false` + /// if the message is still in the send queue. + /// /// This function is not blocking. - pub fn send(&mut self, message: &[u8]) -> io::Result<()> { + pub fn send(&mut self, message: &[u8]) -> io::Result { // Get the length of the message as a u16. let message_len: u16 = match message.len().try_into() { Ok(len) => len, @@ -75,9 +117,11 @@ impl Connection { /// Updates the connection. /// /// This function sends any pending messages that have not been sent yet. + /// It returns `true` if there is no remaining data to send after updating + /// the connection and `false` otherwise. /// /// This function is not blocking. - pub fn update(&mut self) -> io::Result<()> { + pub fn update(&mut self) -> io::Result { // Looping over the send buffers. while let Some((offset, buffer)) = self.send_buffers.front_mut() { // Writing the buffer to the stream. @@ -95,7 +139,7 @@ impl Connection { } // Returning success. - Ok(()) + Ok(self.send_buffers.is_empty()) } /// Receives a byte block from the connection. @@ -177,3 +221,48 @@ impl Connection { Ok(Some(&self.receive_buffer[..message_len as usize])) } } + +/// A non-blocking tcp listener. +/// +/// ```rust +/// use std::io; +/// +/// use bevnet::{Connection, Listener}; +/// +/// # fn main() -> io::Result<()> { +/// let listener = Listener::bind("127.0.0.1:23732")?; +/// let mut connection = Connection::connect("127.0.0.1:23732")?; +/// +/// // The accept operation is not blocking. So we need to loop here. +/// let mut server_connection; +/// loop { +/// if let Some(new_connection) = listener.accept()? { +/// server_connection = new_connection; +/// break; +/// } +/// } +/// # Ok(()) +/// # } +/// ``` +pub struct Listener(TcpListener); + +impl Listener { + /// Creates a new listener. + pub fn bind(addr: impl ToSocketAddrs) -> io::Result { + let listener = TcpListener::bind(addr)?; + listener.set_nonblocking(true)?; + Ok(Listener(listener)) + } + + /// Accepts a new [Connection]. + /// + /// This function is not blocking. + pub fn accept(&self) -> io::Result> { + match self.0.accept() { + Ok((stream, _)) => Connection::new(stream).map(Some), + Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None), + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => Ok(None), + Err(e) => Err(e), + } + } +}