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