object_rainbow/
length_prefixed.rs

1use std::ops::{Add, Deref, DerefMut};
2
3use generic_array::ArrayLength;
4use typenum::{Sum, U8, Unsigned, tarr};
5
6use crate::{
7    Error, Inline, MaybeHasNiche, NoNiche, Object, Parse, ParseAsInline, ParseInline, ParseInput,
8    ReflessInline, ReflessObject, Size, SomeNiche, Tagged, ToOutput, ToOutputExt, Topological,
9    ZeroNiche, ZeroNoNiche, numeric::Le,
10};
11
12#[derive(Topological, Tagged, Object, Inline, ReflessObject, ReflessInline, ParseAsInline)]
13pub struct Lp<T>(pub T);
14
15impl<T> Deref for Lp<T> {
16    type Target = T;
17
18    fn deref(&self) -> &Self::Target {
19        &self.0
20    }
21}
22
23impl<T> DerefMut for Lp<T> {
24    fn deref_mut(&mut self) -> &mut Self::Target {
25        &mut self.0
26    }
27}
28
29impl<T: ToOutput> ToOutput for Lp<T> {
30    fn to_output(&self, output: &mut dyn crate::Output) {
31        let data = self.0.output::<Vec<u8>>();
32        let len = data.len();
33        let len = len as u64;
34        assert_ne!(len, u64::MAX);
35        let prefix = Le::<u64>(len);
36        prefix.to_output(output);
37        data.to_output(output);
38    }
39}
40
41impl<T: Size> Size for Lp<T>
42where
43    U8: Add<T::Size, Output: Unsigned>,
44{
45    type Size = Sum<U8, T::Size>;
46}
47
48impl<T: Size> MaybeHasNiche for Lp<T>
49where
50    U8: Add<T::Size, Output: ArrayLength>,
51{
52    type MnArray = tarr![SomeNiche<ZeroNiche<U8>>, NoNiche<ZeroNoNiche<T::Size>>];
53}
54
55impl<T: Parse<I>, I: ParseInput> ParseInline<I> for Lp<T> {
56    fn parse_inline(input: &mut I) -> crate::Result<Self> {
57        let prefix: Le<u64> = input.parse_inline()?;
58        let len = prefix.0;
59        let len = len.try_into().map_err(|_| Error::LenOutOfBounds)?;
60        Ok(Self(input.parse_ahead(len)?))
61    }
62}
63
64#[test]
65fn prefixed() {
66    let a = Lp(vec![0, 1, 2]);
67    let data = a.output::<Vec<u8>>();
68    let b = <Lp<Vec<u8>> as ReflessObject>::parse_slice(&data).unwrap();
69    assert_eq!(*a, *b);
70}
71
72#[derive(Debug, Clone, ParseAsInline, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
73pub struct LpBytes(pub Vec<u8>);
74
75impl Deref for LpBytes {
76    type Target = Vec<u8>;
77
78    fn deref(&self) -> &Self::Target {
79        &self.0
80    }
81}
82
83impl DerefMut for LpBytes {
84    fn deref_mut(&mut self) -> &mut Self::Target {
85        &mut self.0
86    }
87}
88
89impl ToOutput for LpBytes {
90    fn to_output(&self, output: &mut dyn crate::Output) {
91        let data = &self.0;
92        let len = data.len();
93        let len = len as u64;
94        assert_ne!(len, u64::MAX);
95        let prefix = Le::<u64>(len);
96        prefix.to_output(output);
97        data.to_output(output);
98    }
99}
100
101impl<I: ParseInput> ParseInline<I> for LpBytes {
102    fn parse_inline(input: &mut I) -> crate::Result<Self> {
103        let prefix: Le<u64> = input.parse_inline()?;
104        let len = prefix.0;
105        let len = len.try_into().map_err(|_| Error::LenOutOfBounds)?;
106        Ok(Self(input.parse_n(len)?.into()))
107    }
108}
109
110impl Topological for LpBytes {}
111impl Tagged for LpBytes {}
112impl Object for LpBytes {}
113impl Inline for LpBytes {}
114impl ReflessObject for LpBytes {}
115impl ReflessInline for LpBytes {}
116
117#[derive(Debug, Clone, ParseAsInline, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
118pub struct LpString(pub String);
119
120impl Deref for LpString {
121    type Target = String;
122
123    fn deref(&self) -> &Self::Target {
124        &self.0
125    }
126}
127
128impl DerefMut for LpString {
129    fn deref_mut(&mut self) -> &mut Self::Target {
130        &mut self.0
131    }
132}
133
134impl ToOutput for LpString {
135    fn to_output(&self, output: &mut dyn crate::Output) {
136        let data = self.0.as_bytes();
137        let len = data.len();
138        let len = len as u64;
139        assert_ne!(len, u64::MAX);
140        let prefix = Le::<u64>(len);
141        prefix.to_output(output);
142        data.to_output(output);
143    }
144}
145
146impl<I: ParseInput> ParseInline<I> for LpString {
147    fn parse_inline(input: &mut I) -> crate::Result<Self> {
148        String::from_utf8(input.parse_inline::<LpBytes>()?.0)
149            .map_err(Error::Utf8)
150            .map(Self)
151    }
152}
153
154impl Topological for LpString {}
155impl Tagged for LpString {}
156impl Object for LpString {}
157impl Inline for LpString {}
158impl ReflessObject for LpString {}
159impl ReflessInline for LpString {}