embedded-nal
embedded-nal copied to clipboard
UDP stack compatible with embassy-net; socket splitting
Addresses #103
As per the subject, this PR contains two changes (I can split into two separate PRs as well, but given that both would be backwards incompatible, and are touching the same traits, perhaps it is better to discuss those in one go):
- The PR introduces lifetimes in the
UdpStack::Connected
,UdpStack::UniquelyBound
andUdpStack::MultiplyBound
associated types, making those GATs- The change is similar and following the lead as to how the the
TcpConnect::Connection
type is modeled already - It is necessary, so that the e-nal-async
UdpStack
trait is implementable inembassy-net
and possibly other non-allocating network stacks using an identical approach to the already implementedTcpConnect
factory trait
- The change is similar and following the lead as to how the the
- The second change in this PR is that it puts an extra requirement on the
UdpSocket
factory trait. Namely, that the sockets it returns should be splittable into two separate halves - "receive" and "send" which can be used concurrently in app protocols that do require full-duplex UDP datagram sending and receiving. This is done by:- Splitting the
ConnectedUdp
andUnconnectedUdp
existing traits into separate "send" and "receive" traits:ConnectedUdpReceive
,ConnectedUdpSend
,UnconnectedUdpReceive
andUnconnectedUdpSend
- similarly as to how theTcpConnect::Connection
associated type is constrained by two separate traits for reading and writing from/to TCP sockets - namely -embedded_io_async::Read
andembedded_io_async::Write
- Introducing two new traits:
ConnectedUdpSplit
andUnconnectedUdpSplit
- which model the notion of a splittable connected/unconnected UDP socket by usingSend/Receive
lifetimed associated types.
- Splitting the
Background on these changes, and justification for introducing UDP socket splitting can be found in #103
Open topics / next steps:
-
As per #103 I think we should come to an agreement that socket splitting is important and necessary.
-
Regardless of the outcome of the above, I think the separation of
ConnectedUdp
andUnconnectedUdp
into "receive" and "send" parts stands on its own. Reason being - if a concrete network stack does allow UDP socket splitting, and even if we decide (regrettably) not to require this in theUdpSocket
factory, app code that does need split UDP sockets would still benefit from the existence of separate "send" and "receive" traits, for the very same reasons we have separateRead
andWrite
traits for TCP / streaming cases - i.e. the app code can take an "already splitted" in a platform-specific way UDP socket in the form of - e.g.async fn foo(send: impl UnconnectedUdpSend, recv: impl UnconnectedUdpReceive)
and then proceed with polling these separately -
(UPDATED) The existing traits' names are mouthful. How about the following simplification:
- Rename:
-
UnconnectedUdpReceive
->UdpReceive
-
UnconnectedUdpSend
->UdpSend
-
UnconnectedUdpSplit
->UdpSplit
- Retire ALL of the
Connected*
traits and use theUnconnected*
ones for the connected case as well. We are anyway already a bit in this situation, by re-using theUnconnected*
traits for "single-bound" sockets, even though the API signatures of the unconnected traits are not a perfect fit there, as they take / return thelocal
socket addr, which serves no useful purpose when the socket is already single-bound to a fixed local IP address.
-
- Rename: