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
//! APS Data frame definitions.
use std::num::{NonZero, TryFromIntError};
use bytes::Bytes;
use le_stream::{FromLeStream, ToLeStream};
pub use self::defragmentation::Assembler;
pub use self::fragments::Fragments;
pub use self::header::Header;
pub use self::unicast::Unicast;
mod defragmentation;
mod fragments;
mod header;
mod unicast;
/// An APS Data frame.
#[derive(Clone, Debug, Eq, PartialEq, Hash, ToLeStream)]
pub struct Frame<T> {
header: Header,
payload: T,
}
impl<T> Frame<T> {
/// Creates a new APS Data frame without any validation.
///
/// # Safety
///
/// The caller must ensure that the provided header is consistent with the payload.
#[expect(unsafe_code)]
#[must_use]
pub const unsafe fn new_unchecked(header: Header, payload: T) -> Self {
Self { header, payload }
}
/// Return a reference to the header.
#[must_use]
pub const fn header(&self) -> Header {
self.header
}
/// Return a reference to the payload.
#[must_use]
pub const fn payload(&self) -> &T {
&self.payload
}
/// Drop the extended header.
pub fn drop_extended(&mut self) {
self.header.drop_extended();
}
/// Return the header and payload, consuming the frame.
#[must_use]
pub fn into_parts(self) -> (Header, T) {
(self.header, self.payload)
}
/// Transform the payload while preserving the APS data header.
#[must_use]
pub fn map_payload<U, F>(self, map: F) -> Frame<U>
where
F: FnOnce(T) -> U,
{
Frame {
header: self.header,
payload: map(self.payload),
}
}
}
impl Frame<Bytes> {
/// Return a new frame with the given header and payload.
#[must_use]
pub const fn raw(header: Header, payload: Bytes) -> Self {
Self { header, payload }
}
/// Fragment the frame payload into APS data frames of at most `chunk_size` bytes.
///
/// The returned iterator owns the frame payload and yields frames with extended
/// headers that describe the first and follow-up fragments.
///
/// # Errors
///
/// Returns an error if the number of fragments does not fit into the APS
/// extended header block count field.
///
pub fn fragment(self, chunk_size: NonZero<usize>) -> Result<Fragments, TryFromIntError> {
Fragments::new(self, chunk_size)
}
}
impl Frame<Bytes> {
/// Parse the frame into a frame with typed payload.
///
/// # Errors
///
/// Returns an error if the payload cannot be parsed into the given type.
pub fn parse<T>(self) -> Result<Frame<T>, T::Error>
where
T: TryFrom<Self>,
{
let header = self.header;
T::try_from(self).map(|payload| Frame { header, payload })
}
}
impl<T> FromLeStream for Frame<T>
where
T: FromLeStream,
{
fn from_le_stream<I>(mut bytes: I) -> Option<Self>
where
I: Iterator<Item = u8>,
{
let header = Header::from_le_stream(&mut bytes)?;
let payload = T::from_le_stream(&mut bytes)?;
Some(Self { header, payload })
}
}