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
#![no_std]
//! Extensions to [embedded_nal]'s TCP traits to make more precise use of TCP buffers.
//!
//! This is not intended to be a long-term extension of embedded-nal,
//! but more an experimenation playground for [#59]
//! where users and implementations can play (ideally behind unstable feature gates);
//! once this is mature it is hoped that it'll be taken up into embedded-nal.
//!
//! [#59]: https://github.com/rust-embedded-community/embedded-nal/issues/59

use embedded_nal::nb;

mod wrappers;
pub use wrappers::*;

/// A specialization of [embedded_nal::TcpClientStack] that allows nonblocking until a given number of bytes can
/// be read, and writing in an all-or-nothing way.
///
/// Stacks that can not provide this can be wrapped in [`BufferedStack::<_, 1152>::new()`] to gain
/// this capability at the cost of per-socket allocated buffers.
///
/// It is an early form of what should resolve
/// <https://github.com/rust-embedded-community/embedded-nal/issues/59>.
pub trait TcpExactStack: embedded_nal::TcpClientStack {
    /// Capacity of the connection's TCP buffer.
    ///
    /// Calls to [`receive_exact()`](TcpExactStack::receive_exact) can ask up to this many
    /// bytes to be returned.
    ///
    /// Checking this (possibly in static assertions) is important because applications that'd wait
    /// for larger chunks of data than the TCP socket can buffer will deadlock -- the application
    /// waits for the server to send more, but the stack tells the server to stop sending more
    /// until the application processes the data.
    ///
    /// (This is a per-stack-type property. Stacks where this is configurable per socket need to
    /// report the smallest value, which is guaranteed to be usable with [`receive_exact()`](TcpExactStack::receive_exact) on every
    /// instance. It is exposed this way to allow users to have suitable const-sized allocations
    /// for the sockets they are built for.)
    const RECVBUFLEN: usize;

    /// Receive data from the stream.
    ///
    /// Returns `Ok(())` if the whole buffer could be filled, or an error. If a packet has not been
    /// received when called, or not enough data is present, then [`nb::Error::WouldBlock`] should
    /// be returned.
    ///
    /// # Panics
    ///
    /// This may panic when buffer is larger than RECVBUFLEN.
    fn receive_exact(
        &mut self,
        socket: &mut Self::TcpSocket,
        buffer: &mut [u8],
    ) -> nb::Result<(), Self::Error>;

    /// Capacity of the connection's TCP send buffer.
    ///
    /// Calls to [`send_All()`](TcpExactStack::send_all) can send up to this many bytes.
    const SENDBUFLEN: usize;

    /// Send all this data to the stream.
    ///
    /// Returns `Ok(())` if the whole buffer could be submitted, or an error. If the data can not
    /// fit into the send buffer when called (especially, but not only, if the send buffer is
    /// full), then [`nb::Error::WouldBlock`'] is returned.
    ///
    /// # Panics
    ///
    /// When the passed slice is larger than the advertised SENDBUFLEN, this may panic -- for the
    /// worse alternative is to return WouldBlock indefinitely, as the message can't be put in the
    /// send buffer no matter how empty it becomes.
    fn send_all(
        &mut self,
        socket: &mut Self::TcpSocket,
        buffer: &[u8],
    ) -> Result<(), embedded_nal::nb::Error<Self::Error>>;
}