Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_jdat/src/string/enc.rs

49.0 KiB, 28 runs

created by r1870400018:487, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 prelude::*,
3 usr::{
4 UsrKind,
5 UsrKinds,
6 UsrKindId,
7 UsrKindCode,
8 },
9 int::DatInt,
10 kind::KindCase,
11};
12
13use oxedyne_fe2o3_core::{
14 prelude::*,
15 map::MapMut,
16};
17use oxedyne_fe2o3_num::{
18 float::{
19 Float32,
20 Float64,
21 },
22};
23use oxedyne_fe2o3_text::{
24 base2x,
25 string::{
26 Indenter,
27 Stringer,
28 },
29};
30
31use std::{
32 collections::BTreeMap,
33 fmt,
34};
35
36
37/// Escape the reserved characters in a string literal so it can
38/// be safely embedded between `"..."` in a JDAT or JSON document.
39///
40/// Implements RFC 8259 §7: `"`, `\`, the C0 control characters
41/// U+0000..U+001F, and U+007F (DEL for safety) are escaped. All
42/// other characters -- including all non-ASCII UTF-8 -- are
43/// passed through unchanged, so a string containing `'` or `’`
44/// or an emoji round-trips as raw bytes rather than as
45/// `\u0027` / `\u2019` / a surrogate pair.
46///
47/// This is the inverse of the decoder's `handle_string_escape`
48/// path (which accepts both raw characters and escapes on input),
49/// and round-tripping a decoded Dat through the encoder and back
50/// is a fixed point after the first pass.
51pub fn escape_json_string(s: &str) -> String {
52 let mut out = String::with_capacity(s.len());
53 for c in s.chars() {
54 match c {
55 '"' => out.push_str("\\\""),
56 '\\' => out.push_str("\\\\"),
57 '\u{0008}' => out.push_str("\\b"),
58 '\u{000C}' => out.push_str("\\f"),
59 '\n' => out.push_str("\\n"),
60 '\r' => out.push_str("\\r"),
61 '\t' => out.push_str("\\t"),
62 c if (c as u32) < 0x20 || (c as u32) == 0x7f => {
63 // Other C0 controls and DEL: hex-escape.
64 out.push_str(&fmt!("\\u{:04x}", c as u32));
65 }
66 c => out.push(c),
67 }
68 }
69 out
70}
71
72
73/// Except for the addition of trailing commas and some explicit kindicles like (omap|, this is
74/// essentially JSON format.
75impl fmt::Display for Dat {
76 fn fmt (&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 match self.encode_string_with_config(&EncoderConfig::<(), ()>::display(None)) {
78 Ok(s) => write!(f, "{}", s),
79 Err(e) => write!(f, "{}", e),
80 }
81 }
82}
83
84/// This is essentially JDAT format, but with capitalised types which signals that
85/// `fmt::Debug` formatting was used.
86impl fmt::Debug for Dat {
87 fn fmt (&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 match self.encode_string_with_config(&EncoderConfig::<(), ()>::debug(None)) {
89 Ok(s) => write!(f, "{}", s),
90 Err(e) => write!(f, "{}", e),
91 }
92 }
93}
94
95/// Controls the visibility of type information (kindicles) during encoding.
96///
97/// # Variants
98///
99/// ## `Nothing`
100/// - Used primarily in JSON-compatible mode
101/// - Shows kindicles only for `AtomLogic` types (Empty, True, False, None)
102/// - Suppresses all other type information
103/// - Examples:
104/// - `42` instead of `(u8|42)`
105/// - `"text"` instead of `(str|"text")`
106/// - Special handling of ABox comments: displays as strings with comment markers
107///
108/// ## `Some`
109/// Shows kindicles for:
110/// - Atomic Logic types (Empty, True, False, None)
111/// - Molecule Unitary types (Usr, Box, Some, ABox)
112/// - Tuples (Tup2-Tup10)
113///
114/// Hides kindicles for:
115/// - All Atomic Fixed types (integers, floats)
116/// - All Atomic Variable types (including strings)
117/// - Lists, Maps, and their ordered variants
118/// - All Molecule Same types (homogeneous collections like Vek, byte arrays)
119///
120/// Used by
121///
122/// ## `Most`
123/// The default scope.
124///
125/// Hides kindicles only for:
126/// - Strings (shows as `"text"` instead of `(str|"text")`)
127/// - Maps (shows as `{...}` instead of `(map|{...})`)
128/// - Lists (shows as `[...]` instead of `(list|[...])`)
129///
130/// Shows kindicles for all other types.
131///
132/// ## `Everything`
133/// - Shows kindicles for all types without exception
134/// - Used in debug mode
135/// - Most verbose output format
136/// - Examples:
137/// - `(str|"text")`
138/// - `(map|{...})`
139/// - `(list|[...])`
140/// - ABox comments shown in full `(abox|data !comment!)` format
141///
142/// # Notes
143///
144/// - The `hide_usr_types` config flag can override the display of user-defined type kindicles
145/// regardless of scope
146/// - ABox (annotated box) types have special comment display handling based on scope:
147/// - Everything: Full `(abox|data !comment!)` format
148/// - Nothing: Comments as strings with comment markers
149/// - Other modes: Data with trailing comment
150///
151/// # Kindicle Visibility Reference Table
152///
153/// | | Nothing | Some | Most | Everything |
154/// | ------------------------- | ------- | ---- | ---- | ---------- |
155/// | AtomLogic | | | | |
156/// | Empty,True,False,None | ✓ | ✓ | ✓ | ✓ |
157/// | AtomFixed | | | | |
158/// | U8-U128,I8-I128,F32/64 | ✗ | ✗ | ✓ | ✓ |
159/// | | | | | |
160/// | AtomVariable (except Str) | | | | |
161/// | Aint,Adec,C64 | ✗ | ✗ | ✓ | ✓ |
162/// | | | | | |
163/// | Str (special case) | ✗ | ✗ | ✗ | ✓ |
164/// | | | | | |
165/// | MoleculeUnitary | | | | |
166/// | Usr,Box,Some,ABox | ✗ | ✓ | ✓ | ✓ |
167/// | | | | | |
168/// | MoleculeMixed | | | | |
169/// | Tup2-10 | ✗ | ✓ | ✓ | ✓ |
170/// | Map | ✗ | ✗ | ✗ | ✓ |
171/// | List | ✗ | ✗ | ✗ | ✓ |
172/// | | | | | |
173/// | MoleculeSame | | | | |
174/// | Vek,BU8-64,B2-32,etc | ✗ | ✗ | ✓ | ✓ |
175///
176/// This enum provides a hierarchical system for controlling type information visibility
177/// while maintaining data readability, ranging from JSON-compatible output to fully typed
178/// JDAT format.
179#[derive(Clone, Debug, PartialEq, PartialOrd)]
180pub enum KindScope {
181 Nothing,
182 Some,
183 Most,
184 Everything,
185}
186
187#[derive(Clone, Debug, PartialEq)]
188pub enum ByteEncoding {
189 Base2x,
190 Binary,
191 Decimal,
192 Hex,
193 Octal,
194}
195
196#[derive(Clone, Debug, PartialEq)]
197pub enum IntEncoding {
198 Binary,
199 Decimal,
200 Hex,
201 Octal,
202}
203
204#[derive(Clone, Debug)]
205pub struct EncoderConfig<
206 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
207 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
208>{
209 pub kind_scope: KindScope,
210 pub type_lower_case: bool,
211 pub byte_encoding: ByteEncoding,
212 pub int_encoding: IntEncoding,
213 pub to_lines: bool,
214 pub tab: String,
215 pub trailing_commas: bool,
216 pub hide_usr_types: bool,
217 pub ukinds_opt: Option<UsrKinds<M1, M2>>,
218 pub comment_allowed: bool, // Include Annotated Box comments?
219 pub comment1_start_char: char,
220 pub comment1_end_char: char,
221 pub comment2_start_char: char,
222 pub comment2_end_char: char,
223 /// Encode an absent optional as the `null` literal rather than as the kind
224 /// label.
225 ///
226 /// JDAT writes a missing option as `none`, which is its own keyword and
227 /// round-trips through JDAT's own decoder. JSON has no such keyword: it has
228 /// `null`, and a reader given the string `"none"` instead sees a present
229 /// value whose content happens to be a word. In JavaScript that string is
230 /// truthy, so `if (x.field)` takes the branch for a value that is not there.
231 /// Set for the JSON presets and left off elsewhere, so JDAT output is
232 /// unchanged. It applies to `Opt` alone: a user kind carrying no value
233 /// encodes as its own label, which names the kind and is not the same
234 /// statement as "there is nothing here".
235 pub none_as_null: bool,
236}
237
238impl<
239 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
240 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
241>
242 Default for EncoderConfig<M1, M2>
243{
244 fn default() -> Self {
245 Self {
246 kind_scope: KindScope::Most,
247 type_lower_case: true,
248 byte_encoding: ByteEncoding::Hex,
249 int_encoding: IntEncoding::Decimal,
250 to_lines: false,
251 tab: fmt!(" "),
252 trailing_commas: false,
253 hide_usr_types: false,
254 ukinds_opt: None,
255 comment_allowed: true,
256 comment1_start_char: '!',
257 comment1_end_char: '!',
258 comment2_start_char: '#',
259 comment2_end_char: '#',
260 none_as_null: false,
261 }
262 }
263}
264
265impl<
266 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
267 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
268>
269 EncoderConfig<M1, M2>
270{
271 pub fn debug(ukinds_opt: Option<UsrKinds<M1, M2>>) -> Self {
272 Self {
273 kind_scope: KindScope::Everything,
274 type_lower_case: true,
275 byte_encoding: ByteEncoding::Decimal,
276 trailing_commas: true,
277 ukinds_opt,
278 ..Default::default()
279 }
280 }
281
282 pub fn debug_to_lines(ukinds_opt: Option<UsrKinds<M1, M2>>, tab: &str) -> Self {
283 let mut result = Self::debug(ukinds_opt);
284 result.to_lines = true;
285 result.tab = tab.to_string();
286 result
287 }
288
289 pub fn display(ukinds_opt: Option<UsrKinds<M1, M2>>) -> Self {
290 Self {
291 kind_scope: KindScope::Most,
292 type_lower_case: true,
293 byte_encoding: ByteEncoding::Decimal,
294 ukinds_opt,
295 ..Default::default()
296 }
297 }
298
299 pub fn display_to_lines(ukinds_opt: Option<UsrKinds<M1, M2>>, tab: &str) -> Self {
300 let mut result = Self::display(ukinds_opt);
301 result.to_lines = true;
302 result.tab = tab.to_string();
303 result
304 }
305
306 pub fn display_some(ukinds_opt: Option<UsrKinds<M1, M2>>) -> Self {
307 Self {
308 kind_scope: KindScope::Some,
309 type_lower_case: true,
310 byte_encoding: ByteEncoding::Decimal,
311 ukinds_opt,
312 ..Default::default()
313 }
314 }
315
316 pub fn display_some_to_lines(ukinds_opt: Option<UsrKinds<M1, M2>>, tab: &str) -> Self {
317 let mut result = Self::display_some(ukinds_opt);
318 result.to_lines = true;
319 result.tab = tab.to_string();
320 result
321 }
322
323 pub fn jdat(ukinds_opt: Option<UsrKinds<M1, M2>>) -> Self {
324 Self {
325 kind_scope: KindScope::Most,
326 byte_encoding: ByteEncoding::Base2x,
327 trailing_commas: true,
328 ukinds_opt,
329 ..Default::default()
330 }
331 }
332
333 pub fn jdat_to_lines(ukinds_opt: Option<UsrKinds<M1, M2>>, tab: &str) -> Self {
334 let mut result = Self::jdat(ukinds_opt);
335 result.to_lines = true;
336 result.tab = tab.to_string();
337 result
338 }
339
340 pub fn jdat_full(ukinds_opt: Option<UsrKinds<M1, M2>>) -> Self {
341 Self {
342 kind_scope: KindScope::Everything,
343 byte_encoding: ByteEncoding::Base2x,
344 trailing_commas: true,
345 ukinds_opt,
346 ..Default::default()
347 }
348 }
349
350 pub fn jdat_full_to_lines(ukinds_opt: Option<UsrKinds<M1, M2>>, tab: &str) -> Self {
351 let mut result = Self::jdat_full(ukinds_opt);
352 result.to_lines = true;
353 result.tab = tab.to_string();
354 result
355 }
356
357 pub fn json(ukinds_opt: Option<UsrKinds<M1, M2>>) -> Self {
358 Self {
359 kind_scope: KindScope::Nothing,
360 byte_encoding: ByteEncoding::Decimal,
361 ukinds_opt,
362 comment_allowed: false,
363 none_as_null: true,
364 ..Default::default()
365 }
366 }
367
368 pub fn json_to_lines(ukinds_opt: Option<UsrKinds<M1, M2>>, tab: &str) -> Self {
369 let mut result = Self::json(ukinds_opt);
370 result.to_lines = true;
371 result.tab = tab.to_string();
372 result
373 }
374}
375
376#[derive(Clone, Debug, Default)]
377pub struct EncoderState {
378 pub indenter: Indenter,
379}
380
381impl EncoderState {
382
383 pub fn recurse(&self) -> Self {
384 Self {
385 indenter: self.indenter.clone(),
386 ..Default::default()
387 }
388 }
389
390 pub fn inc_indent<
391 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
392 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
393 >(
394 mut self,
395 cfg: &EncoderConfig<M1, M2>,
396 )
397 -> Self
398 {
399 if cfg.to_lines {
400 self.indenter.inc();
401 }
402 self
403 }
404
405 pub fn dec_indent<
406 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
407 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
408 >(
409 mut self,
410 cfg: &EncoderConfig<M1, M2>,
411 )
412 -> Self
413 {
414 if cfg.to_lines {
415 self.indenter.dec();
416 }
417 self
418 }
419}
420
421impl Dat {
422
423 /// Uses `EncoderConfig::debug`, `EncoderConfig::display` and `oxedyne_fe2o3_core::string::Stringer`.
424 pub fn to_lines(&self, tab: &str, print_kinds: bool) -> Vec<String> {
425 let s = if print_kinds {
426 fmt!("{:?}", self)
427 } else {
428 self.to_string()
429 };
430 Stringer::new(s).to_lines(tab)
431 }
432
433 pub fn debug< >(&self) -> Outcome<String> {
434 let cfg = EncoderConfig::<(), ()>::debug(None);
435 self.encode_string_with_config(&cfg)
436 }
437
438 pub fn debug_with_usr_kinds<
439 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
440 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
441 >(
442 &self,
443 ukinds_opt: Option<UsrKinds<M1, M2>>,
444 )
445 -> Outcome<String>
446 {
447 let cfg = EncoderConfig::<M1, M2>::debug(ukinds_opt);
448 self.encode_string_with_config(&cfg)
449 }
450
451 pub fn debug_to_lines(&self, tab: &str) -> Outcome<String> {
452 let cfg = EncoderConfig::<(), ()>::debug_to_lines(None, tab);
453 self.encode_string_with_config(&cfg)
454 }
455
456 pub fn debug_with_usr_kinds_to_lines<
457 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
458 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
459 >(
460 &self,
461 ukinds_opt: Option<UsrKinds<M1, M2>>,
462 tab: &str,
463 )
464 -> Outcome<String>
465 {
466 let cfg = EncoderConfig::<M1, M2>::debug_to_lines(ukinds_opt, tab);
467 self.encode_string_with_config(&cfg)
468 }
469
470 pub fn display(&self) -> Outcome<String> {
471 let cfg = EncoderConfig::<(), ()>::display(None);
472 self.encode_string_with_config(&cfg)
473 }
474
475 pub fn display_with_usr_kinds<
476 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
477 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
478 >(
479 &self,
480 ukinds_opt: Option<UsrKinds<M1, M2>>,
481 )
482 -> Outcome<String>
483 {
484 let cfg = EncoderConfig::<M1, M2>::display(ukinds_opt);
485 self.encode_string_with_config(&cfg)
486 }
487
488 pub fn display_to_lines(&self, tab: &str,) -> Outcome<String> {
489 let cfg = EncoderConfig::<(), ()>::display_to_lines(None, tab);
490 self.encode_string_with_config(&cfg)
491 }
492
493 pub fn display_some_to_lines(&self, tab: &str,) -> Outcome<String> {
494 let cfg = EncoderConfig::<(), ()>::display_some_to_lines(None, tab);
495 self.encode_string_with_config(&cfg)
496 }
497
498 pub fn display_with_usr_kinds_to_lines<
499 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
500 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
501 >(
502 &self,
503 ukinds_opt: Option<UsrKinds<M1, M2>>,
504 tab: &str,
505 )
506 -> Outcome<String>
507 {
508 let cfg = EncoderConfig::<M1, M2>::display_to_lines(ukinds_opt, tab);
509 self.encode_string_with_config(&cfg)
510 }
511
512 pub fn jdat(&self) -> Outcome<String> {
513 let cfg = EncoderConfig::<(), ()>::jdat(None);
514 self.encode_string_with_config(&cfg)
515 }
516
517 pub fn jdat_with_usr_kinds<
518 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
519 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
520 >(
521 &self,
522 ukinds_opt: Option<UsrKinds<M1, M2>>,
523 )
524 -> Outcome<String>
525 {
526 let cfg = EncoderConfig::<M1, M2>::jdat(ukinds_opt);
527 self.encode_string_with_config(&cfg)
528 }
529
530 pub fn jdat_to_lines(&self, tab: &str,) -> Outcome<String> {
531 let cfg = EncoderConfig::<(), ()>::jdat_to_lines(None, tab);
532 self.encode_string_with_config(&cfg)
533 }
534
535 pub fn jdat_with_usr_kinds_to_lines<
536 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
537 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
538 >(
539 &self,
540 ukinds_opt: Option<UsrKinds<M1, M2>>,
541 tab: &str,
542 )
543 -> Outcome<String>
544 {
545 let cfg = EncoderConfig::<M1, M2>::jdat_to_lines(ukinds_opt, tab);
546 self.encode_string_with_config(&cfg)
547 }
548
549 pub fn jdat_full(&self) -> Outcome<String> {
550 let cfg = EncoderConfig::<(), ()>::jdat_full(None);
551 self.encode_string_with_config(&cfg)
552 }
553
554 pub fn jdat_full_with_usr_kinds<
555 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
556 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
557 >(
558 &self,
559 ukinds_opt: Option<UsrKinds<M1, M2>>,
560 )
561 -> Outcome<String>
562 {
563 let cfg = EncoderConfig::<M1, M2>::jdat_full(ukinds_opt);
564 self.encode_string_with_config(&cfg)
565 }
566
567 pub fn jdat_full_to_lines(&self, tab: &str,) -> Outcome<String> {
568 let cfg = EncoderConfig::<(), ()>::jdat_full_to_lines(None, tab);
569 self.encode_string_with_config(&cfg)
570 }
571
572 pub fn jdat_full_with_usr_kinds_to_lines<
573 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
574 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
575 >(
576 &self,
577 ukinds_opt: Option<UsrKinds<M1, M2>>,
578 tab: &str,
579 )
580 -> Outcome<String>
581 {
582 let cfg = EncoderConfig::<M1, M2>::jdat_full_to_lines(ukinds_opt, tab);
583 self.encode_string_with_config(&cfg)
584 }
585
586 pub fn json(&self) -> Outcome<String> {
587 let cfg = EncoderConfig::<(), ()>::json(None);
588 self.encode_string_with_config(&cfg)
589 }
590
591 pub fn json_with_usr_kinds<
592 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
593 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
594 >(
595 &self,
596 ukinds_opt: Option<UsrKinds<M1, M2>>,
597 )
598 -> Outcome<String>
599 {
600 let cfg = EncoderConfig::<M1, M2>::json(ukinds_opt);
601 self.encode_string_with_config(&cfg)
602 }
603
604 pub fn json_to_lines(&self, tab: &str,) -> Outcome<String> {
605 let cfg = EncoderConfig::<(), ()>::json_to_lines(None, tab);
606 self.encode_string_with_config(&cfg)
607 }
608
609 pub fn json_with_usr_kinds_to_lines<
610 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
611 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
612 >(
613 &self,
614 ukinds_opt: Option<UsrKinds<M1, M2>>,
615 tab: &str,
616 )
617 -> Outcome<String>
618 {
619 let cfg = EncoderConfig::<M1, M2>::json_to_lines(ukinds_opt, tab);
620 self.encode_string_with_config(&cfg)
621 }
622
623
624 pub fn encode_string<
625 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
626 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
627 >(
628 &self,
629 )
630 -> Outcome<String>
631 {
632 let cfg = EncoderConfig::<
633 BTreeMap<UsrKindCode, UsrKind>,
634 BTreeMap<String, UsrKindId>,
635 >::default();
636
637 self.encode_string_with_config(&cfg)
638 }
639
640 pub fn encode_string_with_config<
641 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
642 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
643 >(
644 &self,
645 cfg: &EncoderConfig<M1, M2>,
646 )
647 -> Outcome<String>
648 {
649 self.recursive_encode(
650 cfg,
651 EncoderState::default(),
652 )
653 }
654
655 pub fn recursive_encode<
656 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
657 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
658 >(
659 &self,
660 cfg: &EncoderConfig<M1, M2>,
661 mut state: EncoderState,
662 )
663 -> Outcome<String>
664 {
665 let mut typ_str = if
666 (cfg.kind_scope == KindScope::Nothing)
667 && (self.kind().case() != KindCase::AtomLogic)
668 {
669 String::new()
670 } else {
671 if cfg.type_lower_case {
672 self.kind().to_string().to_lowercase()
673 } else {
674 self.kind().to_string().to_uppercase()
675 }
676 };
677 // The following match avoids returning from the method anywhere, except in the case of
678 // Self::ABox.
679 let (s, is_dataless) = match self {
680 // Atomic Kinds ===========================
681 // Logic
682 Self::Empty => (fmt!("\"\""), true),
683 // The value string here is the bare token `true` or `false`,
684 // not the kind name in quotes. In jdat-native modes the
685 // `is_dataless = true` flag triggers the `({typ_str})`
686 // kindicle wrapping below, so the output still emerges as
687 // `(true)` / `(false)`. In JSON mode (`kind_scope: Nothing`),
688 // the `hide_kindicle` branch further down emits `{s}` as-is,
689 // producing the unquoted JSON boolean literal `true` or
690 // `false`. The earlier form `fmt!("\"{}\"", typ_str)` emitted
691 // the value as a quoted string in JSON mode, which Let's
692 // Encrypt's JSON parser correctly rejected as malformed
693 // (`termsOfServiceAgreed` is required to be a boolean, not a
694 // string).
695 Self::Bool(b) => (fmt!("{}", b), true),
696 // Fixed
697 Self::U8(n) => (Self::encode_int(&DatInt::U8(*n), &cfg), false),
698 Self::U16(n) => (Self::encode_int(&DatInt::U16(*n), &cfg), false),
699 Self::U32(n) => (Self::encode_int(&DatInt::U32(*n), &cfg), false),
700 Self::U64(n) |
701 Self::C64(n) => (Self::encode_int(&DatInt::U64(*n), &cfg), false),
702 Self::U128(n) => (Self::encode_int(&DatInt::U128(*n), &cfg), false),
703 Self::I8(n) => (Self::encode_int(&DatInt::I8(*n), &cfg), false),
704 Self::I16(n) => (Self::encode_int(&DatInt::I16(*n), &cfg), false),
705 Self::I32(n) => (Self::encode_int(&DatInt::I32(*n), &cfg), false),
706 Self::I64(n) => (Self::encode_int(&DatInt::I64(*n), &cfg), false),
707 Self::I128(n) => (Self::encode_int(&DatInt::I128(*n), &cfg), false),
708 Self::F32(Float32(v)) => {
709 let native = fmt!("{:e}", v);
710 let native_with_decimal = if !native.contains('.') {
711 native.replace("e", ".0e")
712 } else {
713 native
714 };
715 (native_with_decimal, false)
716 }
717 Self::F64(Float64(v)) => {
718 let native = fmt!("{:e}", v);
719 let native_with_decimal = if !native.contains('.') {
720 native.replace("e", ".0e")
721 } else {
722 native
723 };
724 (native_with_decimal, false)
725 }
726 // Variable
727 Self::Aint(n) => (fmt!("{}", n), false),
728 Self::Adec(n) => {
729 let (bint, expi64) = n.as_bigint_and_exponent();
730 (fmt!("{}e{}", bint, -expi64), false)
731 }
732 Self::Str(s) => (fmt!("\"{}\"", escape_json_string(s)), false),
733 // Molecule Kinds =========================
734 // Unitary
735 Self::Usr(ukid, optboxd) => {
736 typ_str = ukid.label().to_string();
737 if let Some(ukinds) = &cfg.ukinds_opt {
738 // If a UsrKinds has been given it can override the string label.
739 if let Some(ukid2) = ukinds.get_code(&ukid.code()) {
740 typ_str = ukid2.label().to_string();
741 }
742 }
743 match optboxd {
744 None => (fmt!("\"\""), true),
745 Some(boxd) => (fmt!("{}", res!(boxd.recursive_encode(&cfg, state.recurse()))), false)
746 }
747 }
748 Self::Box(d) => (fmt!("{}", res!(d.recursive_encode(&cfg, state.recurse()))), false),
749 Self::Opt(boxoptd) => {
750 match &**boxoptd {
751 None if cfg.none_as_null => (fmt!("null"), false),
752 None => (fmt!("\"{}\"", typ_str), true),
753 Some(d) => (fmt!("{}", res!(d.recursive_encode(&cfg, state.recurse()))), false),
754 }
755 }
756 Self::ABox(ncfg, d, s) => {
757 // Kindicle wrapping dealt with with specially here before exit, unlike all other
758 // kinds.
759 let (start_char, end_char) = if ncfg.is_type1() {
760 (cfg.comment1_start_char, cfg.comment1_end_char)
761 } else {
762 (cfg.comment2_start_char, cfg.comment2_end_char)
763 };
764 return Ok(match cfg.kind_scope {
765 KindScope::Everything => {
766 // Bias toward a reluctance to show the (abox| kindicle.
767 fmt!(
768 "({}|{} {}{}{})",
769 typ_str,
770 res!(d.recursive_encode(&cfg, state.recurse())),
771 start_char,
772 s,
773 end_char,
774 )
775 }
776 KindScope::Nothing => {
777 // Display the comment as a plain string, but wrap it in the comment
778 // characters so that a reader can identify it as a comment.
779 if **d == Dat::Empty {
780 fmt!(
781 "\"{}{}{}\"",
782 start_char,
783 s,
784 end_char,
785 )
786
787 } else {
788 // Don't throw out comment, package it with the data in a list,
789 // including the comment characters.
790 fmt!(
791 "[{}, \"{}{}{}\"{}]",
792 res!(d.recursive_encode(&cfg, state.recurse())),
793 start_char,
794 s,
795 end_char,
796 if cfg.trailing_commas { ", " } else { "" },
797 )
798 }
799 }
800 _ => {
801 if **d == Dat::Empty {
802 fmt!(
803 "{}{}{}",
804 start_char,
805 s,
806 end_char,
807 )
808
809 } else {
810 fmt!(
811 "{} {}{}{}",
812 res!(d.recursive_encode(&cfg, state.recurse())),
813 start_char,
814 s,
815 end_char,
816 )
817 }
818 }
819 });
820 }
821 // Heterogenous
822 Self::List(list) => res!(Self::encode_list(list.as_slice(), &cfg, &mut state)),
823 Self::Tup2(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
824 Self::Tup3(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
825 Self::Tup4(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
826 Self::Tup5(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
827 Self::Tup6(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
828 Self::Tup7(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
829 Self::Tup8(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
830 Self::Tup9(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
831 Self::Tup10(arr) => res!(Self::encode_list(&arr[..], &cfg, &mut state)),
832 Self::Map(m) => {
833 if m.len() == 0 {
834 (fmt!("{{}}"), false)
835 } else {
836 let mut s = String::new();
837 let last = m.len() - 1;
838 let (indent0, indent, sep, sep_last) = Self::collection_encoding(
839 &cfg,
840 &mut state,
841 );
842 for (i, (k, v)) in m.iter().enumerate() {
843 res!(Self::encode_map_entry(
844 (k, v),
845 &mut s,
846 &cfg,
847 &mut state,
848 &indent,
849 &sep,
850 &sep_last,
851 i == last,
852 ));
853 }
854 (
855 fmt!("{{{}{}{}}}",
856 if cfg.to_lines { "\n" } else { " " },
857 s,
858 indent0,
859 ),
860 false,
861 )
862 }
863 }
864 Self::OrdMap(m) => {
865 if m.len() == 0 {
866 (fmt!("{{}}"), false)
867 } else {
868 let mut s = String::new();
869 let last = m.len() - 1;
870 let (indent0, indent, sep, sep_last) = Self::collection_encoding(
871 &cfg,
872 &mut state,
873 );
874 for (i, (mk, v)) in m.iter().enumerate() {
875 let k = mk.dat();
876 res!(Self::encode_map_entry(
877 (k, v),
878 &mut s,
879 &cfg,
880 &mut state,
881 &indent,
882 &sep,
883 &sep_last,
884 i == last,
885 ));
886 }
887 (
888 fmt!("{{{}{}{}}}",
889 if cfg.to_lines { "\n" } else { " " },
890 s,
891 indent0,
892 ),
893 false,
894 )
895 }
896 }
897 // Homogenous
898 Self::Vek(vek) => res!(Self::encode_list(vek.as_slice(), &cfg, &mut state)),
899 // Byte arrays
900 // Variable length bytes
901 Self::BU8(v) |
902 Self::BU16(v) |
903 Self::BU32(v) |
904 Self::BU64(v) |
905 Self::BC64(v) => (Self::encode_bytes(&v, &cfg), false),
906 // Fixed length bytes
907 Self::B2(a) => (Self::encode_bytes(&a[..], &cfg), false),
908 Self::B3(a) => (Self::encode_bytes(&a[..], &cfg), false),
909 Self::B4(a) => (Self::encode_bytes(&a[..], &cfg), false),
910 Self::B5(a) => (Self::encode_bytes(&a[..], &cfg), false),
911 Self::B6(a) => (Self::encode_bytes(&a[..], &cfg), false),
912 Self::B7(a) => (Self::encode_bytes(&a[..], &cfg), false),
913 Self::B8(a) => (Self::encode_bytes(&a[..], &cfg), false),
914 Self::B9(a) => (Self::encode_bytes(&a[..], &cfg), false),
915 Self::B10(a) => (Self::encode_bytes(&a[..], &cfg), false),
916 Self::B16(a) => (Self::encode_bytes(&a[..], &cfg), false),
917 Self::B32(a) => (Self::encode_bytes(&a[..], &cfg), false),
918 // Fixed length numbers
919 Self::Tup2u8(a) => (Self::encode_ints(&a[..], &cfg), false),
920 Self::Tup3u8(a) => (Self::encode_ints(&a[..], &cfg), false),
921 Self::Tup4u8(a) => (Self::encode_ints(&a[..], &cfg), false),
922 Self::Tup5u8(a) => (Self::encode_ints(&a[..], &cfg), false),
923 Self::Tup6u8(a) => (Self::encode_ints(&a[..], &cfg), false),
924 Self::Tup7u8(a) => (Self::encode_ints(&a[..], &cfg), false),
925 Self::Tup8u8(a) => (Self::encode_ints(&a[..], &cfg), false),
926 Self::Tup9u8(a) => (Self::encode_ints(&a[..], &cfg), false),
927 Self::Tup10u8(a) => (Self::encode_ints(&a[..], &cfg), false),
928 Self::Tup2u16(a) => (Self::encode_ints(&a[..], &cfg), false),
929 Self::Tup3u16(a) => (Self::encode_ints(&a[..], &cfg), false),
930 Self::Tup4u16(a) => (Self::encode_ints(&a[..], &cfg), false),
931 Self::Tup5u16(a) => (Self::encode_ints(&a[..], &cfg), false),
932 Self::Tup6u16(a) => (Self::encode_ints(&a[..], &cfg), false),
933 Self::Tup7u16(a) => (Self::encode_ints(&a[..], &cfg), false),
934 Self::Tup8u16(a) => (Self::encode_ints(&a[..], &cfg), false),
935 Self::Tup9u16(a) => (Self::encode_ints(&a[..], &cfg), false),
936 Self::Tup10u16(a) => (Self::encode_ints(&a[..], &cfg), false),
937 Self::Tup2u32(a) => (Self::encode_ints(&a[..], &cfg), false),
938 Self::Tup3u32(a) => (Self::encode_ints(&a[..], &cfg), false),
939 Self::Tup4u32(a) => (Self::encode_ints(&a[..], &cfg), false),
940 Self::Tup5u32(a) => (Self::encode_ints(&a[..], &cfg), false),
941 Self::Tup6u32(a) => (Self::encode_ints(&a[..], &cfg), false),
942 Self::Tup7u32(a) => (Self::encode_ints(&a[..], &cfg), false),
943 Self::Tup8u32(a) => (Self::encode_ints(&a[..], &cfg), false),
944 Self::Tup9u32(a) => (Self::encode_ints(&a[..], &cfg), false),
945 Self::Tup10u32(a) => (Self::encode_ints(&a[..], &cfg), false),
946 Self::Tup2u64(a) => (Self::encode_ints(&a[..], &cfg), false),
947 Self::Tup3u64(a) => (Self::encode_ints(&a[..], &cfg), false),
948 Self::Tup4u64(a) => (Self::encode_ints(&a[..], &cfg), false),
949 Self::Tup5u64(a) => (Self::encode_ints(&a[..], &cfg), false),
950 Self::Tup6u64(a) => (Self::encode_ints(&a[..], &cfg), false),
951 Self::Tup7u64(a) => (Self::encode_ints(&a[..], &cfg), false),
952 Self::Tup8u64(a) => (Self::encode_ints(&a[..], &cfg), false),
953 Self::Tup9u64(a) => (Self::encode_ints(&a[..], &cfg), false),
954 Self::Tup10u64(a) => (Self::encode_ints(&a[..], &cfg), false),
955 Self::Tup2i8(a) => (Self::encode_ints(&a[..], &cfg), false),
956 Self::Tup3i8(a) => (Self::encode_ints(&a[..], &cfg), false),
957 Self::Tup4i8(a) => (Self::encode_ints(&a[..], &cfg), false),
958 Self::Tup5i8(a) => (Self::encode_ints(&a[..], &cfg), false),
959 Self::Tup6i8(a) => (Self::encode_ints(&a[..], &cfg), false),
960 Self::Tup7i8(a) => (Self::encode_ints(&a[..], &cfg), false),
961 Self::Tup8i8(a) => (Self::encode_ints(&a[..], &cfg), false),
962 Self::Tup9i8(a) => (Self::encode_ints(&a[..], &cfg), false),
963 Self::Tup10i8(a) => (Self::encode_ints(&a[..], &cfg), false),
964 Self::Tup2i16(a) => (Self::encode_ints(&a[..], &cfg), false),
965 Self::Tup3i16(a) => (Self::encode_ints(&a[..], &cfg), false),
966 Self::Tup4i16(a) => (Self::encode_ints(&a[..], &cfg), false),
967 Self::Tup5i16(a) => (Self::encode_ints(&a[..], &cfg), false),
968 Self::Tup6i16(a) => (Self::encode_ints(&a[..], &cfg), false),
969 Self::Tup7i16(a) => (Self::encode_ints(&a[..], &cfg), false),
970 Self::Tup8i16(a) => (Self::encode_ints(&a[..], &cfg), false),
971 Self::Tup9i16(a) => (Self::encode_ints(&a[..], &cfg), false),
972 Self::Tup10i16(a) => (Self::encode_ints(&a[..], &cfg), false),
973 Self::Tup2i32(a) => (Self::encode_ints(&a[..], &cfg), false),
974 Self::Tup3i32(a) => (Self::encode_ints(&a[..], &cfg), false),
975 Self::Tup4i32(a) => (Self::encode_ints(&a[..], &cfg), false),
976 Self::Tup5i32(a) => (Self::encode_ints(&a[..], &cfg), false),
977 Self::Tup6i32(a) => (Self::encode_ints(&a[..], &cfg), false),
978 Self::Tup7i32(a) => (Self::encode_ints(&a[..], &cfg), false),
979 Self::Tup8i32(a) => (Self::encode_ints(&a[..], &cfg), false),
980 Self::Tup9i32(a) => (Self::encode_ints(&a[..], &cfg), false),
981 Self::Tup10i32(a) => (Self::encode_ints(&a[..], &cfg), false),
982 Self::Tup2i64(a) => (Self::encode_ints(&a[..], &cfg), false),
983 Self::Tup3i64(a) => (Self::encode_ints(&a[..], &cfg), false),
984 Self::Tup4i64(a) => (Self::encode_ints(&a[..], &cfg), false),
985 Self::Tup5i64(a) => (Self::encode_ints(&a[..], &cfg), false),
986 Self::Tup6i64(a) => (Self::encode_ints(&a[..], &cfg), false),
987 Self::Tup7i64(a) => (Self::encode_ints(&a[..], &cfg), false),
988 Self::Tup8i64(a) => (Self::encode_ints(&a[..], &cfg), false),
989 Self::Tup9i64(a) => (Self::encode_ints(&a[..], &cfg), false),
990 Self::Tup10i64(a) => (Self::encode_ints(&a[..], &cfg), false),
991 };
992 let kind = self.kind();
993 if kind.is_usr() && cfg.hide_usr_types {
994 return Ok(if is_dataless {
995 fmt!("\"{}\"", typ_str)
996 } else {
997 fmt!("{}", s)
998 });
999 }
1000 let hide_kindicle =
1001 cfg.kind_scope == KindScope::Nothing
1002 || (cfg.kind_scope == KindScope::Some &&
1003 match kind {
1004 Kind::Str | Kind::Map | Kind::List => true,
1005 _ => {
1006 match kind.case() {
1007 KindCase::AtomFixed |
1008 KindCase::AtomVariable |
1009 KindCase::MoleculeSame => true,
1010 _ => false,
1011 }
1012 }
1013 }
1014 )
1015 || (cfg.kind_scope == KindScope::Most &&
1016 match kind { // Don't show kindicles for strings, maps, and lists.
1017 Kind::Str | Kind::Map | Kind::List => true,
1018 _ => false,
1019 }
1020 );
1021 Ok(if hide_kindicle {
1022 if is_dataless && kind.is_usr() {
1023 // Special case of usr kinds carrying data in json format, e.g.
1024 // jdat: (my_kind)
1025 // json: "my_kind"
1026 fmt!("\"{}\"", typ_str)
1027 } else {
1028 fmt!("{}", s)
1029 }
1030 } else {
1031 if is_dataless {
1032 fmt!("({})", typ_str)
1033 } else {
1034 fmt!("({}|{})", typ_str, s)
1035 }
1036 })
1037 }
1038
1039 pub fn encode_bytes<
1040 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
1041 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
1042 >(
1043 byts: &[u8],
1044 cfg: &EncoderConfig<M1, M2>,
1045 )
1046 -> String
1047 {
1048 if cfg.trailing_commas {
1049 match cfg.byte_encoding {
1050 ByteEncoding::Base2x => fmt!("\"{}\"", base2x::HEMATITE64.to_string(&byts)),
1051 ByteEncoding::Binary => fmt!("[{}]", byts.iter().map(|b| fmt!("{}, ", DatInt::U8(*b).fmt_bin()))
1052 .collect::<Vec<String>>().join("")),
1053 ByteEncoding::Decimal => fmt!("[{}]", byts.iter().map(|b| fmt!("{}, ", DatInt::U8(*b).fmt_dec()))
1054 .collect::<Vec<String>>().join("")),
1055 ByteEncoding::Hex => fmt!("[{}]", byts.iter().map(|b| fmt!("{}, ", DatInt::U8(*b).fmt_hex()))
1056 .collect::<Vec<String>>().join("")),
1057 ByteEncoding::Octal => fmt!("[{}]", byts.iter().map(|b| fmt!("{}, ", DatInt::U8(*b).fmt_oct()))
1058 .collect::<Vec<String>>().join("")),
1059 }
1060 } else {
1061 match cfg.byte_encoding {
1062 ByteEncoding::Base2x => fmt!("\"{}\"", base2x::HEMATITE64.to_string(&byts)),
1063 ByteEncoding::Binary => fmt!("[{}]", byts.iter().map(|b| DatInt::U8(*b).fmt_bin())
1064 .collect::<Vec<String>>().join(", ")),
1065 ByteEncoding::Decimal => fmt!("[{}]", byts.iter().map(|b| DatInt::U8(*b).fmt_dec())
1066 .collect::<Vec<String>>().join(", ")),
1067 ByteEncoding::Hex => fmt!("[{}]", byts.iter().map(|b| DatInt::U8(*b).fmt_hex())
1068 .collect::<Vec<String>>().join(", ")),
1069 ByteEncoding::Octal => fmt!("[{}]", byts.iter().map(|b| DatInt::U8(*b).fmt_oct())
1070 .collect::<Vec<String>>().join(", ")),
1071 }
1072 }
1073 }
1074
1075 pub fn encode_int<
1076 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
1077 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
1078 >(
1079 n: &DatInt,
1080 cfg: &EncoderConfig<M1, M2>,
1081 )
1082 -> String
1083 {
1084 match cfg.int_encoding {
1085 IntEncoding::Binary => n.fmt_bin(),
1086 IntEncoding::Decimal => n.fmt_dec(),
1087 IntEncoding::Octal => n.fmt_oct(),
1088 IntEncoding::Hex => n.fmt_hex(),
1089 }
1090 }
1091
1092 pub fn encode_ints<
1093 T: Into<DatInt> + Copy,
1094 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
1095 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
1096 >(
1097 a: &[T],
1098 cfg: &EncoderConfig<M1, M2>,
1099 )
1100 -> String
1101 {
1102 if cfg.trailing_commas {
1103 match cfg.int_encoding {
1104 IntEncoding::Binary => fmt!("[{}]", a.iter().map(|n| fmt!("{}, ", (*n).into().fmt_bin()))
1105 .collect::<Vec<String>>().join("")),
1106 IntEncoding::Decimal => fmt!("[{}]", a.iter().map(|n| fmt!("{}, ", (*n).into().fmt_dec()))
1107 .collect::<Vec<String>>().join("")),
1108 IntEncoding::Hex => fmt!("[{}]", a.iter().map(|n| fmt!("{}, ", (*n).into().fmt_hex()))
1109 .collect::<Vec<String>>().join("")),
1110 IntEncoding::Octal => fmt!("[{}]", a.iter().map(|n| fmt!("{}, ", (*n).into().fmt_oct()))
1111 .collect::<Vec<String>>().join("")),
1112 }
1113 } else {
1114 match cfg.int_encoding {
1115 IntEncoding::Binary => fmt!("[{}]", a.iter().map(|n| (*n).into().fmt_bin())
1116 .collect::<Vec<String>>().join(", ")),
1117 IntEncoding::Decimal => fmt!("[{}]", a.iter().map(|n| (*n).into().fmt_dec())
1118 .collect::<Vec<String>>().join(", ")),
1119 IntEncoding::Hex => fmt!("[{}]", a.iter().map(|n| (*n).into().fmt_hex())
1120 .collect::<Vec<String>>().join(", ")),
1121 IntEncoding::Octal => fmt!("[{}]", a.iter().map(|n| (*n).into().fmt_oct())
1122 .collect::<Vec<String>>().join(", ")),
1123 }
1124 }
1125 }
1126
1127 pub fn encode_map_entry<
1128 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
1129 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
1130 >(
1131 (k, v): (&Dat, &Dat),
1132 s: &mut String,
1133 cfg: &EncoderConfig<M1, M2>,
1134 state: &mut EncoderState,
1135 indent: &String,
1136 sep: &String,
1137 sep_last: &String,
1138 is_last: bool,
1139 )
1140 -> Outcome<()>
1141 {
1142 if cfg.to_lines
1143 && cfg.comment_allowed
1144 && cfg.kind_scope != KindScope::Everything
1145 && (k.kind().is_abox() || v.kind().is_abox())
1146 {
1147 // Special case of abox annotation to end of line.
1148 if !k.kind().is_abox() {
1149 // :! A comment\n i.e. () => abox!((), "A comment")
1150 if let Dat::ABox(ncfg, boxdat, comment) = v {
1151 if boxdat.kind() == Kind::Empty {
1152 let key_str = if k.kind() == Kind::Empty {
1153 fmt!("")
1154 } else {
1155 res!(k.recursive_encode(&cfg, state.clone()))
1156 };
1157 s.push_str(&fmt!("{}{}:{} {}\n",
1158 indent,
1159 key_str,
1160 if ncfg.is_type1() {
1161 cfg.comment1_start_char
1162 } else {
1163 cfg.comment2_start_char
1164 },
1165 comment,
1166 ));
1167 }
1168 }
1169 } else if !v.kind().is_abox() {
1170 // ! A comment\n i.e. abox!((), "A comment") => ()
1171 if let Dat::ABox(ncfg, boxdat, comment) = k {
1172 if boxdat.kind() == Kind::Empty {
1173 s.push_str(&fmt!("{}{} {}\n",
1174 indent,
1175 if ncfg.is_type1() {
1176 cfg.comment1_start_char
1177 } else {
1178 cfg.comment2_start_char
1179 },
1180 comment,
1181 ));
1182 }
1183 }
1184 }
1185 } else {
1186 s.push_str(&fmt!("{}{}: {}{}",
1187 indent,
1188 res!(k.recursive_encode(&cfg, state.recurse())),
1189 res!(v.recursive_encode(&cfg, state.recurse())),
1190 if !is_last { &sep } else { &sep_last },
1191 ));
1192 }
1193 Ok(())
1194 }
1195
1196 pub fn encode_list<
1197 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
1198 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
1199 >(
1200 list: &[Dat],
1201 cfg: &EncoderConfig<M1, M2>,
1202 mut state: &mut EncoderState,
1203 )
1204 -> Outcome<(String, bool)>
1205 {
1206 if list.len() == 0 {
1207 Ok((fmt!("[]"), false))
1208 } else {
1209 let mut s = String::new();
1210 let last = list.len() - 1;
1211 let (indent0, indent, sep, sep_last) = Self::collection_encoding(
1212 &cfg,
1213 &mut state,
1214 );
1215 for (i, v) in list.iter().enumerate() {
1216 if cfg.to_lines
1217 && cfg.comment_allowed
1218 && cfg.kind_scope != KindScope::Everything
1219 && v.kind().is_abox()
1220 {
1221 // Special case of abox annotation to end of line.
1222 if let Dat::ABox(ncfg, boxdat, comment) = v {
1223 if boxdat.kind() == Kind::Empty {
1224 s.push_str(&fmt!("{}{} {}\n",
1225 indent,
1226 if ncfg.is_type1() {
1227 cfg.comment1_start_char
1228 } else {
1229 cfg.comment2_start_char
1230 },
1231 comment,
1232 ));
1233 }
1234 }
1235 } else {
1236 s.push_str(&fmt!("{}{}{}",
1237 indent,
1238 res!(v.recursive_encode(&cfg, state.recurse())),
1239 if i != last { &sep } else { &sep_last },
1240 ));
1241 }
1242 }
1243 Ok((
1244 fmt!("[{}{}{}]",
1245 if cfg.to_lines { "\n" } else { " " },
1246 s,
1247 indent0,
1248 ),
1249 false,
1250 ))
1251 }
1252 }
1253
1254 pub fn collection_encoding<
1255 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
1256 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
1257 >(
1258 cfg: &EncoderConfig<M1, M2>,
1259 state: &mut EncoderState,
1260 )
1261 -> (
1262 String, // indent0
1263 String, // indent
1264 String, // sep
1265 String, // sep_last
1266 )
1267 {
1268 let sep = fmt!(",{}", if cfg.to_lines { "\n" } else { " " });
1269 let sep_last = fmt!(
1270 "{}{}",
1271 if cfg.trailing_commas { "," } else { "" },
1272 if cfg.to_lines { "\n" } else { "" },
1273 );
1274 let indent0 = cfg.tab.repeat(state.indenter.level());
1275 if cfg.to_lines {
1276 state.indenter.inc();
1277 }
1278 let indent = cfg.tab.repeat(state.indenter.level());
1279 (indent0, indent, sep, sep_last)
1280 }
1281}