1#![cfg_attr(not(test), no_std)]
2
3pub(crate) mod fmt;
5
6mod meta;
7mod ref_;
8mod ring_buffer;
9mod set;
10pub mod tcp;
11pub mod tcp_listener;
12pub mod udp;
13pub mod udp_listener;
14
15pub(crate) use self::meta::Meta as SocketMeta;
16pub use self::ring_buffer::RingBuffer;
17
18#[cfg(feature = "socket-tcp")]
19pub use tcp::{State as TcpState, TcpSocket};
20
21#[cfg(feature = "socket-udp")]
22pub use udp::{State as UdpState, UdpSocket};
23
24pub use self::set::{Handle as SocketHandle, Set as SocketSet};
25
26pub use self::ref_::Ref as SocketRef;
27
28#[non_exhaustive]
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub enum Error {
33 Exhausted,
35 Illegal,
37 Unaddressable,
41
42 Timer,
43 Timeout,
44
45 SocketClosed,
46 BadLength,
47
48 NotBound,
49
50 ListenerError,
51
52 SocketSetFull,
53 InvalidSocket,
54 DuplicateSocket,
55}
56
57type Result<T> = core::result::Result<T, Error>;
58pub type Instant<const TIMER_HZ: u32> = fugit::TimerInstantU32<TIMER_HZ>;
59
60#[non_exhaustive]
71#[derive(Debug)]
72pub enum Socket<const TIMER_HZ: u32, const L: usize> {
73 #[cfg(feature = "socket-udp")]
74 Udp(UdpSocket<TIMER_HZ, L>),
75 #[cfg(feature = "socket-tcp")]
76 Tcp(TcpSocket<TIMER_HZ, L>),
77}
78
79#[non_exhaustive]
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub enum SocketType {
83 Udp,
84 Tcp,
85}
86
87impl<const TIMER_HZ: u32, const L: usize> Socket<TIMER_HZ, L> {
88 #[inline]
90 pub fn handle(&self) -> SocketHandle {
91 self.meta().handle
92 }
93
94 pub(crate) fn meta(&self) -> &SocketMeta {
95 match self {
96 #[cfg(feature = "socket-udp")]
97 Socket::Udp(ref socket) => &socket.meta,
98 #[cfg(feature = "socket-tcp")]
99 Socket::Tcp(ref socket) => &socket.meta,
100 }
101 }
102
103 pub fn get_type(&self) -> SocketType {
104 match self {
105 Socket::Tcp(_) => SocketType::Tcp,
106 Socket::Udp(_) => SocketType::Udp,
107 }
108 }
109
110 pub fn should_update_available_data(&mut self, ts: Instant<TIMER_HZ>) -> bool {
111 match self {
112 Socket::Tcp(s) => s.should_update_available_data(ts),
113 Socket::Udp(s) => s.should_update_available_data(ts),
114 }
115 }
116
117 pub fn available_data(&self) -> usize {
118 match self {
119 Socket::Tcp(s) => s.get_available_data(),
120 Socket::Udp(s) => s.get_available_data(),
121 }
122 }
123
124 pub fn recycle(&self, ts: Instant<TIMER_HZ>) -> bool {
125 match self {
126 Socket::Tcp(s) => s.recycle(ts),
127 Socket::Udp(s) => s.recycle(ts),
128 }
129 }
130
131 pub fn closed_by_remote(&mut self, ts: Instant<TIMER_HZ>) {
132 match self {
133 Socket::Tcp(s) => s.closed_by_remote(ts),
134 Socket::Udp(s) => s.closed_by_remote(ts),
135 }
136 }
137
138 pub fn set_available_data(&mut self, available_data: usize) {
139 match self {
140 Socket::Tcp(s) => s.set_available_data(available_data),
141 Socket::Udp(s) => s.set_available_data(available_data),
142 }
143 }
144
145 pub fn rx_enqueue_slice(&mut self, data: &[u8]) -> usize {
146 match self {
147 Socket::Tcp(s) => s.rx_enqueue_slice(data),
148 Socket::Udp(s) => s.rx_enqueue_slice(data),
149 }
150 }
151
152 pub fn rx_window(&self) -> usize {
153 match self {
154 Socket::Tcp(s) => s.rx_window(),
155 Socket::Udp(s) => s.rx_window(),
156 }
157 }
158
159 pub fn can_recv(&self) -> bool {
160 match self {
161 Socket::Tcp(s) => s.can_recv(),
162 Socket::Udp(s) => s.can_recv(),
163 }
164 }
165}
166
167pub trait AnySocket<const TIMER_HZ: u32, const L: usize>: Sized {
169 fn downcast(socket_ref: SocketRef<'_, Socket<TIMER_HZ, L>>) -> Result<SocketRef<'_, Self>>;
170}
171
172#[cfg(feature = "socket-tcp")]
173impl<const TIMER_HZ: u32, const L: usize> AnySocket<TIMER_HZ, L> for TcpSocket<TIMER_HZ, L> {
174 fn downcast(ref_: SocketRef<'_, Socket<TIMER_HZ, L>>) -> Result<SocketRef<'_, Self>> {
175 match SocketRef::into_inner(ref_) {
176 Socket::Tcp(ref mut socket) => Ok(SocketRef::new(socket)),
177 _ => Err(Error::Illegal),
178 }
179 }
180}
181
182#[cfg(feature = "socket-udp")]
183impl<const TIMER_HZ: u32, const L: usize> AnySocket<TIMER_HZ, L> for UdpSocket<TIMER_HZ, L> {
184 fn downcast(ref_: SocketRef<'_, Socket<TIMER_HZ, L>>) -> Result<SocketRef<'_, Self>> {
185 match SocketRef::into_inner(ref_) {
186 Socket::Udp(ref mut socket) => Ok(SocketRef::new(socket)),
187 _ => Err(Error::Illegal),
188 }
189 }
190}
191
192#[cfg(test)]
193#[cfg(feature = "defmt")]
194mod test_helpers {
195 use core::ptr::NonNull;
196
197 #[defmt::global_logger]
198 struct Logger;
199 impl defmt::Write for Logger {
200 fn write(&mut self, _bytes: &[u8]) {}
201 }
202
203 unsafe impl defmt::Logger for Logger {
204 fn acquire() -> Option<NonNull<dyn defmt::Write>> {
205 Some(NonNull::from(&Logger as &dyn defmt::Write))
206 }
207
208 unsafe fn release(_: NonNull<dyn defmt::Write>) {}
209 }
210
211 defmt::timestamp!("");
212
213 #[export_name = "_defmt_panic"]
214 fn panic() -> ! {
215 panic!()
216 }
217}