1
use alloc::borrow::Cow;
2
use alloc::string::String;
3
use alloc::vec::Vec;
4
use core::fmt;
5
use core::fmt::Write;
6

            
7
use crate::tokenizer::Integer;
8
use crate::value::{StructContents, Value};
9

            
10
/// A low-level writer for the Rsn format.
11
#[derive(Debug)]
12
pub struct Writer<'config, Output> {
13
    output: Output,
14
    nested: Vec<NestedState>,
15
    config: Cow<'config, Config>,
16
}
17

            
18
impl Default for Writer<'static, String> {
19
    fn default() -> Self {
20
        Self::new(String::new(), &Config::Compact)
21
    }
22
}
23

            
24
impl<'config, Output> Writer<'config, Output>
25
where
26
    Output: Write,
27
{
28
    /// Returns a writer that outputs to `output` using `config`.
29
20
    pub fn new(output: Output, config: &'config Config) -> Self {
30
20
        Self {
31
20
            output,
32
20
            nested: Vec::new(),
33
20
            config: Cow::Borrowed(config),
34
20
        }
35
20
    }
36

            
37
    /// Finishes writing and returns the output.
38
    ///
39
    /// # Panics
40
    ///
41
    /// This function panics if a nested type was begun and a corresponding
42
    /// `finish_nested` was not called.
43
18
    pub fn finish(self) -> Output {
44
18
        assert!(self.nested.is_empty());
45
18
        self.output
46
18
    }
47

            
48
    /// Begins a named map. A corresponding call to `finish_nested` must be made
49
    /// when the map contents are completed.
50
    ///
51
    /// # Errors
52
    ///
53
    /// Returns any errors that arise while writing to `Output`.
54
11
    pub fn begin_named_map(&mut self, name: &str) -> fmt::Result {
55
11
        self.prepare_to_write_value()?;
56
11
        self.output.write_str(name)?;
57
11
        if matches!(self.config.as_ref(), Config::Pretty { .. }) {
58
5
            self.output.write_char(' ')?;
59
6
        }
60
11
        self.output.write_char('{')?;
61
11
        self.nested.push(NestedState::Map(MapState::Empty));
62
11
        Ok(())
63
11
    }
64

            
65
    /// Begins a named tuple. A corresponding call to `finish_nested` must be
66
    /// made when the tuple contents are completed.
67
    ///
68
    /// # Errors
69
    ///
70
    /// Returns any errors that arise while writing to `Output`.
71
6
    pub fn begin_named_tuple(&mut self, name: &str) -> fmt::Result {
72
6
        self.prepare_to_write_value()?;
73
6
        self.nested.push(NestedState::Tuple(SequenceState::Empty));
74
6
        self.output.write_str(name)?;
75
6
        self.output.write_char('(')
76
6
    }
77

            
78
    /// Begins a map. A corresponding call to `finish_nested` must be made when
79
    /// the map contents are completed.
80
    ///
81
    /// # Errors
82
    ///
83
    /// Returns any errors that arise while writing to `Output`.
84
3
    pub fn begin_map(&mut self) -> fmt::Result {
85
3
        self.prepare_to_write_value()?;
86
3
        self.nested.push(NestedState::Map(MapState::Empty));
87
3
        self.output.write_char('{')
88
3
    }
89

            
90
    /// Begins a tuple. A corresponding call to `finish_nested` must be made when
91
    /// the tuple contents are completed.
92
    ///
93
    /// # Errors
94
    ///
95
    /// Returns any errors that arise while writing to `Output`.
96
    pub fn begin_tuple(&mut self) -> fmt::Result {
97
        self.prepare_to_write_value()?;
98
        self.nested.push(NestedState::Tuple(SequenceState::Empty));
99
        self.output.write_char('(')
100
    }
101

            
102
    /// Begins a list/array. A corresponding call to `finish_nested` must be
103
    /// made when the list contents are completed.
104
    ///
105
    /// # Errors
106
    ///
107
    /// Returns any errors that arise while writing to `Output`.
108
2
    pub fn begin_list(&mut self) -> fmt::Result {
109
2
        self.prepare_to_write_value()?;
110
2
        self.nested.push(NestedState::List(SequenceState::Empty));
111
2
        self.output.write_char('[')
112
2
    }
113

            
114
    /// Writes a primitive value, formatting it as valid Rsn.
115
    ///
116
    /// # Errors
117
    ///
118
    /// Returns any errors that arise while writing to `Output`.
119
216
    pub fn write_primitive<P>(&mut self, p: &P) -> fmt::Result
120
216
    where
121
216
        P: Primitive + ?Sized,
122
216
    {
123
216
        self.prepare_to_write_value()?;
124
216
        p.render_to(&mut self.output)
125
216
    }
126

            
127
    /// Writes `ident` without any extra formatting.
128
    ///
129
    /// # Errors
130
    ///
131
    /// Returns any errors that arise while writing to `Output`.
132
268
    pub fn write_raw_value(&mut self, ident: &str) -> fmt::Result {
133
268
        self.prepare_to_write_value()?;
134
268
        self.output.write_str(ident)
135
268
    }
136

            
137
506
    fn prepare_to_write_value(&mut self) -> fmt::Result {
138
506
        match self.nested.last_mut() {
139
            Some(
140
2
                NestedState::List(state @ SequenceState::Empty)
141
6
                | NestedState::Tuple(state @ SequenceState::Empty),
142
            ) => {
143
8
                *state = SequenceState::NotEmpty;
144
8
                self.insert_newline()?;
145
            }
146
            Some(NestedState::List(_) | NestedState::Tuple(_)) => {
147
2
                self.output.write_char(',')?;
148
2
                self.insert_newline()?;
149
            }
150
14
            Some(NestedState::Map(state @ MapState::Empty)) => {
151
14
                *state = MapState::AfterKey;
152
14
                self.insert_newline()?;
153
            }
154
152
            Some(NestedState::Map(state @ MapState::AfterEntry)) => {
155
152
                *state = MapState::AfterKey;
156
152
                self.output.write_char(',')?;
157
152
                self.insert_newline()?;
158
            }
159
166
            Some(NestedState::Map(state @ MapState::AfterKey)) => {
160
166
                *state = MapState::AfterEntry;
161
166
                if matches!(self.config.as_ref(), Config::Compact) {
162
108
                    self.output.write_char(':')?;
163
                } else {
164
58
                    self.output.write_str(": ")?;
165
                }
166
            }
167
164
            None => {}
168
        }
169

            
170
506
        Ok(())
171
506
    }
172

            
173
    /// Inserts the configured newline character, if needed.
174
    ///
175
    /// # Errors
176
    ///
177
    /// Returns any errors that arise while writing to `Output`.
178
248
    pub fn insert_newline(&mut self) -> fmt::Result {
179
        if let Config::Pretty {
180
122
            indentation,
181
122
            newline,
182
            ..
183
248
        } = self.config.as_ref()
184
        {
185
122
            self.output.write_str(newline)?;
186
122
            for _ in 0..self.nested.len() {
187
83
                self.output.write_str(indentation)?;
188
            }
189
126
        }
190
248
        Ok(())
191
248
    }
192

            
193
    /// Finishes the current nested value.
194
    ///
195
    /// # Errors
196
    ///
197
    /// Returns any errors that arise while writing to `Output`.
198
    ///
199
    /// # Panics
200
    ///
201
    /// This function panics if are no open nested types.
202
22
    pub fn finish_nested(&mut self) -> fmt::Result {
203
22
        match self.nested.pop().expect("not in a nested state") {
204
6
            NestedState::Tuple(state) => {
205
6
                if matches!(state, SequenceState::NotEmpty) {
206
6
                    self.insert_newline()?;
207
                }
208
6
                self.output.write_char(')')
209
            }
210
2
            NestedState::List(state) => {
211
2
                if matches!(state, SequenceState::NotEmpty) {
212
2
                    self.insert_newline()?;
213
                }
214
2
                self.output.write_char(']')
215
            }
216
14
            NestedState::Map(state @ (MapState::AfterEntry | MapState::Empty)) => {
217
14
                if matches!(state, MapState::AfterEntry) {
218
14
                    self.insert_newline()?;
219
                }
220
14
                self.output.write_char('}')
221
            }
222
            NestedState::Map(_) => unreachable!("map entry not complete"),
223
        }
224
22
    }
225

            
226
    /// Writes a value.
227
    ///
228
    /// # Errors
229
    ///
230
    /// Returns any errors that arise while writing to `Output`.
231
4
    pub fn write_value(&mut self, value: &Value<'_>) -> fmt::Result {
232
4
        match value {
233
            Value::Integer(value) => match value {
234
                Integer::Usize(value) => self.write_primitive(value),
235
                Integer::Isize(value) => self.write_primitive(value),
236
                Integer::UnsignedLarge(value) => self.write_primitive(value),
237
                Integer::SignedLarge(value) => self.write_primitive(value),
238
            },
239
            Value::Float(value) => self.write_primitive(value),
240
            Value::Bool(value) => self.write_primitive(value),
241
            Value::Char(value) => self.write_primitive(value),
242
            Value::Byte(value) => self.write_primitive(value),
243
2
            Value::Identifier(value) | Value::String(value) => self.write_primitive(value.as_ref()),
244
            Value::Bytes(value) => self.write_primitive(value.as_ref()),
245
2
            Value::Named(value) => {
246
2
                match &value.contents {
247
                    StructContents::Map(map) => {
248
                        self.begin_named_map(&value.name)?;
249
                        for (key, value) in &map.0 {
250
                            self.write_value(key)?;
251
                            self.write_value(value)?;
252
                        }
253
                    }
254
2
                    StructContents::Tuple(seq) => {
255
2
                        self.begin_named_tuple(&value.name)?;
256
4
                        for value in &seq.0 {
257
2
                            self.write_value(value)?;
258
                        }
259
                    }
260
                }
261
2
                self.finish_nested()
262
            }
263
            Value::Tuple(list) => {
264
                self.begin_tuple()?;
265
                for value in &list.0 {
266
                    self.write_value(value)?;
267
                }
268
                self.finish_nested()
269
            }
270
            Value::Array(list) => {
271
                self.begin_list()?;
272
                for value in &list.0 {
273
                    self.write_value(value)?;
274
                }
275
                self.finish_nested()
276
            }
277
            Value::Map(map) => {
278
                self.begin_map()?;
279
                for (key, value) in &map.0 {
280
                    self.write_value(key)?;
281
                    self.write_value(value)?;
282
                }
283
                self.finish_nested()
284
            }
285
        }
286
4
    }
287
}
288

            
289
/// A type that can be written as a primitive.q
290
pub trait Primitive {
291
    /// Renders this type to `buffer`.
292
    ///
293
    /// # Errors
294
    ///
295
    /// Returns any errors that arise while writing to `buffer`.
296
    fn render_to<W: Write>(&self, buffer: &mut W) -> fmt::Result;
297
}
298

            
299
macro_rules! impl_primitive_using_to_string {
300
    ($type:ty) => {
301
        impl Primitive for $type {
302
154
            fn render_to<W: Write>(&self, buffer: &mut W) -> fmt::Result {
303
154
                write!(buffer, "{self}")
304
154
            }
305
        }
306
    };
307
}
308

            
309
impl_primitive_using_to_string!(u8);
310
impl_primitive_using_to_string!(u16);
311
impl_primitive_using_to_string!(u32);
312
impl_primitive_using_to_string!(u64);
313
impl_primitive_using_to_string!(u128);
314
impl_primitive_using_to_string!(usize);
315
impl_primitive_using_to_string!(i8);
316
impl_primitive_using_to_string!(i16);
317
impl_primitive_using_to_string!(i32);
318
impl_primitive_using_to_string!(i64);
319
impl_primitive_using_to_string!(i128);
320
impl_primitive_using_to_string!(isize);
321
impl_primitive_using_to_string!(f64);
322
impl_primitive_using_to_string!(f32);
323

            
324
impl Primitive for str {
325
27
    fn render_to<W: Write>(&self, buffer: &mut W) -> fmt::Result {
326
27
        buffer.write_char('"')?;
327
319
        for ch in self.chars() {
328
319
            escape_string_char(ch, buffer)?;
329
        }
330
27
        buffer.write_char('"')
331
27
    }
332
}
333

            
334
impl Primitive for bool {
335
12
    fn render_to<W: Write>(&self, buffer: &mut W) -> fmt::Result {
336
12
        buffer.write_str(if *self { "true" } else { "false" })
337
12
    }
338
}
339

            
340
impl Primitive for [u8] {
341
13
    fn render_to<W: Write>(&self, buffer: &mut W) -> fmt::Result {
342
13
        buffer.write_str("b\"")?;
343
320
        for byte in self {
344
307
            match DEFAULT_STRING_ESCAPE_HANDLING.get(usize::from(*byte)) {
345
39
                Some(Some(escaped)) => {
346
39
                    buffer.write_str(escaped)?;
347
                }
348
                Some(None) => {
349
141
                    buffer.write_char(char::from(*byte))?;
350
                }
351
                None => {
352
                    // Non-ASCII, must be hex-escaped.
353
127
                    write!(buffer, "\\x{byte:02x}")?;
354
                }
355
            }
356
        }
357
13
        buffer.write_char('"')
358
13
    }
359
}
360

            
361
#[inline]
362
331
fn escape_string_char<W: Write>(ch: char, buffer: &mut W) -> fmt::Result {
363
331
    if let Ok(cp) = usize::try_from(u32::from(ch)) {
364
331
        if let Some(Some(escaped)) = DEFAULT_STRING_ESCAPE_HANDLING.get(cp) {
365
47
            return buffer.write_str(escaped);
366
284
        }
367
    }
368

            
369
284
    let mut utf8_bytes = [0; 8];
370
284
    buffer.write_str(ch.encode_utf8(&mut utf8_bytes))
371
331
}
372

            
373
impl Primitive for char {
374
12
    fn render_to<W: Write>(&self, buffer: &mut W) -> fmt::Result {
375
12
        buffer.write_char('\'')?;
376
12
        escape_string_char(*self, buffer)?;
377
12
        buffer.write_char('\'')
378
12
    }
379
}
380

            
381
#[rustfmt::skip]
382
static DEFAULT_STRING_ESCAPE_HANDLING: [Option<&'static str>; 128] = [
383
    // 0x0         1              2              3              4              5              6              7
384
    Some("\\0"),   Some("\\x01"), Some("\\x02"), Some("\\x03"), Some("\\x04"), Some("\\x05"), Some("\\x06"), Some("\\x07"),
385
    // 0x8         9              A              B              C              D              E              F
386
    Some("\\x08"), Some("\\t"),   Some("\\n"),   Some("\\x0b"), Some("\\x0c"), Some("\\r"),   Some("\\x0e"), Some("\\x0f"),
387
    // 0x10
388
    Some("\\x10"), Some("\\x11"), Some("\\x12"), Some("\\x13"), Some("\\x14"), Some("\\x15"), Some("\\x16"), Some("\\x17"),
389
    Some("\\x18"), Some("\\x19"), Some("\\x1a"), Some("\\x1b"), Some("\\x1c"), Some("\\x1d"), Some("\\x1e"), Some("\\x1f"),
390
    // 0x20
391
    None,          None,          Some("\\\""),  None,          None,          None,          None,          None,
392
    None,          None,          None,          None,          None,          None,          None,          None,
393
    // 0x30
394
    None,          None,          None,          None,          None,          None,          None,          None,
395
    None,          None,          None,          None,          None,          None,          None,          None,
396
    // 0x40
397
    None,          None,          None,          None,          None,          None,          None,          None,
398
    None,          None,          None,          None,          None,          None,          None,          None,
399
    // 0x50
400
    None,          None,          None,          None,          None,          None,          None,          None,
401
    None,          None,          None,          None,          Some("\\\\"),  None,          None,          None,
402
    // 0x60
403
    None,          None,          None,          None,          None,          None,          None,          None,
404
    None,          None,          None,          None,          None,          None,          None,          None,
405
    // 0x70
406
    None,          None,          None,          None,          None,          None,          None,          None,
407
    None,          None,          None,          None,          None,          None,          None,          Some("\\x7f"),
408
];
409

            
410
#[derive(Debug)]
411
enum NestedState {
412
    Tuple(SequenceState),
413
    List(SequenceState),
414
    Map(MapState),
415
}
416

            
417
#[derive(Debug)]
418
enum SequenceState {
419
    Empty,
420
    NotEmpty,
421
}
422

            
423
#[derive(Debug)]
424
enum MapState {
425
    Empty,
426
    AfterEntry,
427
    AfterKey,
428
}
429

            
430
/// A writer configuration.
431
#[derive(Debug, Default, Clone)]
432
#[non_exhaustive]
433
pub enum Config {
434
    /// Renders Rsn in its most compact representation.
435
    #[default]
436
    Compact,
437
    /// Renders Rsn with indentation and line endings.
438
    Pretty {
439
        /// The indentation to include for each level of nested data type.
440
        indentation: Cow<'static, str>,
441
        /// The newline character(s) to include when wrapping to a new line.
442
        newline: Cow<'static, str>,
443
    },
444
}
445

            
446
#[test]
447
1
fn string_rendering() {
448
    use crate::tokenizer::{Token, TokenKind, Tokenizer};
449
1
    let mut to_encode = String::new();
450
129
    for ch in 0_u8..128 {
451
128
        to_encode.push(ch as char);
452
128
    }
453
1
    to_encode.write_char('\u{1_F980}').unwrap();
454
1
    let mut rendered = String::new();
455
1
    to_encode.render_to(&mut rendered).unwrap();
456
1
    assert_eq!(
457
1
        rendered,
458
1
        "\"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f🦀\""
459
1
    );
460
    let Some(Ok(Token {
461
1
        kind: TokenKind::String(parsed),
462
        ..
463
1
    })) = Tokenizer::full(&rendered).next()
464
    else {
465
        unreachable!("failed to parse rendered string")
466
    };
467
1
    assert_eq!(parsed, to_encode);
468
1
}
469

            
470
#[test]
471
1
fn byte_rendering() {
472
    use crate::tokenizer::{Token, TokenKind, Tokenizer};
473
1
    let mut to_encode = Vec::new();
474
256
    for ch in 0_u8..255 {
475
255
        to_encode.push(ch);
476
255
    }
477
1
    let mut rendered = String::new();
478
1
    to_encode.render_to(&mut rendered).unwrap();
479
1
    assert_eq!(
480
1
        rendered,
481
1
        "b\"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\""
482
1
    );
483
    let Some(Ok(Token {
484
1
        kind: TokenKind::Bytes(parsed),
485
        ..
486
1
    })) = Tokenizer::full(&rendered).next()
487
    else {
488
        unreachable!("failed to parse rendered bytes")
489
    };
490
1
    assert_eq!(parsed, to_encode);
491
1
}