Skip to main content

object_rainbow/
zero_terminated.rs

1use object_rainbow_derive::{ParseAsInline, Tagged, Topological};
2
3use crate::*;
4
5#[derive(Tagged, ListHashes, Topological)]
6struct ZtInner<T> {
7    object: T,
8    data: Vec<u8>,
9}
10
11/// Zero-terminated value. Used to make [`Inline`]s out of [`Object`]s which don't contain zeroes.
12///
13/// If you can't guarantee absence of zeroes, see [`length_prefixed::Lp`].
14#[derive(Tagged, ListHashes, Topological, ParseAsInline)]
15pub struct Zt<T> {
16    inner: Arc<ZtInner<T>>,
17}
18
19impl<T: ToOutput> Zt<T> {
20    /// Create a zero-terminated value.
21    ///
22    /// Pre-computes the output, errors if it contains a zero.
23    pub fn new(object: T) -> crate::Result<Self> {
24        let data = object.vec();
25        if data.contains(&0) {
26            Err(Error::Zero)
27        } else {
28            Ok(Self {
29                inner: Arc::new(ZtInner { object, data }),
30            })
31        }
32    }
33}
34
35impl<T> Clone for Zt<T> {
36    fn clone(&self) -> Self {
37        Self {
38            inner: self.inner.clone(),
39        }
40    }
41}
42
43impl<T> Deref for Zt<T> {
44    type Target = T;
45
46    fn deref(&self) -> &Self::Target {
47        &self.inner.object
48    }
49}
50
51impl<T: ToOutput> ToOutput for Zt<T> {
52    fn to_output(&self, output: &mut dyn Output) {
53        self.inner.data.to_output(output);
54        output.write(&[0]);
55    }
56}
57
58impl<T: ToOutput> InlineOutput for Zt<T> {}
59
60impl<T: Parse<I>, I: ParseInput> ParseInline<I> for Zt<T> {
61    fn parse_inline(input: &mut I) -> crate::Result<Self> {
62        let data = input.parse_until_zero()?;
63        let object = input.reparse(data)?;
64        let data = data.into();
65        let inner = Arc::new(ZtInner { object, data });
66        Ok(Self { inner })
67    }
68}