musli/writer/
slice_mut_writer.rs

1use core::marker::PhantomData;
2use core::ptr::NonNull;
3
4use crate::Context;
5use crate::alloc::Vec;
6
7use super::{SliceOverflow, Writer};
8
9/// A writer into a slice.
10///
11/// This is typically created by using a mutable slice as a writer through
12/// the [`IntoWriter`] trait.
13///
14/// [`IntoWriter`]: crate::writer::IntoWriter
15///
16/// # Examples
17///
18/// ```
19/// use musli::writer::{IntoWriter, Writer};
20/// use musli::context;
21///
22/// let mut buffer = [0u8; 10];
23/// let mut writer = buffer.as_mut_slice().into_writer();
24/// let cx = context::new();
25///
26/// writer.write_bytes(&cx, b"Hello")?;
27/// let remaining = writer.finish(&cx)?;
28///
29/// assert_eq!(&buffer[..5], b"Hello");
30/// assert_eq!(remaining, 5); // 5 bytes remaining in the 10-byte buffer
31/// # Ok::<_, musli::context::ErrorMarker>(())
32/// ```
33pub struct SliceMutWriter<'a> {
34    start: NonNull<u8>,
35    end: NonNull<u8>,
36    _marker: PhantomData<&'a mut [u8]>,
37}
38
39impl<'a> SliceMutWriter<'a> {
40    pub(super) fn new(slice: &'a mut [u8]) -> Self {
41        // SAFETY: The slice is valid for the duration of the writer.
42        unsafe {
43            let range = slice.as_mut_ptr_range();
44            let start = NonNull::new_unchecked(range.start);
45            let end = NonNull::new_unchecked(range.end);
46            Self {
47                start,
48                end,
49                _marker: PhantomData,
50            }
51        }
52    }
53
54    #[inline]
55    pub(crate) fn remaining(&self) -> usize {
56        self.end.as_ptr() as usize - self.start.as_ptr() as usize
57    }
58}
59
60impl<'a> Writer for SliceMutWriter<'a> {
61    type Ok = usize;
62
63    type Mut<'this>
64        = &'this mut SliceMutWriter<'a>
65    where
66        Self: 'this;
67
68    #[inline]
69    fn finish<C>(&mut self, _: C) -> Result<Self::Ok, C::Error>
70    where
71        C: Context,
72    {
73        Ok(self.remaining())
74    }
75
76    #[inline]
77    fn borrow_mut(&mut self) -> Self::Mut<'_> {
78        self
79    }
80
81    #[inline]
82    fn extend<C>(&mut self, cx: C, buffer: Vec<u8, C::Allocator>) -> Result<(), C::Error>
83    where
84        C: Context,
85    {
86        // SAFETY: the buffer never outlives this function call.
87        self.write_bytes(cx, buffer.as_slice())
88    }
89
90    #[inline]
91    fn write_bytes<C>(&mut self, cx: C, bytes: &[u8]) -> Result<(), C::Error>
92    where
93        C: Context,
94    {
95        let end = self.start.as_ptr().wrapping_add(bytes.len());
96
97        if end > self.end.as_ptr() || end < self.start.as_ptr() {
98            return Err(cx.message(SliceOverflow {
99                n: bytes.len(),
100                capacity: self.remaining(),
101            }));
102        }
103
104        // SAFETY: Construction of the writer ensures the range is valid.
105        unsafe {
106            self.start
107                .as_ptr()
108                .copy_from_nonoverlapping(bytes.as_ptr(), bytes.len());
109            self.start = NonNull::new_unchecked(end);
110        }
111
112        Ok(())
113    }
114
115    #[inline]
116    fn write_byte<C>(&mut self, cx: C, b: u8) -> Result<(), C::Error>
117    where
118        C: Context,
119    {
120        if self.start == self.end {
121            return Err(cx.message(format_args!(
122                "Buffer overflow, remaining is 0 while tried to write 1"
123            )));
124        }
125
126        // SAFETY: Construction of the writer ensures the range is valid.
127        unsafe {
128            self.start.write(b);
129            self.start = self.start.add(1);
130        }
131
132        Ok(())
133    }
134}