Skip to main content

oxirush_aper/
octets.rs

1//! Octets that are borrowed from what was decoded, or owned.
2
3use alloc::borrow::Cow;
4use alloc::vec::Vec;
5use core::fmt;
6use core::ops::Deref;
7
8/// The octets of an OCTET STRING or of an open type: borrowed from the octets that
9/// they were decoded from, or owned.
10///
11/// A decoder borrows: the NAS-PDU of a message is a slice of the PDU, and reading it
12/// allocates nothing. A value that is built owns its octets, or borrows them from the
13/// caller. [`into_owned`](Self::into_owned) makes a value that borrows nothing, which
14/// is kept after the octets that it was decoded from are gone.
15///
16/// ```
17/// use oxirush_aper::Octets;
18///
19/// // Borrowed, and owned
20/// let received = [0x7e, 0x00, 0x41];
21/// let borrowed = Octets::from(&received[..]);
22/// let owned = Octets::from(vec![0x7e, 0x00, 0x41]);
23/// assert_eq!(borrowed, owned);
24///
25/// // It reads as a slice
26/// assert_eq!(borrowed.len(), 3);
27/// assert_eq!(borrowed[0], 0x7e);
28/// assert_eq!(borrowed, [0x7e, 0x00, 0x41]);
29///
30/// // Kept after `received` is gone
31/// let kept: Octets<'static> = borrowed.into_owned();
32/// assert_eq!(format!("{kept:?}"), "7e0041");
33/// ```
34#[derive(Clone, Default)]
35pub struct Octets<'a>(Cow<'a, [u8]>);
36
37impl<'a> Octets<'a> {
38    /// No octet.
39    pub const EMPTY: Self = Self(Cow::Borrowed(&[]));
40
41    /// Octets that are borrowed.
42    pub const fn borrowed(octets: &'a [u8]) -> Self {
43        Self(Cow::Borrowed(octets))
44    }
45
46    /// Octets that are owned.
47    pub const fn owned(octets: Vec<u8>) -> Octets<'static> {
48        Octets(Cow::Owned(octets))
49    }
50
51    /// The octets.
52    pub fn as_slice(&self) -> &[u8] {
53        &self.0
54    }
55
56    /// Whether the octets are borrowed.
57    pub fn is_borrowed(&self) -> bool {
58        matches!(self.0, Cow::Borrowed(_))
59    }
60
61    /// The octets for as long as what they are borrowed from, when they are borrowed:
62    /// the slice outlives this value.
63    pub fn as_borrowed(&self) -> Option<&'a [u8]> {
64        match self.0 {
65            Cow::Borrowed(octets) => Some(octets),
66            Cow::Owned(_) => None,
67        }
68    }
69
70    /// The same octets, owned and kept as long as they are needed: `Octets<'static>`
71    /// is the type to write in a struct. They are copied when they were borrowed.
72    #[doc(alias("to_owned", "owned", "keep"))]
73    pub fn into_owned(self) -> Octets<'static> {
74        Octets(Cow::Owned(self.0.into_owned()))
75    }
76
77    /// The octets as a vector: they are copied when they were borrowed.
78    pub fn into_vec(self) -> Vec<u8> {
79        self.0.into_owned()
80    }
81
82    /// The octets, to change them: they are copied first when they were borrowed.
83    pub fn to_mut(&mut self) -> &mut Vec<u8> {
84        self.0.to_mut()
85    }
86}
87
88impl Deref for Octets<'_> {
89    type Target = [u8];
90
91    fn deref(&self) -> &[u8] {
92        &self.0
93    }
94}
95
96impl AsRef<[u8]> for Octets<'_> {
97    fn as_ref(&self) -> &[u8] {
98        &self.0
99    }
100}
101
102impl<'a> From<&'a [u8]> for Octets<'a> {
103    fn from(octets: &'a [u8]) -> Self {
104        Self(Cow::Borrowed(octets))
105    }
106}
107
108impl<'a, const N: usize> From<&'a [u8; N]> for Octets<'a> {
109    fn from(octets: &'a [u8; N]) -> Self {
110        Self(Cow::Borrowed(octets))
111    }
112}
113
114impl<'a> From<&'a Vec<u8>> for Octets<'a> {
115    fn from(octets: &'a Vec<u8>) -> Self {
116        Self(Cow::Borrowed(octets))
117    }
118}
119
120impl From<Vec<u8>> for Octets<'_> {
121    fn from(octets: Vec<u8>) -> Self {
122        Self(Cow::Owned(octets))
123    }
124}
125
126impl<const N: usize> From<[u8; N]> for Octets<'_> {
127    fn from(octets: [u8; N]) -> Self {
128        Self(Cow::Owned(octets.to_vec()))
129    }
130}
131
132impl<'a> From<Cow<'a, [u8]>> for Octets<'a> {
133    fn from(octets: Cow<'a, [u8]>) -> Self {
134        Self(octets)
135    }
136}
137
138impl<'a> From<Octets<'a>> for Vec<u8> {
139    fn from(octets: Octets<'a>) -> Self {
140        octets.into_vec()
141    }
142}
143
144impl PartialEq for Octets<'_> {
145    fn eq(&self, other: &Self) -> bool {
146        self.as_slice() == other.as_slice()
147    }
148}
149
150impl Eq for Octets<'_> {}
151
152impl PartialOrd for Octets<'_> {
153    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
154        Some(self.cmp(other))
155    }
156}
157
158impl Ord for Octets<'_> {
159    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
160        self.as_slice().cmp(other.as_slice())
161    }
162}
163
164impl core::hash::Hash for Octets<'_> {
165    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
166        self.as_slice().hash(state);
167    }
168}
169
170impl PartialEq<[u8]> for Octets<'_> {
171    fn eq(&self, other: &[u8]) -> bool {
172        self.as_slice() == other
173    }
174}
175
176impl PartialEq<&[u8]> for Octets<'_> {
177    fn eq(&self, other: &&[u8]) -> bool {
178        self.as_slice() == *other
179    }
180}
181
182impl PartialEq<Vec<u8>> for Octets<'_> {
183    fn eq(&self, other: &Vec<u8>) -> bool {
184        self.as_slice() == other.as_slice()
185    }
186}
187
188impl<const N: usize> PartialEq<[u8; N]> for Octets<'_> {
189    fn eq(&self, other: &[u8; N]) -> bool {
190        self.as_slice() == other
191    }
192}
193
194impl PartialEq<Octets<'_>> for [u8] {
195    fn eq(&self, other: &Octets<'_>) -> bool {
196        self == other.as_slice()
197    }
198}
199
200impl PartialEq<Octets<'_>> for Vec<u8> {
201    fn eq(&self, other: &Octets<'_>) -> bool {
202        self.as_slice() == other.as_slice()
203    }
204}
205
206/// As a type of its own, octets are an OCTET STRING without a size constraint.
207impl crate::AsnType for Octets<'_> {
208    const NAME: &'static str = "OCTET STRING";
209}
210
211impl<'a> crate::Decode<'a> for Octets<'a> {
212    fn decode(reader: &mut crate::Reader<'a>) -> Result<Self, crate::Error> {
213        reader.octet_string(0, crate::UNBOUNDED)
214    }
215}
216
217impl crate::Encode for Octets<'_> {
218    fn encode(&self, writer: &mut crate::Writer<'_>) -> Result<(), crate::Error> {
219        writer.octet_string(self, 0, crate::UNBOUNDED)
220    }
221}
222
223#[cfg(feature = "inspect")]
224impl crate::json::Tree for Octets<'_> {
225    const NAME: &'static str = "OCTET STRING";
226
227    fn to_tree(&self) -> crate::json::Value {
228        crate::json::octets(self)
229    }
230
231    fn from_tree(
232        value: &crate::json::Value,
233        reading: &mut crate::json::Reading,
234    ) -> Result<Self, crate::json::Refused> {
235        crate::json::read_octets(reading, value)
236    }
237}
238
239/// The octets in hexadecimal, in lower case.
240impl fmt::Debug for Octets<'_> {
241    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
242        write_hex(self.as_slice(), formatter)
243    }
244}
245
246/// Octets in hexadecimal, in lower case.
247pub(crate) fn write_hex(octets: &[u8], formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
248    for octet in octets {
249        write!(formatter, "{octet:02x}")?;
250    }
251    Ok(())
252}
253
254#[cfg(test)]
255mod tests {
256    use super::*;
257    use alloc::format;
258    use alloc::vec;
259
260    #[test]
261    fn octets_are_borrowed_or_owned_and_compare_by_what_they_hold() {
262        let received = vec![1u8, 2, 3];
263        let borrowed = Octets::from(&received);
264        assert!(borrowed.is_borrowed());
265        let owned = Octets::from(vec![1u8, 2, 3]);
266        assert!(!owned.is_borrowed());
267        assert_eq!(borrowed, owned);
268        assert_eq!(borrowed, [1, 2, 3]);
269        assert_eq!(borrowed, vec![1, 2, 3]);
270        assert_eq!(borrowed, &[1u8, 2, 3][..]);
271        assert_eq!(received, borrowed);
272        let (less, more) = (Octets::from([1u8, 2]), Octets::from([1u8, 3]));
273        assert!(less < more);
274        assert_eq!(Octets::EMPTY.len(), 0);
275        assert_eq!(Octets::default(), Octets::EMPTY);
276
277        let kept: Octets<'static> = borrowed.clone().into_owned();
278        assert!(!kept.is_borrowed());
279        assert_eq!(kept.clone().into_vec(), [1, 2, 3]);
280        assert_eq!(Vec::from(kept), [1, 2, 3]);
281
282        let mut changed = borrowed;
283        changed.to_mut().push(4);
284        assert_eq!(changed, [1, 2, 3, 4]);
285        assert_eq!(format!("{changed:?}"), "01020304");
286    }
287}