Skip to main content

sval_flatten/
tuple.rs

1use crate::{
2    flattener::{Flatten, Flattener},
3    label::Empty,
4};
5use sval::{Index, Label, Stream, Tag};
6
7/**
8Flatten the fields of a value onto a tuple.
9
10The `offset` is the current length of the tuple. A new offset will be returned
11with the length of the tuple after flattening the value.
12 */
13pub fn flatten_to_tuple<'sval>(
14    stream: &mut (impl Stream<'sval> + ?Sized),
15    value: &'sval (impl sval::Value + ?Sized),
16    offset: isize,
17) -> sval::Result<isize> {
18    let mut stream = FlattenToTuple::new(stream, offset);
19
20    value.stream(&mut stream)?;
21
22    Ok(stream.end().0)
23}
24
25/**
26A stream that flattens the fields of a value onto a tuple.
27*/
28pub struct FlattenToTuple<'sval, S> {
29    inner: Flattener<'sval, TupleFlatten<S>>,
30}
31
32impl<'sval, S: sval::Stream<'sval>> FlattenToTuple<'sval, S> {
33    /**
34    Wrap the given `stream`.
35
36    The `offset` is the current length of the tuple being flattened onto.
37    Call [`FlattenToTuple::end`] after streaming a value to get the new length of the tuple.
38    */
39    pub fn new(stream: S, offset: isize) -> Self {
40        FlattenToTuple {
41            inner: Flattener::begin(
42                TupleFlatten {
43                    stream,
44                    label_stream: Empty,
45                },
46                offset,
47            ),
48        }
49    }
50
51    /**
52    Finish flattening a value.
53
54    This method returns the length of the map after flattening that can be used to reconstruct a `FlattenToTuple` for a future value.
55    */
56    pub fn end(self) -> (isize, S) {
57        let (offset, TupleFlatten { stream, .. }) = self.inner.end();
58
59        (offset, stream)
60    }
61}
62
63impl_stream_forward!({ impl<'sval, S: Stream<'sval>> Stream<'sval> for FlattenToTuple<'sval, S> } => x => { x.inner });
64
65struct TupleFlatten<S> {
66    stream: S,
67    label_stream: Empty,
68}
69
70impl<'sval, S: Stream<'sval>> Flatten<'sval> for TupleFlatten<S> {
71    type Stream = S;
72    type LabelStream = Empty;
73
74    fn stream(&mut self) -> &mut Self::Stream {
75        &mut self.stream
76    }
77
78    fn label_stream(&mut self) -> &mut Self::LabelStream {
79        &mut self.label_stream
80    }
81
82    fn flattened_value_begin(
83        &mut self,
84        tag: Option<&Tag>,
85        _: &Label,
86        index: &Index,
87    ) -> sval::Result {
88        self.stream.tuple_value_begin(tag, index)
89    }
90
91    fn flattened_value_end(&mut self, tag: Option<&Tag>, _: &Label, index: &Index) -> sval::Result {
92        self.stream.tuple_value_end(tag, index)
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use sval_derive_macros::*;
99
100    use super::*;
101
102    struct Outer<I>(i32, I, i32);
103
104    impl<I: sval::Value> sval::Value for Outer<I> {
105        fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
106            let mut offset = 0;
107
108            stream.tuple_begin(None, Some(&Label::new("Outer")), None, None)?;
109
110            stream.tuple_value_begin(
111                None,
112                &Index::from(offset).with_tag(&sval::tags::VALUE_OFFSET),
113            )?;
114            stream.i32(self.0)?;
115            stream.tuple_value_end(
116                None,
117                &Index::from(offset).with_tag(&sval::tags::VALUE_OFFSET),
118            )?;
119            offset += 1;
120
121            offset = flatten_to_tuple(&mut *stream, &self.1, offset)?;
122
123            stream.tuple_value_begin(
124                None,
125                &Index::from(offset).with_tag(&sval::tags::VALUE_OFFSET),
126            )?;
127            stream.i32(self.2)?;
128            stream.tuple_value_end(
129                None,
130                &Index::from(offset).with_tag(&sval::tags::VALUE_OFFSET),
131            )?;
132            offset += 1;
133
134            let _ = offset;
135            stream.tuple_end(None, Some(&Label::new("Outer")), None)
136        }
137    }
138
139    #[test]
140    fn flatten_record() {
141        #[derive(Value)]
142        #[sval(unindexed_fields)]
143        struct Inner {
144            b: i32,
145            c: i32,
146        }
147
148        sval_test::assert_tokens(&Outer(1, Inner { b: 2, c: 3 }, 4), {
149            use sval_test::Token::*;
150
151            &[
152                TupleBegin(None, Some(Label::new("Outer")), None, None),
153                TupleValueBegin(None, Index::new(0)),
154                I32(1),
155                TupleValueEnd(None, Index::new(0)),
156                TupleValueBegin(None, Index::new(1)),
157                I32(2),
158                TupleValueEnd(None, Index::new(1)),
159                TupleValueBegin(None, Index::new(2)),
160                I32(3),
161                TupleValueEnd(None, Index::new(2)),
162                TupleValueBegin(None, Index::new(3)),
163                I32(4),
164                TupleValueEnd(None, Index::new(3)),
165                TupleEnd(None, Some(Label::new("Outer")), None),
166            ]
167        });
168    }
169
170    #[test]
171    fn flatten_tuple() {
172        sval_test::assert_tokens(&Outer(1, (2, 3), 4), {
173            use sval_test::Token::*;
174
175            &[
176                TupleBegin(None, Some(Label::new("Outer")), None, None),
177                TupleValueBegin(None, Index::new(0)),
178                I32(1),
179                TupleValueEnd(None, Index::new(0)),
180                TupleValueBegin(None, Index::new(1)),
181                I32(2),
182                TupleValueEnd(None, Index::new(1)),
183                TupleValueBegin(None, Index::new(2)),
184                I32(3),
185                TupleValueEnd(None, Index::new(2)),
186                TupleValueBegin(None, Index::new(3)),
187                I32(4),
188                TupleValueEnd(None, Index::new(3)),
189                TupleEnd(None, Some(Label::new("Outer")), None),
190            ]
191        });
192    }
193
194    #[test]
195    fn flatten_seq() {
196        sval_test::assert_tokens(&Outer(1, [2, 3], 4), {
197            use sval_test::Token::*;
198
199            &[
200                TupleBegin(None, Some(Label::new("Outer")), None, None),
201                TupleValueBegin(None, Index::new(0)),
202                I32(1),
203                TupleValueEnd(None, Index::new(0)),
204                TupleValueBegin(None, Index::new(1)),
205                I32(2),
206                TupleValueEnd(None, Index::new(1)),
207                TupleValueBegin(None, Index::new(2)),
208                I32(3),
209                TupleValueEnd(None, Index::new(2)),
210                TupleValueBegin(None, Index::new(3)),
211                I32(4),
212                TupleValueEnd(None, Index::new(3)),
213                TupleEnd(None, Some(Label::new("Outer")), None),
214            ]
215        });
216    }
217
218    #[test]
219    fn flatten_map() {
220        sval_test::assert_tokens(
221            &Outer(
222                1,
223                sval::MapSlice::new(&[(["b1", "b2"], 2), (["c1", "c2"], 3)]),
224                4,
225            ),
226            {
227                use sval_test::Token::*;
228
229                &[
230                    TupleBegin(None, Some(Label::new("Outer")), None, None),
231                    TupleValueBegin(None, Index::new(0)),
232                    I32(1),
233                    TupleValueEnd(None, Index::new(0)),
234                    TupleValueBegin(None, Index::new(1)),
235                    I32(2),
236                    TupleValueEnd(None, Index::new(1)),
237                    TupleValueBegin(None, Index::new(2)),
238                    I32(3),
239                    TupleValueEnd(None, Index::new(2)),
240                    TupleValueBegin(None, Index::new(3)),
241                    I32(4),
242                    TupleValueEnd(None, Index::new(3)),
243                    TupleEnd(None, Some(Label::new("Outer")), None),
244                ]
245            },
246        );
247    }
248
249    #[test]
250    fn flatten_record_tuple() {
251        #[derive(Value)]
252        struct Inner {
253            b: i32,
254            c: i32,
255        }
256
257        sval_test::assert_tokens(&Outer(1, Inner { b: 2, c: 3 }, 4), {
258            use sval_test::Token::*;
259
260            &[
261                TupleBegin(None, Some(Label::new("Outer")), None, None),
262                TupleValueBegin(None, Index::new(0)),
263                I32(1),
264                TupleValueEnd(None, Index::new(0)),
265                TupleValueBegin(None, Index::new(1)),
266                I32(2),
267                TupleValueEnd(None, Index::new(1)),
268                TupleValueBegin(None, Index::new(2)),
269                I32(3),
270                TupleValueEnd(None, Index::new(2)),
271                TupleValueBegin(None, Index::new(3)),
272                I32(4),
273                TupleValueEnd(None, Index::new(3)),
274                TupleEnd(None, Some(Label::new("Outer")), None),
275            ]
276        });
277    }
278
279    #[test]
280    fn flatten_enum() {
281        #[derive(Value)]
282        enum Inner {
283            #[sval(label = "b")]
284            A(i32),
285            B {
286                b: i32,
287                c: i32,
288            },
289            C(i32, i32),
290        }
291
292        sval_test::assert_tokens(&Outer(1, Inner::A(2), 4), {
293            use sval_test::Token::*;
294
295            &[
296                TupleBegin(None, Some(Label::new("Outer")), None, None),
297                TupleValueBegin(None, Index::new(0)),
298                I32(1),
299                TupleValueEnd(None, Index::new(0)),
300                TupleValueBegin(None, Index::new(1)),
301                I32(2),
302                TupleValueEnd(None, Index::new(1)),
303                TupleValueBegin(None, Index::new(2)),
304                I32(4),
305                TupleValueEnd(None, Index::new(2)),
306                TupleEnd(None, Some(Label::new("Outer")), None),
307            ]
308        });
309
310        sval_test::assert_tokens(&Outer(1, Inner::B { b: 2, c: 3 }, 4), {
311            use sval_test::Token::*;
312
313            &[
314                TupleBegin(None, Some(Label::new("Outer")), None, None),
315                TupleValueBegin(None, Index::new(0)),
316                I32(1),
317                TupleValueEnd(None, Index::new(0)),
318                TupleValueBegin(None, Index::new(1)),
319                I32(2),
320                TupleValueEnd(None, Index::new(1)),
321                TupleValueBegin(None, Index::new(2)),
322                I32(3),
323                TupleValueEnd(None, Index::new(2)),
324                TupleValueBegin(None, Index::new(3)),
325                I32(4),
326                TupleValueEnd(None, Index::new(3)),
327                TupleEnd(None, Some(Label::new("Outer")), None),
328            ]
329        });
330
331        sval_test::assert_tokens(&Outer(1, Inner::C(2, 3), 4), {
332            use sval_test::Token::*;
333
334            &[
335                TupleBegin(None, Some(Label::new("Outer")), None, None),
336                TupleValueBegin(None, Index::new(0)),
337                I32(1),
338                TupleValueEnd(None, Index::new(0)),
339                TupleValueBegin(None, Index::new(1)),
340                I32(2),
341                TupleValueEnd(None, Index::new(1)),
342                TupleValueBegin(None, Index::new(2)),
343                I32(3),
344                TupleValueEnd(None, Index::new(2)),
345                TupleValueBegin(None, Index::new(3)),
346                I32(4),
347                TupleValueEnd(None, Index::new(3)),
348                TupleEnd(None, Some(Label::new("Outer")), None),
349            ]
350        });
351    }
352}