embedded_nal/stack/
share.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use crate::{nb, SocketAddr, TcpClientStack, TcpFullStack, UdpClientStack, UdpFullStack};
use core::cell::RefCell;

/// Sharable wrapper for a network stack implementation.
///
/// An implementation of the stack traits that can contain (and provide provide
/// single-threaded shared access to) another stack implementation. A direct
/// implementation can only be used when owned or with a mutable reference.
/// This implementation will store another implementation internally, and yield
/// an arbitrary number of shared references to it, which themselves implement
/// the stack traits.
///
/// ```
/// use embedded_nal::SharableStack;
/// # use embedded_nal::{UdpClientStack, SocketAddr, SocketAddrV4, Ipv4Addr, nb};
/// # struct SomeNalDriver {}
/// # impl SomeNalDriver {
/// #   fn new() -> Self { Self {} }
/// # }
/// # impl UdpClientStack for SomeNalDriver {
/// #   type Error = ();
/// #   type UdpSocket = ();
/// #   fn socket(&mut self) -> Result<Self::UdpSocket, Self::Error> {
/// #     Ok(())
/// #   }
/// #   fn connect(
/// #       &mut self,
/// #       socket: &mut Self::UdpSocket,
/// #       remote: SocketAddr,
/// #   ) -> Result<(), Self::Error> {
/// #     Ok(())
/// #   }
/// #   fn send(&mut self, socket: &mut Self::UdpSocket, buffer: &[u8]) -> nb::Result<(), Self::Error> {
/// #     Ok(())
/// #   }
/// #   fn receive(
/// #       &mut self,
/// #       socket: &mut Self::UdpSocket,
/// #       buffer: &mut [u8],
/// #   ) -> nb::Result<(usize, SocketAddr), Self::Error> {
/// #     Ok((0, SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0))))
/// #   }
/// #   fn close(&mut self, socket: Self::UdpSocket) -> Result<(), Self::Error> {
/// #     Ok(())
/// #   }
/// # }
/// let mut driver = SomeNalDriver::new();
/// // Driver can only be used in one place at a time.
/// let mut sharable_driver = SharableStack::new(driver);
/// // Sharable driver can't do anything on its own, but it can create many usable copies.
/// let mut shared_driver0 = sharable_driver.acquire();
/// let mut shared_driver1 = sharable_driver.acquire();
/// // These shared copies can be passed around to other parts of an application's code, and used
/// // independently.
/// let mut socket0 = shared_driver0.socket()?;
/// shared_driver0.connect(&mut socket0, SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
/// // ...
///
/// // ... and somewhere else
/// let mut socket1 = shared_driver1.socket()?;
/// shared_driver1.connect(&mut socket1, SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8443)));
/// // ...
/// # Ok::<(), ()>(())
/// ```
pub struct SharableStack<T> {
	stack: RefCell<T>,
}

impl<T> SharableStack<T> {
	/// Create a new SharedStack that contains and uses some other stack implementation.
	pub fn new(stack: T) -> Self {
		SharableStack {
			stack: RefCell::new(stack),
		}
	}

	/// Returns a shared reference to the driver that can be used as a first-class implementation.
	pub fn acquire(&self) -> SharedStack<T> {
		SharedStack { stack: &self.stack }
	}
}

/// Single-thread shared reference to an internal network stack implementation.
///
/// This can only be created by calling [`SharableStack::acquire()`]
pub struct SharedStack<'a, T> {
	stack: &'a RefCell<T>,
}

macro_rules! forward {
    ($func:ident($($v:ident: $IT:ty),*) -> $T:ty) => {
        fn $func(&mut self, $($v: $IT),*) -> $T {
            self.stack.borrow_mut().$func($($v),*)
        }
    }
}

impl<'a, T> UdpClientStack for SharedStack<'a, T>
where
	T: UdpClientStack,
{
	type Error = T::Error;
	type UdpSocket = T::UdpSocket;

	forward! {socket() -> Result<Self::UdpSocket, Self::Error>}
	forward! {connect(socket: &mut Self::UdpSocket, address: SocketAddr) -> Result<(), Self::Error>}
	forward! {send(socket: &mut Self::UdpSocket, data: &[u8]) -> Result<(), nb::Error<<T as UdpClientStack>::Error>>}
	forward! {receive(socket: &mut Self::UdpSocket, data: &mut [u8]) -> Result<(usize, SocketAddr), nb::Error<<T as UdpClientStack>::Error>>}
	forward! {close(socket: Self::UdpSocket) -> Result<(), Self::Error>}
}

impl<'a, T> UdpFullStack for SharedStack<'a, T>
where
	T: UdpFullStack,
{
	forward! {bind(socket: &mut Self::UdpSocket, local_port: u16) -> Result<(), Self::Error>}
	forward! {send_to(socket: &mut Self::UdpSocket, remote: SocketAddr, buffer: &[u8]) -> Result<(), nb::Error<<T as UdpClientStack>::Error>>}
}

impl<'a, T> TcpClientStack for SharedStack<'a, T>
where
	T: TcpClientStack,
{
	type TcpSocket = T::TcpSocket;
	type Error = T::Error;

	forward! {socket() -> Result<Self::TcpSocket, Self::Error>}
	forward! {connect(socket: &mut Self::TcpSocket, address: SocketAddr) -> Result<(), nb::Error<<T as TcpClientStack>::Error>>}
	forward! {send(socket: &mut Self::TcpSocket, data: &[u8]) -> Result<usize, nb::Error<<T as TcpClientStack>::Error>>}
	forward! {receive(socket: &mut Self::TcpSocket, data: &mut [u8]) -> Result<usize, nb::Error<<T as TcpClientStack>::Error>>}
	forward! {close(socket: Self::TcpSocket) -> Result<(), Self::Error>}
}

impl<'a, T> TcpFullStack for SharedStack<'a, T>
where
	T: TcpFullStack,
{
	forward! {bind(socket: &mut Self::TcpSocket, port: u16) -> Result<(), <T as TcpClientStack>::Error>}
	forward! {listen(socket: &mut Self::TcpSocket) -> Result<(), <T as TcpClientStack>::Error>}
	forward! {accept(socket: &mut Self::TcpSocket) -> Result<(<T as TcpClientStack>::TcpSocket, SocketAddr), nb::Error<<T as TcpClientStack>::Error>>}
}