octseq/
octets.rs

1//! Octets Sequences
2//!
3//! An octets sequence – or just octets for short – is a variable length
4//! sequence of bytes. In their most simple form, any type that implements
5//! `AsRef<[u8]>` can serve as octets. However, in some cases additional
6//! functionality is required.
7//!
8//! The trait [`Octets`] allows taking a sub-sequence, called a ‘range’, out
9//! of the octets in the cheapest way possible. For most types, ranges will
10//! be octet slices `&[u8]` but some shareable types (most notably
11//! `bytes::Bytes`) allow ranges to be owned values, thus avoiding the
12//! lifetime limitations a slice would bring. Therefore, `Octets` allows
13//! defining the type of a range as an associated type.
14
15use core::convert::Infallible;
16use core::ops::{Index, RangeBounds};
17#[cfg(feature = "bytes")] use bytes::{Bytes, BytesMut};
18#[cfg(feature = "std")] use std::borrow::Cow;
19#[cfg(feature = "std")] use std::vec::Vec;
20use crate::builder::ShortBuf;
21
22
23//------------ Octets --------------------------------------------------------
24
25/// A type representing an octets sequence.
26///
27/// The primary purpose of the trait is to allow access to a sub-sequence,
28/// called a ‘range.’ The type of this range is given via the `Range`
29/// associated type. For most types it will be a `&[u8]` with a lifetime
30/// equal to that of a reference. Only if an owned range can be created
31/// cheaply, it should be that type.
32pub trait Octets: AsRef<[u8]> {
33    type Range<'a>: Octets where Self: 'a;
34
35    /// Returns a sub-sequence or ‘range’ of the sequence.
36    ///
37    /// # Panics
38    ///
39    /// The method should panic if `start` or `end` are greater than the
40    /// length of the octets sequence or if `start` is greater than `end`.
41    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_>;
42}
43
44impl<'t, T: Octets + ?Sized> Octets for &'t T {
45    type Range<'a> = <T as Octets>::Range<'t> where Self: 'a;
46
47    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_> {
48        (*self).range(range)
49    }
50}
51
52impl Octets for [u8] {
53    type Range<'a> = &'a [u8];
54
55    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_> {
56        self.index(
57            (range.start_bound().cloned(), range.end_bound().cloned())
58        )
59    }
60}
61
62#[cfg(feature = "std")]
63impl<'c> Octets for Cow<'c, [u8]> {
64    type Range<'a> = &'a [u8] where Self: 'a;
65
66    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_> {
67        self.as_ref().range(range)
68    }
69}
70
71#[cfg(feature = "std")]
72impl Octets for Vec<u8> {
73    type Range<'a> = &'a [u8];
74
75    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_> {
76        self.as_slice().range(range)
77    }
78}
79
80#[cfg(feature = "std")]
81impl Octets for std::sync::Arc<[u8]> {
82    type Range<'a> = &'a [u8];
83
84    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_> {
85        self.as_ref().range(range)
86    }
87}
88
89#[cfg(feature = "bytes")]
90impl Octets for Bytes {
91    type Range<'a> = Bytes;
92
93    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_> {
94        self.slice(range)
95    }
96}
97
98#[cfg(feature = "smallvec")]
99impl<A: smallvec::Array<Item = u8>> Octets for smallvec::SmallVec<A> {
100    type Range<'a> = &'a [u8] where A: 'a;
101
102    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_> {
103        self.as_slice().range(range)
104    }
105}
106
107#[cfg(feature = "heapless")]
108impl<const N: usize> Octets for heapless::Vec<u8, N> {
109    type Range<'a> = &'a [u8] where Self: 'a;
110
111    fn range(&self, range: impl RangeBounds<usize>) -> Self::Range<'_> {
112        self.index(
113            (range.start_bound().cloned(), range.end_bound().cloned())
114        )
115    }
116}
117
118
119//------------ OctetsFrom ----------------------------------------------------
120
121/// Convert a type from one octets type to another.
122///
123/// This trait allows creating a value of a type that is generic over an
124/// octets sequence from an identical value using a different type of octets
125/// sequence.
126///
127/// This is different from just `From` in that the conversion may fail if the
128/// source sequence is longer than the space available for the target type.
129pub trait OctetsFrom<Source>: Sized {
130    type Error: Into<ShortBuf>;
131
132    /// Performs the conversion.
133    fn try_octets_from(source: Source) -> Result<Self, Self::Error>;
134
135    /// Performs an infallible conversion.
136    fn octets_from(source: Source) -> Self
137    where Self::Error: Into<Infallible> {
138        // XXX Use .into_ok() once that is stable.
139        match Self::try_octets_from(source) {
140            Ok(ok) => ok,
141            Err(_) => unreachable!()
142        }
143    }
144}
145
146impl<'a, Source: AsRef<[u8]> + 'a> OctetsFrom<&'a Source> for &'a [u8] {
147    type Error = Infallible;
148
149    fn try_octets_from(source: &'a Source) -> Result<Self, Self::Error> {
150        Ok(source.as_ref())
151    }
152}
153
154#[cfg(feature = "std")]
155impl<Source> OctetsFrom<Source> for Vec<u8>
156where
157    Self: From<Source>,
158{
159    type Error = Infallible;
160
161    fn try_octets_from(source: Source) -> Result<Self, Self::Error> {
162        Ok(From::from(source))
163    }
164}
165
166#[cfg(feature = "bytes")]
167impl<Source> OctetsFrom<Source> for Bytes
168where
169    Self: From<Source>,
170{
171    type Error = Infallible;
172
173    fn try_octets_from(source: Source) -> Result<Self, Self::Error> {
174        Ok(From::from(source))
175    }
176}
177
178#[cfg(feature = "bytes")]
179impl<Source> OctetsFrom<Source> for BytesMut
180where
181    Self: From<Source>,
182{
183    type Error = Infallible;
184
185    fn try_octets_from(source: Source) -> Result<Self, Self::Error> {
186        Ok(From::from(source))
187    }
188}
189
190#[cfg(features = "smallvec")]
191impl<Source, A> OctetsFrom<Source> for smallvec::SmallVec<A>
192where
193    Source: AsRef<u8>,
194    A: Array<Item = u8>,
195{
196    type Error = Infallible;
197
198    fn try_octets_from(source: Source) -> Result<Self, Self::Infallible> {
199        Ok(smallvec::ToSmallVec::to_smallvec(source.as_ref()))
200    }
201}
202
203#[cfg(feature = "heapless")]
204impl<Source, const N: usize> OctetsFrom<Source> for heapless::Vec<u8, N>
205where
206    Source: AsRef<[u8]>,
207{
208    type Error = ShortBuf;
209
210    fn try_octets_from(source: Source) -> Result<Self, ShortBuf> {
211        heapless::Vec::from_slice(source.as_ref()).map_err(|_| ShortBuf)
212    }
213}
214
215
216//------------ OctetsInto ----------------------------------------------------
217
218/// Convert a type from one octets type to another.
219///
220/// This trait allows trading in a value of a type that is generic over an
221/// octets sequence for an identical value using a different type of octets
222/// sequence.
223///
224/// This is different from just `Into` in that the conversion may fail if the
225/// source sequence is longer than the space available for the target type.
226///
227/// This trait has a blanket implementation for all pairs of types where
228/// `OctetsFrom` has been implemented.
229pub trait OctetsInto<Target>: Sized {
230    type Error: Into<ShortBuf>;
231
232    /// Performs the conversion.
233    fn try_octets_into(self) -> Result<Target, Self::Error>;
234
235    /// Performs an infallible conversion.
236    fn octets_into(self) -> Target
237    where Self::Error: Into<Infallible> {
238        match self.try_octets_into() {
239            Ok(ok) => ok,
240            Err(_) => unreachable!()
241        }
242    }
243}
244
245impl<Source, Target: OctetsFrom<Source>> OctetsInto<Target> for Source {
246    type Error = <Target as OctetsFrom<Source>>::Error;
247
248    fn try_octets_into(self) -> Result<Target, Self::Error> {
249        Target::try_octets_from(self)
250    }
251}
252
253
254//------------ SmallOctets ---------------------------------------------------
255
256/// A octets vector that doesn’t allocate for small sizes.
257#[cfg(feature = "smallvec")]
258pub type SmallOctets = smallvec::SmallVec<[u8; 24]>;
259