octseq/
builder.rs

1//! Octets Builders
2//!
3//! Octets builders, i.e., anything that implements the [`OctetsBuilder`]
4//! trait, represent a buffer to which octets can be appended.
5//! Whether the buffer can grow to accommodate appended data depends on the
6//! underlying type.
7//!
8//! The [`OctetsBuilder`] trait only provides methods to append data to the
9//! builder. Implementations may, however, provide more functionality. They
10//! do so by implementing additional traits. Conversely, if additional
11//! functionality is needed from a builder, this can be expressed by
12//! adding trait bounds.
13//!
14//! Some examples are:
15//!
16//! * creating an empty octets builder from scratch is provided by the
17//!   [`EmptyBuilder`] trait,
18//! * looking at already assembled octets is done via `AsRef<[u8]>`,
19//! * manipulation of already assembled octets requires `AsMut<[u8]>`, and
20//! * truncating the sequence of assembled octets happens through
21//!   [`Truncate`].
22
23use core::fmt;
24use core::convert::Infallible;
25#[cfg(feature = "bytes")] use bytes::{Bytes, BytesMut};
26#[cfg(feature = "std")] use std::borrow::Cow;
27#[cfg(feature = "std")] use std::vec::Vec;
28
29
30//------------ OctetsBuilder -------------------------------------------------
31
32/// A buffer to construct an octet sequence.
33///
34/// Octet builders represent a buffer of space available for building an
35/// octets sequence by appending the contents of octet slices. The buffers
36/// may consist of a predefined amount of space or grow as needed.
37///
38/// Octet builders provide access to the already assembled data through
39/// octet slices via their implementations of `AsRef<[u8]>` and
40/// `AsMut<[u8]>`.
41pub trait OctetsBuilder {
42    /// The error type when appending data fails.
43    ///
44    /// There are exactly two options for this type: Builders where appending
45    /// never fails use `Infallible`. Builders with a limited buffer which 
46    /// may have insufficient space for appending use [`ShortBuf`].
47    ///
48    /// The trait bound on the type allows upgrading the error to [`ShortBuf`]
49    /// even for builders with unlimited space. This way, an error type for
50    /// operations that use a builder doesn’t need to be generic over the
51    /// append error type and can simply use a variant for anything
52    /// `Into<ShortBuf>` instead.
53    type AppendError: Into<ShortBuf>;
54
55    /// Appends the content of a slice to the builder.
56    ///
57    /// If there isn’t enough space available for appending the slice,
58    /// returns an error and leaves the builder alone.
59    fn append_slice(
60        &mut self, slice: &[u8]
61    ) -> Result<(), Self::AppendError>;
62}
63
64impl<'a, T: OctetsBuilder> OctetsBuilder for &'a mut T {
65    type AppendError = T::AppendError;
66
67    fn append_slice(
68        &mut self, slice: &[u8]
69    ) -> Result<(), Self::AppendError> {
70        (*self).append_slice(slice)
71    }
72}
73
74#[cfg(feature = "std")]
75impl OctetsBuilder for Vec<u8> {
76    type AppendError = Infallible;
77
78    fn append_slice(
79        &mut self, slice: &[u8]
80    ) -> Result<(), Self::AppendError> {
81        self.extend_from_slice(slice);
82        Ok(())
83    }
84}
85
86#[cfg(feature = "std")]
87impl<'a> OctetsBuilder for Cow<'a, [u8]> {
88    type AppendError = Infallible;
89
90    fn append_slice(
91        &mut self, slice: &[u8]
92    ) -> Result<(), Self::AppendError> {
93        if let Cow::Owned(ref mut vec) = *self {
94            vec.extend_from_slice(slice);
95        } else {
96            let mut vec = std::mem::replace(
97                self, Cow::Borrowed(b"")
98            ).into_owned();
99            vec.extend_from_slice(slice);
100            *self = Cow::Owned(vec);
101        }
102        Ok(())
103    }
104}
105
106#[cfg(feature = "bytes")]
107impl OctetsBuilder for BytesMut {
108    type AppendError = Infallible;
109
110    fn append_slice(
111        &mut self, slice: &[u8]
112    ) -> Result<(), Self::AppendError> {
113        self.extend_from_slice(slice);
114        Ok(())
115    }
116}
117
118#[cfg(feature = "smallvec")]
119impl<A: smallvec::Array<Item = u8>> OctetsBuilder for smallvec::SmallVec<A> {
120    type AppendError = Infallible;
121
122    fn append_slice(
123        &mut self, slice: &[u8]
124    ) -> Result<(), Self::AppendError> {
125        self.extend_from_slice(slice);
126        Ok(())
127    }
128}
129
130#[cfg(feature = "heapless")]
131impl<const N: usize> OctetsBuilder for heapless::Vec<u8, N> {
132    type AppendError = ShortBuf;
133
134    fn append_slice(
135        &mut self, slice: &[u8]
136    ) -> Result<(), Self::AppendError> {
137        self.extend_from_slice(slice).map_err(|_| ShortBuf)
138    }
139}
140
141
142//------------ Truncate ------------------------------------------------------
143
144/// An octet sequence that can be shortened.
145pub trait Truncate {
146    /// Truncate the sequence to `len` octets.
147    ///
148    /// If `len` is larger than the length of the sequence, nothing happens.
149    fn truncate(&mut self, len: usize);
150}
151
152impl<'a, T: Truncate> Truncate for &'a mut T {
153    fn truncate(&mut self, len: usize) {
154        (*self).truncate(len)
155    }
156}
157
158impl<'a> Truncate for &'a [u8] {
159    fn truncate(&mut self, len: usize) {
160        if len < self.len() {
161            *self = &self[..len]
162        }
163    }
164}
165
166#[cfg(feature = "std")]
167impl<'a> Truncate for Cow<'a, [u8]> {
168    fn truncate(&mut self, len: usize) {
169        match *self {
170            Cow::Borrowed(ref mut slice) => *slice = &slice[..len],
171            Cow::Owned(ref mut vec) => vec.truncate(len),
172        }
173    }
174}
175
176#[cfg(feature = "std")]
177impl Truncate for Vec<u8> {
178    fn truncate(&mut self, len: usize) {
179        self.truncate(len)
180    }
181}
182
183#[cfg(feature = "bytes")]
184impl Truncate for Bytes {
185    fn truncate(&mut self, len: usize) {
186        self.truncate(len)
187    }
188}
189
190#[cfg(feature = "bytes")]
191impl Truncate for BytesMut {
192    fn truncate(&mut self, len: usize) {
193        self.truncate(len)
194    }
195}
196
197#[cfg(feature = "smallvec")]
198impl<A: smallvec::Array<Item = u8>> Truncate for smallvec::SmallVec<A> {
199    fn truncate(&mut self, len: usize) {
200        self.truncate(len)
201    }
202}
203
204#[cfg(feature = "heapless")]
205impl<const N: usize> Truncate for heapless::Vec<u8, N> {
206    fn truncate(&mut self, len: usize) {
207        self.truncate(len)
208    }
209}
210
211
212//------------ EmptyBuilder --------------------------------------------------
213
214/// An octets builder that can be newly created empty.
215pub trait EmptyBuilder {
216    /// Creates a new empty octets builder with a default size.
217    fn empty() -> Self;
218
219    /// Creates a new empty octets builder with a suggested initial size.
220    ///
221    /// The builder may or may not use the size provided by `capacity` as the
222    /// initial size of the buffer. It may very well be possible that the
223    /// builder is never able to grow to this capacity at all. Therefore,
224    /// even if you create a builder for your data size via this function,
225    /// appending may still fail.
226    fn with_capacity(capacity: usize) -> Self;
227}
228
229#[cfg(feature = "std")]
230impl EmptyBuilder for Vec<u8> {
231    fn empty() -> Self {
232        Vec::new()
233    }
234
235    fn with_capacity(capacity: usize) -> Self {
236        Vec::with_capacity(capacity)
237    }
238}
239
240#[cfg(feature = "bytes")]
241impl EmptyBuilder for BytesMut {
242    fn empty() -> Self {
243        BytesMut::new()
244    }
245
246    fn with_capacity(capacity: usize) -> Self {
247        BytesMut::with_capacity(capacity)
248    }
249}
250
251#[cfg(feature = "smallvec")]
252impl<A: smallvec::Array<Item = u8>> EmptyBuilder for smallvec::SmallVec<A> {
253    fn empty() -> Self {
254        smallvec::SmallVec::new()
255    }
256
257    fn with_capacity(capacity: usize) -> Self {
258        smallvec::SmallVec::with_capacity(capacity)
259    }
260}
261
262#[cfg(feature = "heapless")]
263impl<const N: usize> EmptyBuilder for heapless::Vec<u8, N> {
264    fn empty() -> Self {
265        Self::new()
266    }
267
268    fn with_capacity(capacity: usize) -> Self {
269        debug_assert!(capacity <= N);
270        // Ignore the capacity because that's determined by the type
271        heapless::Vec::new()
272    }
273}
274
275
276//------------ FreezeBuilder -------------------------------------------------
277
278/// An octets builder that can be frozen into a immutable octets sequence.
279pub trait FreezeBuilder {
280    /// The type of octets sequence to builder will be frozen into.
281    type Octets;
282
283    /// Converts the octets builder into an immutable octets sequence.
284    fn freeze(self) -> Self::Octets;
285}
286
287#[cfg(feature = "std")]
288impl FreezeBuilder for Vec<u8> {
289    type Octets = Self;
290
291    fn freeze(self) -> Self::Octets {
292        self
293    }
294}
295
296#[cfg(feature = "std")]
297impl<'a> FreezeBuilder for Cow<'a, [u8]> {
298    type Octets = Self;
299
300    fn freeze(self) -> Self::Octets {
301        self
302    }
303}
304
305#[cfg(feature = "bytes")]
306impl FreezeBuilder for BytesMut {
307    type Octets = Bytes;
308
309    fn freeze(self) -> Self::Octets {
310        BytesMut::freeze(self)
311    }
312}
313
314#[cfg(feature = "smallvec")]
315impl<A: smallvec::Array<Item = u8>> FreezeBuilder for smallvec::SmallVec<A> {
316    type Octets = Self;
317
318    fn freeze(self) -> Self::Octets {
319        self
320    }
321}
322
323#[cfg(feature = "heapless")]
324impl<const N: usize> FreezeBuilder for heapless::Vec<u8, N> {
325    type Octets = Self;
326
327    fn freeze(self) -> Self::Octets {
328        self
329    }
330}
331
332
333//------------ IntoBuilder ---------------------------------------------------
334
335/// An octets type that can be converted into an octets builder.
336pub trait IntoBuilder {
337    /// The type of octets builder this octets type can be converted into.
338    type Builder: OctetsBuilder;
339
340    /// Converts an octets value into an octets builder.
341    fn into_builder(self) -> Self::Builder;
342}
343
344#[cfg(feature = "std")]
345impl IntoBuilder for Vec<u8> {
346    type Builder = Self;
347
348    fn into_builder(self) -> Self::Builder {
349        self
350    }
351}
352
353#[cfg(feature = "std")]
354impl<'a> IntoBuilder for &'a [u8] {
355    type Builder = Vec<u8>;
356
357    fn into_builder(self) -> Self::Builder {
358        self.into()
359    }
360}
361
362#[cfg(feature = "std")]
363impl<'a> IntoBuilder for Cow<'a, [u8]> {
364    type Builder = Self;
365
366    fn into_builder(self) -> Self::Builder {
367        self
368    }
369}
370
371#[cfg(feature = "bytes")]
372impl IntoBuilder for Bytes {
373    type Builder = BytesMut;
374
375    fn into_builder(self) -> Self::Builder {
376        // XXX Currently, we need to copy to do this. If bytes gains a way
377        //     to convert from Bytes to BytesMut for non-shared data without
378        //     copying, we should change this.
379        BytesMut::from(self.as_ref())
380    }
381}
382
383#[cfg(feature = "smallvec")]
384impl<A: smallvec::Array<Item = u8>> IntoBuilder for smallvec::SmallVec<A> {
385    type Builder = Self;
386
387    fn into_builder(self) -> Self::Builder {
388        self
389    }
390}
391
392#[cfg(feature = "heapless")]
393impl<const N: usize> IntoBuilder for heapless::Vec<u8, N> {
394    type Builder = Self;
395
396    fn into_builder(self) -> Self::Builder {
397        self
398    }
399}
400
401
402//------------ FromBuilder ---------------------------------------------------
403
404/// An octets type that can be created from an octets builder.
405pub trait FromBuilder: AsRef<[u8]> + Sized {
406    /// The type of builder this octets type can be created from.
407    type Builder: OctetsBuilder + FreezeBuilder<Octets = Self>;
408
409    /// Creates an octets value from an octets builder.
410    fn from_builder(builder: Self::Builder) -> Self;
411}
412
413#[cfg(feature = "std")]
414impl FromBuilder for Vec<u8> {
415    type Builder = Self;
416
417    fn from_builder(builder: Self::Builder) -> Self {
418        builder
419    }
420}
421
422#[cfg(feature = "std")]
423impl<'a> FromBuilder for Cow<'a, [u8]> {
424    type Builder = Self;
425
426    fn from_builder(builder: Self::Builder) -> Self {
427        builder
428    }
429}
430
431#[cfg(feature = "bytes")]
432impl FromBuilder for Bytes {
433    type Builder = BytesMut;
434
435    fn from_builder(builder: Self::Builder) -> Self {
436        builder.freeze()
437    }
438}
439
440#[cfg(feature = "smallvec")]
441impl<A: smallvec::Array<Item = u8>> FromBuilder for smallvec::SmallVec<A> {
442    type Builder = Self;
443
444    fn from_builder(builder: Self::Builder) -> Self {
445        builder
446    }
447}
448
449#[cfg(feature = "heapless")]
450impl<const N: usize> FromBuilder for heapless::Vec<u8, N> {
451    type Builder = Self;
452
453    fn from_builder(builder: Self::Builder) -> Self {
454        builder
455    }
456}
457
458
459//------------ BuilderAppendError --------------------------------------------
460
461/// A type alias resolving into the `AppendError` of an octets type’s builder.
462///
463/// This alias can be used rather than spelling out the complete litany in
464/// result types.
465pub type BuilderAppendError<Octets>
466    = <<Octets as FromBuilder>::Builder as OctetsBuilder>::AppendError;
467
468
469//============ Error Handling ================================================
470
471//------------ ShortBuf ------------------------------------------------------
472
473/// An attempt was made to write beyond the end of a buffer.
474///
475/// This type is returned as an error by all functions and methods that append
476/// data to an [octets builder] when the buffer size of the builder is not
477/// sufficient to append the data.
478///
479/// [octets builder]: trait.OctetsBuilder.html
480#[derive(Clone, Debug, Eq, PartialEq)]
481pub struct ShortBuf;
482
483
484//--- From
485
486impl From<Infallible> for ShortBuf {
487    fn from(_: Infallible) -> ShortBuf {
488        unreachable!()
489    }
490}
491
492
493//--- Display and Error
494
495impl fmt::Display for ShortBuf {
496    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
497        f.write_str("buffer size exceeded")
498    }
499}
500
501#[cfg(feature = "std")]
502impl std::error::Error for ShortBuf {}
503
504
505//------------ Functions for Infallible --------------------------------------
506
507/// Erases an error for infallible results.
508///
509/// This function can be used in place of the still unstable
510/// `Result::into_ok` for operations on infallible octets builders.
511///
512/// If you perform multiple operations, [`with_infallible`] allows you to
513/// use the question mark operator on them before erasing the error.
514pub fn infallible<T, E: Into<Infallible>>(src: Result<T, E>) -> T {
515    match src {
516        Ok(ok) => ok,
517        Err(_) => unreachable!(),
518    }
519}
520
521/// Erases an error for a closure returning an infallible results.
522///
523/// This function can be used for a sequence of operations on an infallible
524/// octets builder. By wrapping these operations in a closure, you can still
525/// use the question mark operator rather than having to wrap each individual
526/// operation in [`infallible`].
527pub fn with_infallible<F, T, E>(op: F) -> T
528where
529    F: FnOnce() -> Result<T, E>,
530    E: Into<Infallible>,
531{
532    infallible(op())
533}
534