1use crate::ser::{Fragment, Map, Seq, Serialize};
2use alloc::borrow::Cow;
3use alloc::boxed::Box;
4use alloc::string::String;
5use alloc::vec::Vec;
6
7pub fn to_string<T>(value: &T) -> String
29where
30 T: ?Sized + Serialize,
31{
32 to_string_impl(&value)
33}
34
35struct Serializer<'a> {
36 stack: Vec<Layer<'a>>,
37}
38
39enum Layer<'a> {
40 Seq(Box<dyn Seq + 'a>),
41 Map(Box<dyn Map + 'a>),
42}
43
44impl<'a> Drop for Serializer<'a> {
45 fn drop(&mut self) {
46 while !self.stack.is_empty() {
48 self.stack.pop();
49 }
50 }
51}
52
53fn to_string_impl(value: &dyn Serialize) -> String {
54 let mut out = String::new();
55 let mut serializer = Serializer { stack: Vec::new() };
56 let mut fragment = value.begin();
57
58 loop {
59 match fragment {
60 Fragment::Null => out.push_str("null"),
61 Fragment::Bool(b) => out.push_str(if b { "true" } else { "false" }),
62 Fragment::Str(s) => escape_str(&s, &mut out),
63 Fragment::U64(n) => out.push_str(itoa::Buffer::new().format(n)),
64 Fragment::I64(n) => out.push_str(itoa::Buffer::new().format(n)),
65 Fragment::F64(n) => {
66 if n.is_finite() {
67 out.push_str(zmij::Buffer::new().format_finite(n));
68 } else {
69 out.push_str("null");
70 }
71 }
72 Fragment::Seq(mut seq) => {
73 out.push('[');
74 match unsafe { extend_lifetime!(seq.next() as Option<&dyn Serialize>) } {
76 Some(first) => {
77 serializer.stack.push(Layer::Seq(seq));
78 fragment = first.begin();
79 continue;
80 }
81 None => out.push(']'),
82 }
83 }
84 Fragment::Map(mut map) => {
85 out.push('{');
86 match unsafe { extend_lifetime!(map.next() as Option<(Cow<str>, &dyn Serialize)>) }
88 {
89 Some((key, first)) => {
90 escape_str(&key, &mut out);
91 out.push(':');
92 serializer.stack.push(Layer::Map(map));
93 fragment = first.begin();
94 continue;
95 }
96 None => out.push('}'),
97 }
98 }
99 }
100
101 loop {
102 match serializer.stack.last_mut() {
103 Some(Layer::Seq(seq)) => {
104 match unsafe { extend_lifetime!(seq.next() as Option<&dyn Serialize>) } {
106 Some(next) => {
107 out.push(',');
108 fragment = next.begin();
109 break;
110 }
111 None => out.push(']'),
112 }
113 }
114 Some(Layer::Map(map)) => {
115 match unsafe {
117 extend_lifetime!(map.next() as Option<(Cow<str>, &dyn Serialize)>)
118 } {
119 Some((key, next)) => {
120 out.push(',');
121 escape_str(&key, &mut out);
122 out.push(':');
123 fragment = next.begin();
124 break;
125 }
126 None => out.push('}'),
127 }
128 }
129 None => return out,
130 }
131 serializer.stack.pop();
132 }
133 }
134}
135
136#[allow(clippy::zero_prefixed_literal)]
138fn escape_str(value: &str, out: &mut String) {
139 out.push('"');
140
141 let bytes = value.as_bytes();
142 let mut start = 0;
143
144 for (i, &byte) in bytes.iter().enumerate() {
145 let escape = ESCAPE[byte as usize];
146 if escape == 0 {
147 continue;
148 }
149
150 if start < i {
151 out.push_str(&value[start..i]);
152 }
153
154 match escape {
155 self::BB => out.push_str("\\b"),
156 self::TT => out.push_str("\\t"),
157 self::NN => out.push_str("\\n"),
158 self::FF => out.push_str("\\f"),
159 self::RR => out.push_str("\\r"),
160 self::QU => out.push_str("\\\""),
161 self::BS => out.push_str("\\\\"),
162 self::U => {
163 static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef";
164 out.push_str("\\u00");
165 out.push(HEX_DIGITS[(byte >> 4) as usize] as char);
166 out.push(HEX_DIGITS[(byte & 0xF) as usize] as char);
167 }
168 _ => unreachable!(),
169 }
170
171 start = i + 1;
172 }
173
174 if start != bytes.len() {
175 out.push_str(&value[start..]);
176 }
177
178 out.push('"');
179}
180
181const BB: u8 = b'b'; const TT: u8 = b't'; const NN: u8 = b'n'; const FF: u8 = b'f'; const RR: u8 = b'r'; const QU: u8 = b'"'; const BS: u8 = b'\\'; const U: u8 = b'u'; #[rustfmt::skip]
193static ESCAPE: [u8; 256] = [
194 U, U, U, U, U, U, U, U, BB, TT, NN, U, FF, RR, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, 0, 0, QU, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, BS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];