浏览代码

udp, icmp, raw: return own error enums for public API.

Dario Nieuwenhuis 2 年之前
父节点
当前提交
b7871e4e57
共有 7 个文件被更改,包括 335 次插入226 次删除
  1. 101 71
      src/socket/icmp.rs
  2. 69 39
      src/socket/raw.rs
  3. 80 41
      src/socket/udp.rs
  4. 1 1
      src/storage/assembler.rs
  5. 10 0
      src/storage/mod.rs
  6. 30 33
      src/storage/packet_buffer.rs
  7. 44 41
      src/storage/ring_buffer.rs

+ 101 - 71
src/socket/icmp.rs

@@ -6,7 +6,7 @@ use crate::phy::ChecksumCapabilities;
 #[cfg(feature = "async")]
 use crate::socket::WakerRegistration;
 use crate::socket::{Context, PollAt};
-use crate::{Error, Result};
+use crate::Error;
 
 use crate::wire::IcmpRepr;
 #[cfg(feature = "proto-ipv4")]
@@ -16,6 +16,29 @@ use crate::wire::{Icmpv6Packet, Icmpv6Repr, Ipv6Repr};
 use crate::wire::{IpAddress, IpListenEndpoint, IpProtocol, IpRepr};
 use crate::wire::{UdpPacket, UdpRepr};
 
+/// Error returned by [`Socket::bind`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum BindError {
+    InvalidState,
+    Unaddressable,
+}
+
+/// Error returned by [`Socket::send`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum SendError {
+    Unaddressable,
+    BufferFull,
+}
+
+/// Error returned by [`Socket::recv`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum RecvError {
+    Exhausted,
+}
+
 /// Type of endpoint to bind the ICMP socket to. See [IcmpSocket::bind] for
 /// more details.
 ///
@@ -204,14 +227,14 @@ impl<'a> Socket<'a> {
     /// [IcmpEndpoint::Udp]: enum.IcmpEndpoint.html#variant.Udp
     /// [send]: #method.send
     /// [recv]: #method.recv
-    pub fn bind<T: Into<Endpoint>>(&mut self, endpoint: T) -> Result<()> {
+    pub fn bind<T: Into<Endpoint>>(&mut self, endpoint: T) -> Result<(), BindError> {
         let endpoint = endpoint.into();
         if !endpoint.is_specified() {
-            return Err(Error::Unaddressable);
+            return Err(BindError::Unaddressable);
         }
 
         if self.is_open() {
-            return Err(Error::Illegal);
+            return Err(BindError::InvalidState);
         }
 
         self.endpoint = endpoint;
@@ -273,12 +296,15 @@ impl<'a> Socket<'a> {
     /// This function returns `Err(Error::Exhausted)` if the transmit buffer is full,
     /// `Err(Error::Truncated)` if the requested size is larger than the packet buffer
     /// size, and `Err(Error::Unaddressable)` if the remote address is unspecified.
-    pub fn send(&mut self, size: usize, endpoint: IpAddress) -> Result<&mut [u8]> {
+    pub fn send(&mut self, size: usize, endpoint: IpAddress) -> Result<&mut [u8], SendError> {
         if endpoint.is_unspecified() {
-            return Err(Error::Unaddressable);
+            return Err(SendError::Unaddressable);
         }
 
-        let packet_buf = self.tx_buffer.enqueue(size, endpoint)?;
+        let packet_buf = self
+            .tx_buffer
+            .enqueue(size, endpoint)
+            .map_err(|_| SendError::BufferFull)?;
 
         net_trace!("icmp:{}: buffer to send {} octets", endpoint, size);
         Ok(packet_buf)
@@ -287,7 +313,7 @@ impl<'a> Socket<'a> {
     /// Enqueue a packet to be sent to a given remote address, and fill it from a slice.
     ///
     /// See also [send](#method.send).
-    pub fn send_slice(&mut self, data: &[u8], endpoint: IpAddress) -> Result<()> {
+    pub fn send_slice(&mut self, data: &[u8], endpoint: IpAddress) -> Result<(), SendError> {
         let packet_buf = self.send(data.len(), endpoint)?;
         packet_buf.copy_from_slice(data);
         Ok(())
@@ -297,8 +323,8 @@ impl<'a> Socket<'a> {
     /// as a pointer to the payload.
     ///
     /// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
-    pub fn recv(&mut self) -> Result<(&[u8], IpAddress)> {
-        let (endpoint, packet_buf) = self.rx_buffer.dequeue()?;
+    pub fn recv(&mut self) -> Result<(&[u8], IpAddress), RecvError> {
+        let (endpoint, packet_buf) = self.rx_buffer.dequeue().map_err(|_| RecvError::Exhausted)?;
 
         net_trace!(
             "icmp:{}: receive {} buffered octets",
@@ -312,7 +338,7 @@ impl<'a> Socket<'a> {
     /// and return the amount of octets copied as well as the `IpAddress`
     ///
     /// See also [recv](#method.recv).
-    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<(usize, IpAddress)> {
+    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<(usize, IpAddress), RecvError> {
         let (buffer, endpoint) = self.recv()?;
         let length = cmp::min(data.len(), buffer.len());
         data[..length].copy_from_slice(&buffer[..length]);
@@ -388,13 +414,14 @@ impl<'a> Socket<'a> {
         _cx: &mut Context,
         ip_repr: &IpRepr,
         icmp_repr: &IcmpRepr,
-    ) -> Result<()> {
+    ) -> Result<(), Error> {
         match *icmp_repr {
             #[cfg(feature = "proto-ipv4")]
             IcmpRepr::Ipv4(ref icmp_repr) => {
                 let packet_buf = self
                     .rx_buffer
-                    .enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())?;
+                    .enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())
+                    .map_err(|_| Error::Exhausted)?;
                 icmp_repr.emit(
                     &mut Icmpv4Packet::new_unchecked(packet_buf),
                     &ChecksumCapabilities::default(),
@@ -410,7 +437,8 @@ impl<'a> Socket<'a> {
             IcmpRepr::Ipv6(ref icmp_repr) => {
                 let packet_buf = self
                     .rx_buffer
-                    .enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())?;
+                    .enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())
+                    .map_err(|_| Error::Exhausted)?;
                 icmp_repr.emit(
                     &ip_repr.src_addr(),
                     &ip_repr.dst_addr(),
@@ -432,59 +460,61 @@ impl<'a> Socket<'a> {
         Ok(())
     }
 
-    pub(crate) fn dispatch<F>(&mut self, cx: &mut Context, emit: F) -> Result<()>
+    pub(crate) fn dispatch<F>(&mut self, cx: &mut Context, emit: F) -> Result<(), Error>
     where
-        F: FnOnce(&mut Context, (IpRepr, IcmpRepr)) -> Result<()>,
+        F: FnOnce(&mut Context, (IpRepr, IcmpRepr)) -> Result<(), Error>,
     {
         let hop_limit = self.hop_limit.unwrap_or(64);
-        self.tx_buffer.dequeue_with(|remote_endpoint, packet_buf| {
-            net_trace!(
-                "icmp:{}: sending {} octets",
-                remote_endpoint,
-                packet_buf.len()
-            );
-            match *remote_endpoint {
-                #[cfg(feature = "proto-ipv4")]
-                IpAddress::Ipv4(dst_addr) => {
-                    let src_addr = match cx.get_source_address_ipv4(dst_addr) {
-                        Some(addr) => addr,
-                        None => return Err(Error::Unaddressable),
-                    };
-                    let packet = Icmpv4Packet::new_unchecked(&*packet_buf);
-                    let repr = Icmpv4Repr::parse(&packet, &ChecksumCapabilities::ignored())?;
-                    let ip_repr = IpRepr::Ipv4(Ipv4Repr {
-                        src_addr,
-                        dst_addr,
-                        next_header: IpProtocol::Icmp,
-                        payload_len: repr.buffer_len(),
-                        hop_limit: hop_limit,
-                    });
-                    emit(cx, (ip_repr, IcmpRepr::Ipv4(repr)))
-                }
-                #[cfg(feature = "proto-ipv6")]
-                IpAddress::Ipv6(dst_addr) => {
-                    let src_addr = match cx.get_source_address_ipv6(dst_addr) {
-                        Some(addr) => addr,
-                        None => return Err(Error::Unaddressable),
-                    };
-                    let packet = Icmpv6Packet::new_unchecked(&*packet_buf);
-                    let repr = Icmpv6Repr::parse(
-                        &src_addr.into(),
-                        &dst_addr.into(),
-                        &packet,
-                        &ChecksumCapabilities::ignored(),
-                    )?;
-                    let ip_repr = IpRepr::Ipv6(Ipv6Repr {
-                        src_addr,
-                        dst_addr,
-                        next_header: IpProtocol::Icmpv6,
-                        payload_len: repr.buffer_len(),
-                        hop_limit: hop_limit,
-                    });
-                    emit(cx, (ip_repr, IcmpRepr::Ipv6(repr)))
+        self.tx_buffer
+            .dequeue_with(|remote_endpoint, packet_buf| {
+                net_trace!(
+                    "icmp:{}: sending {} octets",
+                    remote_endpoint,
+                    packet_buf.len()
+                );
+                match *remote_endpoint {
+                    #[cfg(feature = "proto-ipv4")]
+                    IpAddress::Ipv4(dst_addr) => {
+                        let src_addr = match cx.get_source_address_ipv4(dst_addr) {
+                            Some(addr) => addr,
+                            None => return Err(Error::Unaddressable),
+                        };
+                        let packet = Icmpv4Packet::new_unchecked(&*packet_buf);
+                        let repr = Icmpv4Repr::parse(&packet, &ChecksumCapabilities::ignored())?;
+                        let ip_repr = IpRepr::Ipv4(Ipv4Repr {
+                            src_addr,
+                            dst_addr,
+                            next_header: IpProtocol::Icmp,
+                            payload_len: repr.buffer_len(),
+                            hop_limit: hop_limit,
+                        });
+                        emit(cx, (ip_repr, IcmpRepr::Ipv4(repr)))
+                    }
+                    #[cfg(feature = "proto-ipv6")]
+                    IpAddress::Ipv6(dst_addr) => {
+                        let src_addr = match cx.get_source_address_ipv6(dst_addr) {
+                            Some(addr) => addr,
+                            None => return Err(Error::Unaddressable),
+                        };
+                        let packet = Icmpv6Packet::new_unchecked(&*packet_buf);
+                        let repr = Icmpv6Repr::parse(
+                            &src_addr.into(),
+                            &dst_addr.into(),
+                            &packet,
+                            &ChecksumCapabilities::ignored(),
+                        )?;
+                        let ip_repr = IpRepr::Ipv6(Ipv6Repr {
+                            src_addr,
+                            dst_addr,
+                            next_header: IpProtocol::Icmpv6,
+                            payload_len: repr.buffer_len(),
+                            hop_limit: hop_limit,
+                        });
+                        emit(cx, (ip_repr, IcmpRepr::Ipv6(repr)))
+                    }
                 }
-            }
-        })?;
+            })
+            .map_err(|_| Error::Exhausted)??;
 
         #[cfg(feature = "async")]
         self.tx_waker.wake();
@@ -568,7 +598,7 @@ mod test_ipv4 {
         let mut socket = socket(buffer(0), buffer(1));
         assert_eq!(
             socket.send_slice(b"abcdef", IpAddress::Ipv4(Ipv4Address::default())),
-            Err(Error::Unaddressable)
+            Err(SendError::Unaddressable)
         );
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV4.into()), Ok(()));
     }
@@ -587,7 +617,7 @@ mod test_ipv4 {
         // This buffer is too long
         assert_eq!(
             socket.send_slice(&[0xff; 67], REMOTE_IPV4.into()),
-            Err(Error::Truncated)
+            Err(SendError::BufferFull)
         );
         assert!(socket.can_send());
 
@@ -601,7 +631,7 @@ mod test_ipv4 {
         );
         assert_eq!(
             socket.send_slice(b"123456", REMOTE_IPV4.into()),
-            Err(Error::Exhausted)
+            Err(SendError::BufferFull)
         );
         assert!(!socket.can_send());
 
@@ -669,7 +699,7 @@ mod test_ipv4 {
         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
 
         assert!(!socket.can_recv());
-        assert_eq!(socket.recv(), Err(Error::Exhausted));
+        assert_eq!(socket.recv(), Err(RecvError::Exhausted));
 
         let checksum = ChecksumCapabilities::default();
 
@@ -816,7 +846,7 @@ mod test_ipv6 {
         let mut socket = socket(buffer(0), buffer(1));
         assert_eq!(
             socket.send_slice(b"abcdef", IpAddress::Ipv6(Ipv6Address::default())),
-            Err(Error::Unaddressable)
+            Err(SendError::Unaddressable)
         );
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV6.into()), Ok(()));
     }
@@ -835,7 +865,7 @@ mod test_ipv6 {
         // This buffer is too long
         assert_eq!(
             socket.send_slice(&[0xff; 67], REMOTE_IPV6.into()),
-            Err(Error::Truncated)
+            Err(SendError::BufferFull)
         );
         assert!(socket.can_send());
 
@@ -854,7 +884,7 @@ mod test_ipv6 {
         );
         assert_eq!(
             socket.send_slice(b"123456", REMOTE_IPV6.into()),
-            Err(Error::Exhausted)
+            Err(SendError::BufferFull)
         );
         assert!(!socket.can_send());
 
@@ -927,7 +957,7 @@ mod test_ipv6 {
         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
 
         assert!(!socket.can_recv());
-        assert_eq!(socket.recv(), Err(Error::Exhausted));
+        assert_eq!(socket.recv(), Err(RecvError::Exhausted));
 
         let checksum = ChecksumCapabilities::default();
 

+ 69 - 39
src/socket/raw.rs

@@ -7,7 +7,7 @@ use crate::phy::ChecksumCapabilities;
 use crate::socket::PollAt;
 #[cfg(feature = "async")]
 use crate::socket::WakerRegistration;
-use crate::{Error, Result};
+use crate::Error;
 
 use crate::wire::{IpProtocol, IpRepr, IpVersion};
 #[cfg(feature = "proto-ipv4")]
@@ -15,6 +15,28 @@ use crate::wire::{Ipv4Packet, Ipv4Repr};
 #[cfg(feature = "proto-ipv6")]
 use crate::wire::{Ipv6Packet, Ipv6Repr};
 
+/// Error returned by [`Socket::bind`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum BindError {
+    InvalidState,
+    Unaddressable,
+}
+
+/// Error returned by [`Socket::send`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum SendError {
+    BufferFull,
+}
+
+/// Error returned by [`Socket::recv`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum RecvError {
+    Exhausted,
+}
+
 /// A UDP packet metadata.
 pub type PacketMetadata = crate::storage::PacketMetadata<()>;
 
@@ -152,8 +174,11 @@ impl<'a> Socket<'a> {
     ///
     /// **Note:** The IP header is parsed and re-serialized, and may not match
     /// the header actually transmitted bit for bit.
-    pub fn send(&mut self, size: usize) -> Result<&mut [u8]> {
-        let packet_buf = self.tx_buffer.enqueue(size, ())?;
+    pub fn send(&mut self, size: usize) -> Result<&mut [u8], SendError> {
+        let packet_buf = self
+            .tx_buffer
+            .enqueue(size, ())
+            .map_err(|_| SendError::BufferFull)?;
 
         net_trace!(
             "raw:{}:{}: buffer to send {} octets",
@@ -167,7 +192,7 @@ impl<'a> Socket<'a> {
     /// Enqueue a packet to send, and fill it from a slice.
     ///
     /// See also [send](#method.send).
-    pub fn send_slice(&mut self, data: &[u8]) -> Result<()> {
+    pub fn send_slice(&mut self, data: &[u8]) -> Result<(), SendError> {
         self.send(data.len())?.copy_from_slice(data);
         Ok(())
     }
@@ -178,8 +203,8 @@ impl<'a> Socket<'a> {
     ///
     /// **Note:** The IP header is parsed and re-serialized, and may not match
     /// the header actually received bit for bit.
-    pub fn recv(&mut self) -> Result<&[u8]> {
-        let ((), packet_buf) = self.rx_buffer.dequeue()?;
+    pub fn recv(&mut self) -> Result<&[u8], RecvError> {
+        let ((), packet_buf) = self.rx_buffer.dequeue().map_err(|_| RecvError::Exhausted)?;
 
         net_trace!(
             "raw:{}:{}: receive {} buffered octets",
@@ -193,7 +218,7 @@ impl<'a> Socket<'a> {
     /// Dequeue a packet, and copy the payload into the given slice.
     ///
     /// See also [recv](#method.recv).
-    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<usize> {
+    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<usize, RecvError> {
         let buffer = self.recv()?;
         let length = min(data.len(), buffer.len());
         data[..length].copy_from_slice(&buffer[..length]);
@@ -216,12 +241,15 @@ impl<'a> Socket<'a> {
         cx: &mut Context,
         ip_repr: &IpRepr,
         payload: &[u8],
-    ) -> Result<()> {
+    ) -> Result<(), Error> {
         debug_assert!(self.accepts(ip_repr));
 
         let header_len = ip_repr.buffer_len();
         let total_len = header_len + payload.len();
-        let packet_buf = self.rx_buffer.enqueue(total_len, ())?;
+        let packet_buf = self
+            .rx_buffer
+            .enqueue(total_len, ())
+            .map_err(|_| Error::Exhausted)?;
         ip_repr.emit(&mut packet_buf[..header_len], &cx.checksum_caps());
         packet_buf[header_len..].copy_from_slice(payload);
 
@@ -238,15 +266,15 @@ impl<'a> Socket<'a> {
         Ok(())
     }
 
-    pub(crate) fn dispatch<F>(&mut self, cx: &mut Context, emit: F) -> Result<()>
+    pub(crate) fn dispatch<F>(&mut self, cx: &mut Context, emit: F) -> Result<(), Error>
     where
-        F: FnOnce(&mut Context, (IpRepr, &[u8])) -> Result<()>,
+        F: FnOnce(&mut Context, (IpRepr, &[u8])) -> Result<(), Error>,
     {
         fn prepare<'a>(
             next_header: IpProtocol,
             buffer: &'a mut [u8],
             _checksum_caps: &ChecksumCapabilities,
-        ) -> Result<(IpRepr, &'a [u8])> {
+        ) -> Result<(IpRepr, &'a [u8]), Error> {
             match IpVersion::of_packet(buffer)? {
                 #[cfg(feature = "proto-ipv4")]
                 IpVersion::Ipv4 => {
@@ -281,29 +309,31 @@ impl<'a> Socket<'a> {
 
         let ip_protocol = self.ip_protocol;
         let ip_version = self.ip_version;
-        self.tx_buffer.dequeue_with(|&mut (), packet_buf| {
-            match prepare(ip_protocol, packet_buf, &cx.checksum_caps()) {
-                Ok((ip_repr, raw_packet)) => {
-                    net_trace!(
-                        "raw:{}:{}: sending {} octets",
-                        ip_version,
-                        ip_protocol,
-                        ip_repr.buffer_len() + raw_packet.len()
-                    );
-                    emit(cx, (ip_repr, raw_packet))
-                }
-                Err(error) => {
-                    net_debug!(
-                        "raw:{}:{}: dropping outgoing packet ({})",
-                        ip_version,
-                        ip_protocol,
-                        error
-                    );
-                    // Return Ok(()) so the packet is dequeued.
-                    Ok(())
+        self.tx_buffer
+            .dequeue_with(|&mut (), packet_buf| {
+                match prepare(ip_protocol, packet_buf, &cx.checksum_caps()) {
+                    Ok((ip_repr, raw_packet)) => {
+                        net_trace!(
+                            "raw:{}:{}: sending {} octets",
+                            ip_version,
+                            ip_protocol,
+                            ip_repr.buffer_len() + raw_packet.len()
+                        );
+                        emit(cx, (ip_repr, raw_packet))
+                    }
+                    Err(error) => {
+                        net_debug!(
+                            "raw:{}:{}: dropping outgoing packet ({})",
+                            ip_version,
+                            ip_protocol,
+                            error
+                        );
+                        // Return Ok(()) so the packet is dequeued.
+                        Ok(())
+                    }
                 }
-            }
-        })?;
+            })
+            .map_err(|_| Error::Exhausted)??;
 
         #[cfg(feature = "async")]
         self.tx_waker.wake();
@@ -413,7 +443,7 @@ mod test {
                 #[test]
                 fn test_send_truncated() {
                     let mut socket = $socket(buffer(0), buffer(1));
-                    assert_eq!(socket.send_slice(&[0; 56][..]), Err(Error::Truncated));
+                    assert_eq!(socket.send_slice(&[0; 56][..]), Err(SendError::BufferFull));
                 }
 
                 #[test]
@@ -428,7 +458,7 @@ mod test {
                     );
 
                     assert_eq!(socket.send_slice(&$packet[..]), Ok(()));
-                    assert_eq!(socket.send_slice(b""), Err(Error::Exhausted));
+                    assert_eq!(socket.send_slice(b""), Err(SendError::BufferFull));
                     assert!(!socket.can_send());
 
                     assert_eq!(
@@ -476,7 +506,7 @@ mod test {
                     assert!(socket.accepts(&$hdr));
                     assert_eq!(
                         socket.process(&mut cx, &$hdr, &buffer),
-                        Err(Error::Truncated)
+                        Err(Error::Exhausted)
                     );
                 }
             }
@@ -551,7 +581,7 @@ mod test {
             let mut cksumd_packet = ipv4_locals::PACKET_BYTES;
             Ipv4Packet::new_unchecked(&mut cksumd_packet).fill_checksum();
 
-            assert_eq!(socket.recv(), Err(Error::Exhausted));
+            assert_eq!(socket.recv(), Err(RecvError::Exhausted));
             assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
             assert_eq!(
                 socket.process(
@@ -581,7 +611,7 @@ mod test {
             assert!(!socket.can_recv());
             let mut cx = Context::mock();
 
-            assert_eq!(socket.recv(), Err(Error::Exhausted));
+            assert_eq!(socket.recv(), Err(RecvError::Exhausted));
             assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
             assert_eq!(
                 socket.process(

+ 80 - 41
src/socket/udp.rs

@@ -7,7 +7,7 @@ use crate::socket::PollAt;
 #[cfg(feature = "async")]
 use crate::socket::WakerRegistration;
 use crate::wire::{IpEndpoint, IpListenEndpoint, IpProtocol, IpRepr, UdpRepr};
-use crate::{Error, Result};
+use crate::Error;
 
 /// A UDP packet metadata.
 pub type PacketMetadata = crate::storage::PacketMetadata<IpEndpoint>;
@@ -15,6 +15,29 @@ pub type PacketMetadata = crate::storage::PacketMetadata<IpEndpoint>;
 /// A UDP packet ring buffer.
 pub type PacketBuffer<'a> = crate::storage::PacketBuffer<'a, IpEndpoint>;
 
+/// Error returned by [`Socket::bind`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum BindError {
+    InvalidState,
+    Unaddressable,
+}
+
+/// Error returned by [`Socket::send`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum SendError {
+    Unaddressable,
+    BufferFull,
+}
+
+/// Error returned by [`Socket::recv`]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum RecvError {
+    Exhausted,
+}
+
 /// A User Datagram Protocol socket.
 ///
 /// A UDP socket is bound to a specific endpoint, and owns transmit and receive
@@ -120,14 +143,14 @@ impl<'a> Socket<'a> {
     /// This function returns `Err(Error::Illegal)` if the socket was open
     /// (see [is_open](#method.is_open)), and `Err(Error::Unaddressable)`
     /// if the port in the given endpoint is zero.
-    pub fn bind<T: Into<IpListenEndpoint>>(&mut self, endpoint: T) -> Result<()> {
+    pub fn bind<T: Into<IpListenEndpoint>>(&mut self, endpoint: T) -> Result<(), BindError> {
         let endpoint = endpoint.into();
         if endpoint.port == 0 {
-            return Err(Error::Unaddressable);
+            return Err(BindError::Unaddressable);
         }
 
         if self.is_open() {
-            return Err(Error::Illegal);
+            return Err(BindError::InvalidState);
         }
 
         self.endpoint = endpoint;
@@ -206,18 +229,25 @@ impl<'a> Socket<'a> {
     /// `Err(Error::Unaddressable)` if local or remote port, or remote address are unspecified,
     /// and `Err(Error::Truncated)` if there is not enough transmit buffer capacity
     /// to ever send this packet.
-    pub fn send(&mut self, size: usize, remote_endpoint: IpEndpoint) -> Result<&mut [u8]> {
+    pub fn send(
+        &mut self,
+        size: usize,
+        remote_endpoint: IpEndpoint,
+    ) -> Result<&mut [u8], SendError> {
         if self.endpoint.port == 0 {
-            return Err(Error::Unaddressable);
+            return Err(SendError::Unaddressable);
         }
         if remote_endpoint.addr.is_unspecified() {
-            return Err(Error::Unaddressable);
+            return Err(SendError::Unaddressable);
         }
         if remote_endpoint.port == 0 {
-            return Err(Error::Unaddressable);
+            return Err(SendError::Unaddressable);
         }
 
-        let payload_buf = self.tx_buffer.enqueue(size, remote_endpoint)?;
+        let payload_buf = self
+            .tx_buffer
+            .enqueue(size, remote_endpoint)
+            .map_err(|_| SendError::BufferFull)?;
 
         net_trace!(
             "udp:{}:{}: buffer to send {} octets",
@@ -231,7 +261,11 @@ impl<'a> Socket<'a> {
     /// Enqueue a packet to be sent to a given remote endpoint, and fill it from a slice.
     ///
     /// See also [send](#method.send).
-    pub fn send_slice(&mut self, data: &[u8], remote_endpoint: IpEndpoint) -> Result<()> {
+    pub fn send_slice(
+        &mut self,
+        data: &[u8],
+        remote_endpoint: IpEndpoint,
+    ) -> Result<(), SendError> {
         self.send(data.len(), remote_endpoint)?
             .copy_from_slice(data);
         Ok(())
@@ -241,8 +275,9 @@ impl<'a> Socket<'a> {
     /// as a pointer to the payload.
     ///
     /// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
-    pub fn recv(&mut self) -> Result<(&[u8], IpEndpoint)> {
-        let (remote_endpoint, payload_buf) = self.rx_buffer.dequeue()?;
+    pub fn recv(&mut self) -> Result<(&[u8], IpEndpoint), RecvError> {
+        let (remote_endpoint, payload_buf) =
+            self.rx_buffer.dequeue().map_err(|_| RecvError::Exhausted)?;
 
         net_trace!(
             "udp:{}:{}: receive {} buffered octets",
@@ -257,8 +292,8 @@ impl<'a> Socket<'a> {
     /// and return the amount of octets copied as well as the endpoint.
     ///
     /// See also [recv](#method.recv).
-    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<(usize, IpEndpoint)> {
-        let (buffer, endpoint) = self.recv()?;
+    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<(usize, IpEndpoint), RecvError> {
+        let (buffer, endpoint) = self.recv().map_err(|_| RecvError::Exhausted)?;
         let length = min(data.len(), buffer.len());
         data[..length].copy_from_slice(&buffer[..length]);
         Ok((length, endpoint))
@@ -269,17 +304,19 @@ impl<'a> Socket<'a> {
     /// This function otherwise behaves identically to [recv](#method.recv).
     ///
     /// It returns `Err(Error::Exhausted)` if the receive buffer is empty.
-    pub fn peek(&mut self) -> Result<(&[u8], &IpEndpoint)> {
+    pub fn peek(&mut self) -> Result<(&[u8], &IpEndpoint), RecvError> {
         let endpoint = self.endpoint;
-        self.rx_buffer.peek().map(|(remote_endpoint, payload_buf)| {
-            net_trace!(
-                "udp:{}:{}: peek {} buffered octets",
-                endpoint,
-                remote_endpoint,
-                payload_buf.len()
-            );
-            (payload_buf, remote_endpoint)
-        })
+        self.rx_buffer.peek().map_err(|_| RecvError::Exhausted).map(
+            |(remote_endpoint, payload_buf)| {
+                net_trace!(
+                    "udp:{}:{}: peek {} buffered octets",
+                    endpoint,
+                    remote_endpoint,
+                    payload_buf.len()
+                );
+                (payload_buf, remote_endpoint)
+            },
+        )
     }
 
     /// Peek at a packet received from a remote endpoint, copy the payload into the given slice,
@@ -288,7 +325,7 @@ impl<'a> Socket<'a> {
     /// This function otherwise behaves identically to [recv_slice](#method.recv_slice).
     ///
     /// See also [peek](#method.peek).
-    pub fn peek_slice(&mut self, data: &mut [u8]) -> Result<(usize, &IpEndpoint)> {
+    pub fn peek_slice(&mut self, data: &mut [u8]) -> Result<(usize, &IpEndpoint), RecvError> {
         let (buffer, endpoint) = self.peek()?;
         let length = min(data.len(), buffer.len());
         data[..length].copy_from_slice(&buffer[..length]);
@@ -316,7 +353,7 @@ impl<'a> Socket<'a> {
         ip_repr: &IpRepr,
         repr: &UdpRepr,
         payload: &[u8],
-    ) -> Result<()> {
+    ) -> Result<(), Error> {
         debug_assert!(self.accepts(cx, ip_repr, repr));
 
         let size = payload.len();
@@ -326,7 +363,8 @@ impl<'a> Socket<'a> {
             port: repr.src_port,
         };
         self.rx_buffer
-            .enqueue(size, remote_endpoint)?
+            .enqueue(size, remote_endpoint)
+            .map_err(|_| Error::Exhausted)?
             .copy_from_slice(payload);
 
         net_trace!(
@@ -342,9 +380,9 @@ impl<'a> Socket<'a> {
         Ok(())
     }
 
-    pub(crate) fn dispatch<F>(&mut self, cx: &mut Context, emit: F) -> Result<()>
+    pub(crate) fn dispatch<F>(&mut self, cx: &mut Context, emit: F) -> Result<(), Error>
     where
-        F: FnOnce(&mut Context, (IpRepr, UdpRepr, &[u8])) -> Result<()>,
+        F: FnOnce(&mut Context, (IpRepr, UdpRepr, &[u8])) -> Result<(), Error>,
     {
         let endpoint = self.endpoint;
         let hop_limit = self.hop_limit.unwrap_or(64);
@@ -378,7 +416,8 @@ impl<'a> Socket<'a> {
                     hop_limit,
                 );
                 emit(cx, (ip_repr, repr, payload_buf))
-            })?;
+            })
+            .map_err(|_| Error::Exhausted)??;
 
         #[cfg(feature = "async")]
         self.tx_waker.wake();
@@ -488,14 +527,14 @@ mod test {
     #[test]
     fn test_bind_unaddressable() {
         let mut socket = socket(buffer(0), buffer(0));
-        assert_eq!(socket.bind(0), Err(Error::Unaddressable));
+        assert_eq!(socket.bind(0), Err(BindError::Unaddressable));
     }
 
     #[test]
     fn test_bind_twice() {
         let mut socket = socket(buffer(0), buffer(0));
         assert_eq!(socket.bind(1), Ok(()));
-        assert_eq!(socket.bind(2), Err(Error::Illegal));
+        assert_eq!(socket.bind(2), Err(BindError::InvalidState));
     }
 
     #[test]
@@ -511,7 +550,7 @@ mod test {
 
         assert_eq!(
             socket.send_slice(b"abcdef", REMOTE_END),
-            Err(Error::Unaddressable)
+            Err(SendError::Unaddressable)
         );
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
         assert_eq!(
@@ -522,7 +561,7 @@ mod test {
                     ..REMOTE_END
                 }
             ),
-            Err(Error::Unaddressable)
+            Err(SendError::Unaddressable)
         );
         assert_eq!(
             socket.send_slice(
@@ -532,7 +571,7 @@ mod test {
                     ..REMOTE_END
                 }
             ),
-            Err(Error::Unaddressable)
+            Err(SendError::Unaddressable)
         );
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_END), Ok(()));
     }
@@ -553,7 +592,7 @@ mod test {
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_END), Ok(()));
         assert_eq!(
             socket.send_slice(b"123456", REMOTE_END),
-            Err(Error::Exhausted)
+            Err(SendError::BufferFull)
         );
         assert!(!socket.can_send());
 
@@ -588,7 +627,7 @@ mod test {
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
         assert!(!socket.can_recv());
-        assert_eq!(socket.recv(), Err(Error::Exhausted));
+        assert_eq!(socket.recv(), Err(RecvError::Exhausted));
 
         assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
         assert_eq!(
@@ -613,7 +652,7 @@ mod test {
 
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
-        assert_eq!(socket.peek(), Err(Error::Exhausted));
+        assert_eq!(socket.peek(), Err(RecvError::Exhausted));
 
         assert_eq!(
             socket.process(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR, PAYLOAD),
@@ -621,7 +660,7 @@ mod test {
         );
         assert_eq!(socket.peek(), Ok((&b"abcdef"[..], &REMOTE_END)));
         assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END)));
-        assert_eq!(socket.peek(), Err(Error::Exhausted));
+        assert_eq!(socket.peek(), Err(RecvError::Exhausted));
     }
 
     #[test]
@@ -659,7 +698,7 @@ mod test {
         assert_eq!(&slice, b"abcd");
         assert_eq!(socket.recv_slice(&mut slice[..]), Ok((4, REMOTE_END)));
         assert_eq!(&slice, b"abcd");
-        assert_eq!(socket.peek_slice(&mut slice[..]), Err(Error::Exhausted));
+        assert_eq!(socket.peek_slice(&mut slice[..]), Err(RecvError::Exhausted));
     }
 
     #[test]
@@ -724,7 +763,7 @@ mod test {
         let too_large = b"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefx";
         assert_eq!(
             socket.send_slice(too_large, REMOTE_END),
-            Err(Error::Truncated)
+            Err(SendError::BufferFull)
         );
         assert_eq!(socket.send_slice(&too_large[..16 * 4], REMOTE_END), Ok(()));
     }

+ 1 - 1
src/storage/assembler.rs

@@ -192,7 +192,7 @@ impl Assembler {
     }
 
     /// Add a new contiguous range to the assembler, and return `Ok(bool)`,
-    /// or return `Err(())` if too many discontiguities are already recorded.
+    /// or return `Err(TooManyHolesError)` if too many discontiguities are already recorded.
     /// Returns `Ok(true)` when there was an overlap.
     pub fn add(&mut self, mut offset: usize, mut size: usize) -> Result<bool, TooManyHolesError> {
         let mut index = 0;

+ 10 - 0
src/storage/mod.rs

@@ -19,3 +19,13 @@ pub use self::ring_buffer::RingBuffer;
 pub trait Resettable {
     fn reset(&mut self);
 }
+
+/// Error returned when enqueuing into a full buffer.
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct Full;
+
+/// Error returned when dequeuing from an empty buffer.
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct Empty;

+ 30 - 33
src/storage/packet_buffer.rs

@@ -1,7 +1,8 @@
 use managed::ManagedSlice;
 
-use crate::storage::RingBuffer;
-use crate::{Error, Result};
+use crate::storage::{Full, RingBuffer};
+
+use super::Empty;
 
 /// Size and header of a packet.
 #[derive(Debug, Clone, Copy)]
@@ -74,30 +75,25 @@ impl<'a, H> PacketBuffer<'a, H> {
     // in case of failure.
 
     /// Enqueue a single packet with the given header into the buffer, and
-    /// return a reference to its payload, or return `Err(Error::Exhausted)`
-    /// if the buffer is full, or return `Err(Error::Truncated)` if the buffer
-    /// does not have enough spare payload space.
-    pub fn enqueue(&mut self, size: usize, header: H) -> Result<&mut [u8]> {
-        if self.payload_ring.capacity() < size {
-            return Err(Error::Truncated);
-        }
-
-        if self.metadata_ring.is_full() {
-            return Err(Error::Exhausted);
+    /// return a reference to its payload, or return `Err(Full)`
+    /// if the buffer is full.
+    pub fn enqueue(&mut self, size: usize, header: H) -> Result<&mut [u8], Full> {
+        if self.payload_ring.capacity() < size || self.metadata_ring.is_full() {
+            return Err(Full);
         }
 
         let window = self.payload_ring.window();
         let contig_window = self.payload_ring.contiguous_window();
 
         if window < size {
-            return Err(Error::Exhausted);
+            return Err(Full);
         } else if contig_window < size {
             if window - contig_window < size {
                 // The buffer length is larger than the current contiguous window
                 // and is larger than the contiguous window will be after adding
                 // the padding necessary to circle around to the beginning of the
                 // ring buffer.
-                return Err(Error::Exhausted);
+                return Err(Full);
             } else {
                 // Add padding to the end of the ring buffer so that the
                 // contiguous window is at the beginning of the ring buffer.
@@ -127,16 +123,16 @@ impl<'a, H> PacketBuffer<'a, H> {
                 let _buf_dequeued = payload_ring.dequeue_many(metadata.size);
                 Ok(()) // dequeue metadata
             } else {
-                Err(Error::Exhausted) // don't dequeue metadata
+                Err(()) // don't dequeue metadata
             }
         });
     }
 
     /// Call `f` with a single packet from the buffer, and dequeue the packet if `f`
-    /// returns successfully, or return `Err(Error::Exhausted)` if the buffer is empty.
-    pub fn dequeue_with<'c, R, F>(&'c mut self, f: F) -> Result<R>
+    /// returns successfully, or return `Err(EmptyError)` if the buffer is empty.
+    pub fn dequeue_with<'c, R, E, F>(&'c mut self, f: F) -> Result<Result<R, E>, Empty>
     where
-        F: FnOnce(&mut H, &'c mut [u8]) -> Result<R>,
+        F: FnOnce(&mut H, &'c mut [u8]) -> Result<R, E>,
     {
         self.dequeue_padding();
 
@@ -166,7 +162,7 @@ impl<'a, H> PacketBuffer<'a, H> {
 
     /// Dequeue a single packet from the buffer, and return a reference to its payload
     /// as well as its header, or return `Err(Error::Exhausted)` if the buffer is empty.
-    pub fn dequeue(&mut self) -> Result<(H, &mut [u8])> {
+    pub fn dequeue(&mut self) -> Result<(H, &mut [u8]), Empty> {
         self.dequeue_padding();
 
         let PacketMetadata {
@@ -183,7 +179,7 @@ impl<'a, H> PacketBuffer<'a, H> {
     /// its payload as well as its header, or return `Err(Error:Exhausted)` if the buffer is empty.
     ///
     /// This function otherwise behaves identically to [dequeue](#method.dequeue).
-    pub fn peek(&mut self) -> Result<(&H, &[u8])> {
+    pub fn peek(&mut self) -> Result<(&H, &[u8]), Empty> {
         self.dequeue_padding();
 
         if let Some(metadata) = self.metadata_ring.get_allocated(0, 1).first() {
@@ -192,7 +188,7 @@ impl<'a, H> PacketBuffer<'a, H> {
                 self.payload_ring.get_allocated(0, metadata.size),
             ))
         } else {
-            Err(Error::Exhausted)
+            Err(Empty)
         }
     }
 
@@ -226,21 +222,21 @@ mod test {
     fn test_simple() {
         let mut buffer = buffer();
         buffer.enqueue(6, ()).unwrap().copy_from_slice(b"abcdef");
-        assert_eq!(buffer.enqueue(16, ()), Err(Error::Exhausted));
+        assert_eq!(buffer.enqueue(16, ()), Err(Full));
         assert_eq!(buffer.metadata_ring.len(), 1);
         assert_eq!(buffer.dequeue().unwrap().1, &b"abcdef"[..]);
-        assert_eq!(buffer.dequeue(), Err(Error::Exhausted));
+        assert_eq!(buffer.dequeue(), Err(Empty));
     }
 
     #[test]
     fn test_peek() {
         let mut buffer = buffer();
-        assert_eq!(buffer.peek(), Err(Error::Exhausted));
+        assert_eq!(buffer.peek(), Err(Empty));
         buffer.enqueue(6, ()).unwrap().copy_from_slice(b"abcdef");
         assert_eq!(buffer.metadata_ring.len(), 1);
         assert_eq!(buffer.peek().unwrap().1, &b"abcdef"[..]);
         assert_eq!(buffer.dequeue().unwrap().1, &b"abcdef"[..]);
-        assert_eq!(buffer.peek(), Err(Error::Exhausted));
+        assert_eq!(buffer.peek(), Err(Empty));
     }
 
     #[test]
@@ -278,15 +274,16 @@ mod test {
         assert_eq!(buffer.metadata_ring.len(), 3);
         assert!(buffer.dequeue().is_ok());
 
-        assert!(buffer
-            .dequeue_with(|_, _| Err(Error::Unaddressable) as Result<()>)
-            .is_err());
+        assert!(matches!(
+            buffer.dequeue_with(|_, _| Result::<(), u32>::Err(123)),
+            Ok(Err(_))
+        ));
         assert_eq!(buffer.metadata_ring.len(), 1);
 
         assert!(buffer
             .dequeue_with(|&mut (), payload| {
                 assert_eq!(payload, &b"abcd"[..]);
-                Ok(())
+                Result::<(), ()>::Ok(())
             })
             .is_ok());
         assert_eq!(buffer.metadata_ring.len(), 0);
@@ -307,7 +304,7 @@ mod test {
         assert!(buffer.is_full());
         assert!(!buffer.is_empty());
         assert_eq!(buffer.metadata_ring.len(), 4);
-        assert_eq!(buffer.enqueue(1, ()), Err(Error::Exhausted));
+        assert_eq!(buffer.enqueue(1, ()), Err(Full));
     }
 
     #[test]
@@ -316,7 +313,7 @@ mod test {
         assert!(buffer.enqueue(4, ()).is_ok());
         assert!(buffer.enqueue(8, ()).is_ok());
         assert!(buffer.dequeue().is_ok());
-        assert_eq!(buffer.enqueue(16, ()), Err(Error::Exhausted));
+        assert_eq!(buffer.enqueue(16, ()), Err(Full));
         assert_eq!(buffer.metadata_ring.len(), 1);
     }
 
@@ -326,14 +323,14 @@ mod test {
         assert!(buffer.enqueue(4, ()).is_ok());
         assert!(buffer.enqueue(8, ()).is_ok());
         assert!(buffer.dequeue().is_ok());
-        assert_eq!(buffer.enqueue(8, ()), Err(Error::Exhausted));
+        assert_eq!(buffer.enqueue(8, ()), Err(Full));
         assert_eq!(buffer.metadata_ring.len(), 1);
     }
 
     #[test]
     fn test_capacity_too_small() {
         let mut buffer = buffer();
-        assert_eq!(buffer.enqueue(32, ()), Err(Error::Truncated));
+        assert_eq!(buffer.enqueue(32, ()), Err(Full));
     }
 
     #[test]

+ 44 - 41
src/storage/ring_buffer.rs

@@ -6,7 +6,8 @@ use core::cmp;
 use managed::ManagedSlice;
 
 use crate::storage::Resettable;
-use crate::{Error, Result};
+
+use super::{Empty, Full};
 
 /// A ring buffer.
 ///
@@ -114,60 +115,57 @@ impl<'a, T: 'a> RingBuffer<'a, T> {
 /// and boundary conditions (empty/full) are errors.
 impl<'a, T: 'a> RingBuffer<'a, T> {
     /// Call `f` with a single buffer element, and enqueue the element if `f`
-    /// returns successfully, or return `Err(Error::Exhausted)` if the buffer is full.
-    pub fn enqueue_one_with<'b, R, F>(&'b mut self, f: F) -> Result<R>
+    /// returns successfully, or return `Err(Full)` if the buffer is full.
+    pub fn enqueue_one_with<'b, R, E, F>(&'b mut self, f: F) -> Result<Result<R, E>, Full>
     where
-        F: FnOnce(&'b mut T) -> Result<R>,
+        F: FnOnce(&'b mut T) -> Result<R, E>,
     {
         if self.is_full() {
-            return Err(Error::Exhausted);
+            return Err(Full);
         }
 
         let index = self.get_idx_unchecked(self.length);
-        match f(&mut self.storage[index]) {
-            Ok(result) => {
-                self.length += 1;
-                Ok(result)
-            }
-            Err(error) => Err(error),
+        let res = f(&mut self.storage[index]);
+        if res.is_ok() {
+            self.length += 1;
         }
+        Ok(res)
     }
 
     /// Enqueue a single element into the buffer, and return a reference to it,
-    /// or return `Err(Error::Exhausted)` if the buffer is full.
+    /// or return `Err(Full)` if the buffer is full.
     ///
     /// This function is a shortcut for `ring_buf.enqueue_one_with(Ok)`.
-    pub fn enqueue_one(&mut self) -> Result<&mut T> {
-        self.enqueue_one_with(Ok)
+    pub fn enqueue_one(&mut self) -> Result<&mut T, Full> {
+        self.enqueue_one_with(Ok)?
     }
 
     /// Call `f` with a single buffer element, and dequeue the element if `f`
-    /// returns successfully, or return `Err(Error::Exhausted)` if the buffer is empty.
-    pub fn dequeue_one_with<'b, R, F>(&'b mut self, f: F) -> Result<R>
+    /// returns successfully, or return `Err(Empty)` if the buffer is empty.
+    pub fn dequeue_one_with<'b, R, E, F>(&'b mut self, f: F) -> Result<Result<R, E>, Empty>
     where
-        F: FnOnce(&'b mut T) -> Result<R>,
+        F: FnOnce(&'b mut T) -> Result<R, E>,
     {
         if self.is_empty() {
-            return Err(Error::Exhausted);
+            return Err(Empty);
         }
 
         let next_at = self.get_idx_unchecked(1);
-        match f(&mut self.storage[self.read_at]) {
-            Ok(result) => {
-                self.length -= 1;
-                self.read_at = next_at;
-                Ok(result)
-            }
-            Err(error) => Err(error),
+        let res = f(&mut self.storage[self.read_at]);
+
+        if res.is_ok() {
+            self.length -= 1;
+            self.read_at = next_at;
         }
+        Ok(res)
     }
 
     /// Dequeue an element from the buffer, and return a reference to it,
-    /// or return `Err(Error::Exhausted)` if the buffer is empty.
+    /// or return `Err(Empty)` if the buffer is empty.
     ///
     /// This function is a shortcut for `ring_buf.dequeue_one_with(Ok)`.
-    pub fn dequeue_one(&mut self) -> Result<&mut T> {
-        self.dequeue_one_with(Ok)
+    pub fn dequeue_one(&mut self) -> Result<&mut T, Empty> {
+        self.dequeue_one_with(Ok)?
     }
 }
 
@@ -441,31 +439,36 @@ mod test {
     fn test_buffer_enqueue_dequeue_one_with() {
         let mut ring = RingBuffer::new(vec![0; 5]);
         assert_eq!(
-            ring.dequeue_one_with(|_| unreachable!()) as Result<()>,
-            Err(Error::Exhausted)
+            ring.dequeue_one_with(|_| -> Result::<(), ()> { unreachable!() }),
+            Err(Empty)
         );
 
-        ring.enqueue_one_with(Ok).unwrap();
+        ring.enqueue_one_with(Ok::<_, ()>).unwrap().unwrap();
         assert!(!ring.is_empty());
         assert!(!ring.is_full());
 
         for i in 1..5 {
-            ring.enqueue_one_with(|e| Ok(*e = i)).unwrap();
+            ring.enqueue_one_with(|e| Ok::<_, ()>(*e = i))
+                .unwrap()
+                .unwrap();
             assert!(!ring.is_empty());
         }
         assert!(ring.is_full());
         assert_eq!(
-            ring.enqueue_one_with(|_| unreachable!()) as Result<()>,
-            Err(Error::Exhausted)
+            ring.enqueue_one_with(|_| -> Result::<(), ()> { unreachable!() }),
+            Err(Full)
         );
 
         for i in 0..5 {
-            assert_eq!(ring.dequeue_one_with(|e| Ok(*e)).unwrap(), i);
+            assert_eq!(
+                ring.dequeue_one_with(|e| Ok::<_, ()>(*e)).unwrap().unwrap(),
+                i
+            );
             assert!(!ring.is_full());
         }
         assert_eq!(
-            ring.dequeue_one_with(|_| unreachable!()) as Result<()>,
-            Err(Error::Exhausted)
+            ring.dequeue_one_with(|_| -> Result::<(), ()> { unreachable!() }),
+            Err(Empty)
         );
         assert!(ring.is_empty());
     }
@@ -473,7 +476,7 @@ mod test {
     #[test]
     fn test_buffer_enqueue_dequeue_one() {
         let mut ring = RingBuffer::new(vec![0; 5]);
-        assert_eq!(ring.dequeue_one(), Err(Error::Exhausted));
+        assert_eq!(ring.dequeue_one(), Err(Empty));
 
         ring.enqueue_one().unwrap();
         assert!(!ring.is_empty());
@@ -484,13 +487,13 @@ mod test {
             assert!(!ring.is_empty());
         }
         assert!(ring.is_full());
-        assert_eq!(ring.enqueue_one(), Err(Error::Exhausted));
+        assert_eq!(ring.enqueue_one(), Err(Full));
 
         for i in 0..5 {
             assert_eq!(*ring.dequeue_one().unwrap(), i);
             assert!(!ring.is_full());
         }
-        assert_eq!(ring.dequeue_one(), Err(Error::Exhausted));
+        assert_eq!(ring.dequeue_one(), Err(Empty));
         assert!(ring.is_empty());
     }
 
@@ -777,7 +780,7 @@ mod test {
         assert_eq!(no_capacity.get_allocated(0, 0), &[]);
         no_capacity.dequeue_allocated(0);
         assert_eq!(no_capacity.enqueue_many(0), &[]);
-        assert_eq!(no_capacity.enqueue_one(), Err(Error::Exhausted));
+        assert_eq!(no_capacity.enqueue_one(), Err(Full));
         assert_eq!(no_capacity.contiguous_window(), 0);
     }