Skip to main content

object_rainbow/
length_prefixed.rs

1use std::ops::{Deref, DerefMut};
2
3use crate::{u63::U63, *};
4
5/// Length-prefixed value. Used to make [`Inline`]s out of arbitrary [`Object`]s.
6///
7/// If you can guarantee absence of zeroes, see [`zero_terminated::Zt`].
8#[derive(ListHashes, Topological, Tagged, ParseAsInline, Default, Clone, PartialEq, Eq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Lp<T>(pub T);
11
12impl<T> Deref for Lp<T> {
13    type Target = T;
14
15    fn deref(&self) -> &Self::Target {
16        &self.0
17    }
18}
19
20impl<T> DerefMut for Lp<T> {
21    fn deref_mut(&mut self) -> &mut Self::Target {
22        &mut self.0
23    }
24}
25
26impl<T: ToOutput> ToOutput for Lp<T> {
27    fn to_output(&self, output: &mut impl Output) {
28        if output.is_mangling() {
29            self.0.to_output(output);
30        }
31        if output.is_real() {
32            let data = self.0.vec();
33            let prefix = U63::len_of(&data);
34            prefix.to_output(output);
35            data.to_output(output);
36        }
37    }
38}
39
40impl<T: ToOutput> InlineOutput for Lp<T> {}
41
42impl<T: Parse<I>, I: ParseInput> ParseInline<I> for Lp<T> {
43    fn parse_inline(input: &mut I) -> crate::Result<Self> {
44        let prefix: U63 = input.parse_inline()?;
45        Ok(Self(input.split_parse(prefix.as_usize()?)?))
46    }
47}
48
49#[test]
50fn prefixed() -> crate::Result<()> {
51    let a = Lp(vec![0, 1, 2]);
52    let data = a.vec();
53    let b = Lp::<Vec<u8>>::parse_slice_refless(&data)?;
54    assert_eq!(*a, *b);
55    Ok(())
56}
57
58/// Length-prefixed [`Vec<u8>`]
59#[derive(Debug, Clone, ParseAsInline, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61pub struct LpBytes(pub Vec<u8>);
62
63impl Deref for LpBytes {
64    type Target = Vec<u8>;
65
66    fn deref(&self) -> &Self::Target {
67        &self.0
68    }
69}
70
71impl DerefMut for LpBytes {
72    fn deref_mut(&mut self) -> &mut Self::Target {
73        &mut self.0
74    }
75}
76
77impl ToOutput for LpBytes {
78    fn to_output(&self, output: &mut impl Output) {
79        if output.is_real() {
80            let data = &self.0;
81            let prefix = U63::len_of(data);
82            prefix.to_output(output);
83            data.to_output(output);
84        }
85    }
86}
87
88impl InlineOutput for LpBytes {}
89
90impl<I: ParseInput> ParseInline<I> for LpBytes {
91    fn parse_inline(input: &mut I) -> crate::Result<Self> {
92        let prefix: U63 = input.parse_inline()?;
93        let mut data = vec![0; prefix.as_usize()?];
94        input.read(&mut data)?;
95        Ok(Self(data))
96    }
97}
98
99impl Tagged for LpBytes {}
100impl ListHashes for LpBytes {}
101impl Topological for LpBytes {}
102
103/// Length-prefixed [`String`].
104#[derive(Debug, Clone, ParseAsInline, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
106pub struct LpString(pub String);
107
108impl Deref for LpString {
109    type Target = String;
110
111    fn deref(&self) -> &Self::Target {
112        &self.0
113    }
114}
115
116impl DerefMut for LpString {
117    fn deref_mut(&mut self) -> &mut Self::Target {
118        &mut self.0
119    }
120}
121
122impl ToOutput for LpString {
123    fn to_output(&self, output: &mut impl Output) {
124        if output.is_real() {
125            let data = &self.0;
126            let prefix = U63::len_of(data.as_bytes());
127            prefix.to_output(output);
128            data.to_output(output);
129        }
130    }
131}
132
133impl InlineOutput for LpString {}
134
135impl<I: ParseInput> ParseInline<I> for LpString {
136    fn parse_inline(input: &mut I) -> crate::Result<Self> {
137        String::from_utf8(input.parse_inline::<LpBytes>()?.0)
138            .map_err(Error::Utf8)
139            .map(Self)
140    }
141}
142
143impl Tagged for LpString {}
144impl ListHashes for LpString {}
145impl Topological for LpString {}