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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! `toad` is a Rust CoAP implementation that aims to be:
//! - Platform-independent
//! - Extensible
//! - Approachable
//!
//! ## CoAP
//! CoAP is an application-level network protocol that copies the semantics of HTTP
//! to an environment conducive to **constrained** devices. (weak hardware, small battery capacity, etc.)
//!
//! This means that you can write and run two-way RESTful communication
//! between devices very similarly to the networking semantics you are
//! most likely very familiar with.
//!
//! ### Similarities to HTTP
//! CoAP has the same verbs and many of the same semantics as HTTP;
//! - GET, POST, PUT, DELETE
//! - Headers (renamed to [Options](https://datatracker.ietf.org/doc/html/rfc7252#section-5.10))
//! - Data format independent (via the [Content-Format](https://datatracker.ietf.org/doc/html/rfc7252#section-12.3) Option)
//! - [Response status codes](https://datatracker.ietf.org/doc/html/rfc7252#section-5.9)
//!
//! ### Differences from HTTP
//! - CoAP customarily sits on top of UDP (however the standard is [in the process of being adapted](https://tools.ietf.org/id/draft-ietf-core-coap-tcp-tls-11.html) to also run on TCP, like HTTP)
//! - Because UDP is a "connectionless" protocol, it offers no guarantee of "conversation" between traditional client and server roles. All the UDP transport layer gives you is a method to listen for messages thrown at you, and to throw messages at someone. Owing to this, CoAP machines are expected to perform both client and server roles (or more accurately, _sender_ and _receiver_ roles)
//! - While _classes_ of status codes are the same (Success 2xx -> 2.xx, Client error 4xx -> 4.xx, Server error 5xx -> 5.xx), the semantics of the individual response codes differ.

// x-release-please-start-version
#![doc(html_root_url = "https://docs.rs/toad/0.19.1")]
// x-release-please-end
#![cfg_attr(any(docsrs, feature = "docs"), feature(doc_cfg))]
// -
// style
#![allow(clippy::unused_unit)]
// -
// deny
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(missing_copy_implementations)]
#![cfg_attr(not(test), deny(unsafe_code))]
// -
// warnings
#![cfg_attr(not(test), warn(unreachable_pub))]
// -
// features
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(feature = "alloc")]
extern crate alloc as std_alloc;

#[doc(hidden)]
pub mod todo;

#[cfg(test)]
pub(crate) mod test;

/// customizable retrying of fallible operations
pub mod retry;

/// responses
pub mod resp;

/// requests
pub mod req;

/// # The [`Step`](crate::step::Step) trait
/// The Step trait defines a powerful but simple API that allows
/// the CoAP runtime to be a composition of "steps," stored as a
/// type-level linked list.
///
/// e.g.
/// ```text
/// Gather Ingredients
///   -> Mix Wet Ingredients
///   -> Mix Dry Ingredients
///   -> Mix Everything together
///   -> Pour into cake tin
///   -> Bake
/// ```
/// as Steps:
/// ```text
/// Bake<PourIntoCakeTin<MixEverything<MixDry<MixWet<GatherIngredients<Empty>>>>>>
/// ```
///
/// ## Capabilities
///  * May read system state (time, dgram on the socket, platform configuration)
///     * [`platform::Snapshot`]
///  * May maintain internal state
///     * Must be managed with interior mutability (e.g. [`RwLock`](::std::sync::RwLock))
///  * May perform side effects
///     * [`platform::Effect`] provides deterministic API for logging and sending bytes over the wire
///  * May participate in client role, server role, or both roles in the CoAP runtime
///     * [`step::Step::poll_req`] (server)
///     * [`step::Step::poll_resp`] (client)
///  * May modify messages before they are sent
///     * [`step::Step::before_message_sent`]
///  * May be notified whenever a message is sent
///     * [`step::Step::on_message_sent`]
///  * May yield data to the outer step
///     * [`step::Step::PollReq`]
///     * [`step::Step::PollResp`]
///
/// ## Determinism
/// Steps provided by this crate will never perform any observable IO,
/// aside from managing their own internal state and appending to the list of
/// effects provided in the `poll_req`/`poll_resp` fns.
///
/// ## Logging
/// Steps provided by this crate will never log to any streams directly,
/// and will provide them via [`platform::Effect::Log`].
///
/// It is **strongly** recommended that [`log::Level::Warn`] and
/// [`log::Level::Error`] messages are not ignored.
pub mod step;

/// platform configuration
pub mod platform;

/// network abstractions
pub mod net;

/// time abstractions
pub mod time;

/// configuring runtime behavior
pub mod config;

/// `std`-only toad stuff
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub mod std;

mod option;

/// Server functionality
pub mod server;

pub use option::{ContentFormat, ToCoapValue};

/// Helper constants and functions for creating multicast addresses
pub mod multicast {
  use no_std_net::{Ipv4Addr, SocketAddr, SocketAddrV4};

  /// IPv4 "All CoAP devices" multicast address.
  ///
  /// If using multicast to discover devices, it's recommended
  /// that you use this address with a port specific to your application.
  pub const ALL_COAP_DEVICES_IP: Ipv4Addr = Ipv4Addr::new(224, 0, 1, 187);

  /// Create a SocketAddr (IP + port) with the [`ALL_COAP_DEVICES_IP`] address
  ///
  /// If using multicast to discover devices, it's recommended
  /// that you use this address with a port specific to your application.
  pub const fn all_coap_devices(port: u16) -> SocketAddr {
    SocketAddr::V4(SocketAddrV4::new(ALL_COAP_DEVICES_IP, port))
  }
}

macro_rules! code {
  (rfc7252($section:literal) $name:ident = $c:literal.$d:literal) => {
    #[doc = toad_macros::rfc_7252_doc!($section)]
    #[allow(clippy::zero_prefixed_literal)]
    pub const $name: toad_msg::Code = toad_msg::Code::new($c, $d);
  };
  (rfc7252($section:literal) $name:ident = $newtype:tt($c:literal.$d:literal)) => {
    #[doc = toad_macros::rfc_7252_doc!($section)]
    #[allow(clippy::zero_prefixed_literal)]
    pub const $name: $newtype = $newtype(toad_msg::Code::new($c, $d));
  };
}

pub(crate) use code;