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 impl Output) {
53        if output.is_mangling() {
54            self.inner.object.to_output(output);
55        }
56        if output.is_real() {
57            self.inner.data.to_output(output);
58            output.write(&[0]);
59        }
60    }
61}
62
63impl<T: ToOutput> InlineOutput for Zt<T> {}
64
65impl<T: Parse<I>, I: ParseInput> ParseInline<I> for Zt<T> {
66    fn parse_inline(input: &mut I) -> crate::Result<Self> {
67        let data = input.parse_until_zero()?;
68        let object = input.reparse(data)?;
69        let data = data.into();
70        let inner = Arc::new(ZtInner { object, data });
71        Ok(Self { inner })
72    }
73}