Skip to main content

multi_cbor/
write.rs

1#[cfg(feature = "alloc")]
2use alloc::vec::Vec;
3#[cfg(not(feature = "std"))]
4use core::fmt;
5#[cfg(feature = "std")]
6use std::io;
7
8use crate::error;
9
10#[cfg(not(feature = "unsealed_read_write"))]
11/// A sink for serialized CBOR.
12///
13/// This trait is similar to the [`Write`]() trait in the standard library,
14/// but has a smaller and more general API.
15///
16/// Any object implementing `std::io::Write`
17/// can be wrapped in an [`IoWrite`](../write/struct.IoWrite.html) that implements
18/// this trait for the underlying object.
19pub trait Write: private::Sealed {
20    /// The type of error returned when a write operation fails.
21    #[doc(hidden)]
22    type Error: Into<error::Error>;
23
24    /// Attempts to write an entire buffer into this write.
25    #[doc(hidden)]
26    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
27}
28
29#[cfg(feature = "unsealed_read_write")]
30/// A sink for serialized CBOR.
31///
32/// This trait is similar to the [`Write`]() trait in the standard library,
33/// but has a smaller and more general API.
34///
35/// Any object implementing `std::io::Write`
36/// can be wrapped in an [`IoWrite`](../write/struct.IoWrite.html) that implements
37/// this trait for the underlying object.
38///
39/// This trait is sealed by default, enabling the `unsealed_read_write` feature removes this bound
40/// to allow objects outside of this crate to implement this trait.
41pub trait Write {
42    /// The type of error returned when a write operation fails.
43    type Error: Into<error::Error>;
44
45    /// Attempts to write an entire buffer into this write.
46    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
47}
48
49#[cfg(not(feature = "unsealed_read_write"))]
50mod private {
51    pub trait Sealed {}
52}
53
54impl<W> Write for &mut W
55where
56    W: Write,
57{
58    type Error = W::Error;
59
60    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
61        (*self).write_all(buf)
62    }
63}
64
65#[cfg(not(feature = "unsealed_read_write"))]
66impl<W> private::Sealed for &mut W where W: Write {}
67
68#[cfg(feature = "std")]
69/// A wrapper for types that implement
70/// [`std::io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html) to implement the local
71/// [`Write`](trait.Write.html) trait.
72#[derive(Debug)]
73pub struct IoWrite<W>(W);
74
75#[cfg(feature = "std")]
76impl<W: io::Write> IoWrite<W> {
77    /// Wraps an `io::Write` writer to make it compatible with [`Write`](trait.Write.html)
78    pub const fn new(w: W) -> Self {
79        Self(w)
80    }
81}
82
83#[cfg(feature = "std")]
84impl<W: io::Write> Write for IoWrite<W> {
85    type Error = io::Error;
86
87    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
88        self.0.write_all(buf)
89    }
90}
91
92#[cfg(all(feature = "std", not(feature = "unsealed_read_write")))]
93impl<W> private::Sealed for IoWrite<W> where W: io::Write {}
94
95#[cfg(any(feature = "std", feature = "alloc"))]
96impl Write for Vec<u8> {
97    type Error = error::Error;
98
99    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
100        self.extend_from_slice(buf);
101        Ok(())
102    }
103}
104
105#[cfg(all(
106    any(feature = "std", feature = "alloc"),
107    not(feature = "unsealed_read_write")
108))]
109impl private::Sealed for Vec<u8> {}
110
111#[cfg(not(feature = "std"))]
112#[derive(Debug)]
113pub struct FmtWrite<'a, W: Write>(&'a mut W);
114
115#[cfg(not(feature = "std"))]
116impl<'a, W: Write> FmtWrite<'a, W> {
117    /// Wraps an `fmt::Write` writer to make it compatible with [`Write`](trait.Write.html)
118    pub const fn new(w: &'a mut W) -> Self {
119        FmtWrite(w)
120    }
121}
122
123#[cfg(not(feature = "std"))]
124impl<W: Write> fmt::Write for FmtWrite<'_, W> {
125    fn write_str(&mut self, s: &str) -> fmt::Result {
126        self.0.write_all(s.as_bytes()).map_err(|_| fmt::Error)
127    }
128}
129
130#[cfg(all(not(feature = "std"), not(feature = "unsealed_read_write")))]
131impl<W> private::Sealed for FmtWrite<'_, W> where W: Write {}
132
133/// Implements [`Write`](trait.Write.html) for mutable byte slices (`&mut [u8]`).
134///
135/// Returns an error if the value to serialize is too large to fit in the slice.
136#[derive(Debug)]
137pub struct SliceWrite<'a> {
138    slice: &'a mut [u8],
139    index: usize,
140}
141
142impl<'a> SliceWrite<'a> {
143    /// Wraps a mutable slice so it can be used as a `Write`.
144    pub const fn new(slice: &'a mut [u8]) -> Self {
145        SliceWrite { slice, index: 0 }
146    }
147
148    /// Returns the number of bytes written to the underlying slice.
149    #[must_use]
150    pub const fn bytes_written(&self) -> usize {
151        self.index
152    }
153
154    /// Returns the underlying slice.
155    #[must_use]
156    pub const fn into_inner(self) -> &'a mut [u8] {
157        self.slice
158    }
159}
160
161impl Write for SliceWrite<'_> {
162    type Error = error::Error;
163
164    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
165        if self.slice.len() - self.index < buf.len() {
166            // This buffer will not fit in our slice
167            return Err(error::Error::scratch_too_small(self.index as u64));
168        }
169        let end = self.index + buf.len();
170        self.slice[self.index..end].copy_from_slice(buf);
171        self.index = end;
172        Ok(())
173    }
174}
175
176#[cfg(not(feature = "unsealed_read_write"))]
177impl private::Sealed for SliceWrite<'_> {}