cotton_ssdp/udp/
error.rs

1/// The list of system calls which can return errors
2#[non_exhaustive]
3#[derive(Debug)]
4pub enum Syscall {
5    /// recvmsg() returned an error
6    Recvmsg,
7    /// sendmsg() returned an error
8    Sendmsg,
9    /// setsockopt(IP_ADD_MEMBERSHIP) returned an error
10    JoinMulticast,
11    /// setsockopt(IP_DROP_MEMBERSHIP) returned an error
12    LeaveMulticast,
13}
14
15/// The errors which can be returned from UDP trait methods
16#[non_exhaustive]
17#[derive(Debug)]
18pub enum Error {
19    /// recvmsg didn't return packet info as expected
20    NoPacketInfo,
21    /// IPv6 attempted (NYI)
22    Ipv6NotImplemented,
23    /// Something else not implemented
24    NotImplemented,
25
26    /// A system call returned an error
27    #[cfg(feature = "std")]
28    Syscall(Syscall, ::std::io::Error),
29
30    /// A smoltcp multicast call returned an error
31    #[cfg(feature = "smoltcp")]
32    SmoltcpMulticast(Syscall, ::smoltcp::iface::MulticastError),
33
34    /// A smoltcp send call returned an error
35    #[cfg(feature = "smoltcp")]
36    SmoltcpUdpSend(::smoltcp::socket::udp::SendError),
37}
38
39impl ::core::fmt::Display for Error {
40    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
41        match self {
42            Self::NoPacketInfo => f.write_str("recvmsg: no pktinfo returned"),
43            Self::Ipv6NotImplemented => f.write_str("IPv6 not implemented"),
44            Self::NotImplemented => f.write_str("not implemented"),
45
46            #[cfg(feature = "std")]
47            Self::Syscall(s, _) => write!(f, "error from syscall {s:?}"),
48
49            #[cfg(feature = "smoltcp")]
50            Self::SmoltcpMulticast(s, e) => {
51                write!(f, "error from smoltcp {s:?}: {e:?}")
52            }
53
54            #[cfg(feature = "smoltcp")]
55            Self::SmoltcpUdpSend(e) => {
56                write!(f, "error from smoltcp UDP send: {e:?}")
57            }
58        }
59    }
60}
61
62#[cfg(feature = "std")]
63impl ::std::error::Error for Error {
64    fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
65        // NB smoltcp errors do not implement std::Error
66        match self {
67            Self::Syscall(_, e) => Some(e),
68            _ => None,
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use alloc::format;
77    use alloc::string::ToString;
78
79    #[test]
80    #[cfg(feature = "std")]
81    fn display_pkt_error() {
82        use ::std::error::Error;
83
84        let e = super::Error::NoPacketInfo;
85        let m = format!("{e}");
86        assert_eq!(m, "recvmsg: no pktinfo returned".to_string());
87
88        assert!(e.source().is_none());
89    }
90
91    #[test]
92    fn debug_pkt_error() {
93        let e = Error::NoPacketInfo;
94        let e = format!("{e:?}");
95        assert_eq!(e, "NoPacketInfo".to_string());
96    }
97
98    #[test]
99    #[cfg(feature = "std")]
100    fn display_ipv6_error() {
101        use ::std::error::Error;
102
103        let e = super::Error::Ipv6NotImplemented;
104        let m = format!("{e}");
105        assert_eq!(m, "IPv6 not implemented".to_string());
106
107        assert!(e.source().is_none());
108    }
109
110    #[test]
111    fn debug_ipv6_error() {
112        let e = super::Error::Ipv6NotImplemented;
113        let e = format!("{e:?}");
114        assert_eq!(e, "Ipv6NotImplemented".to_string());
115    }
116
117    #[test]
118    #[cfg(feature = "std")]
119    fn display_nyi_error() {
120        use ::std::error::Error;
121
122        let e = super::Error::NotImplemented;
123        let m = format!("{e}");
124        assert_eq!(m, "not implemented".to_string());
125
126        assert!(e.source().is_none());
127    }
128
129    #[test]
130    fn debug_nyi_error() {
131        let e = super::Error::NotImplemented;
132        let e = format!("{e:?}");
133        assert_eq!(e, "NotImplemented".to_string());
134    }
135
136    #[test]
137    #[cfg(feature = "std")]
138    fn display_syscall_error() {
139        use ::std::error::Error;
140
141        let e = super::Error::Syscall(
142            Syscall::JoinMulticast,
143            ::std::io::Error::new(::std::io::ErrorKind::Other, "injected"),
144        );
145        let m = format!("{e}");
146        assert_eq!(m, "error from syscall JoinMulticast".to_string());
147
148        let m = format!("{}", e.source().unwrap());
149        assert_eq!(m, "injected".to_string());
150    }
151
152    #[test]
153    #[cfg(feature = "std")]
154    fn debug_syscall_error() {
155        let e = Error::Syscall(
156            Syscall::JoinMulticast,
157            ::std::io::Error::new(::std::io::ErrorKind::Other, "injected"),
158        );
159        let e = format!("{e:?}");
160        assert_eq!(e, "Syscall(JoinMulticast, Custom { kind: Other, error: \"injected\" })".to_string());
161    }
162
163    #[test]
164    #[cfg(feature = "smoltcp")]
165    fn display_smoltcp_error() {
166        let e = Error::SmoltcpMulticast(
167            Syscall::JoinMulticast,
168            ::smoltcp::iface::MulticastError::GroupTableFull,
169        );
170        let m = format!("{e}");
171        assert_eq!(
172            m,
173            "error from smoltcp JoinMulticast: GroupTableFull".to_string()
174        );
175    }
176
177    #[test]
178    #[cfg(feature = "smoltcp")]
179    fn debug_smoltcp_error() {
180        let e = Error::SmoltcpMulticast(
181            Syscall::JoinMulticast,
182            ::smoltcp::iface::MulticastError::Unaddressable,
183        );
184        let e = format!("{e:?}");
185        assert_eq!(
186            e,
187            "SmoltcpMulticast(JoinMulticast, Unaddressable)".to_string()
188        );
189    }
190
191    #[test]
192    #[cfg(feature = "smoltcp")]
193    fn display_smoltcp_udp_send_error() {
194        let e = Error::SmoltcpUdpSend(
195            ::smoltcp::socket::udp::SendError::BufferFull,
196        );
197        let m = format!("{e}");
198        assert_eq!(m, "error from smoltcp UDP send: BufferFull".to_string());
199    }
200
201    #[test]
202    #[cfg(feature = "smoltcp")]
203    fn debug_smoltcp_udp_send_error() {
204        let e = Error::SmoltcpUdpSend(
205            ::smoltcp::socket::udp::SendError::BufferFull,
206        );
207        let e = format!("{e:?}");
208        assert_eq!(e, "SmoltcpUdpSend(BufferFull)".to_string());
209    }
210}