1use crate::{
2 flattener::{Flatten, Flattener},
3 label::Empty,
4};
5use sval::{Index, Label, Stream, Tag};
6
7pub 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}