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;