1use crate::error::YsonError;
2use serde::{Serialize, ser};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub enum YsonFormat {
7 Binary,
9 Text,
11}
12
13pub struct Serializer {
15 pub output: Vec<u8>,
17 pub(crate) is_binary: bool,
18 pub(crate) is_writing_attributes: bool,
19}
20
21impl Serializer {
22 #[must_use]
40 pub fn new(is_binary: bool) -> Self {
41 Self::with_buffer(Vec::with_capacity(8192), is_binary)
42 }
43
44 #[must_use]
51 pub fn with_buffer(buffer: Vec<u8>, is_binary: bool) -> Self {
52 Self {
53 output: buffer,
54 is_binary,
55 is_writing_attributes: false,
56 }
57 }
58
59 #[must_use]
61 pub fn into_output(self) -> Vec<u8> {
62 self.output
63 }
64
65 #[inline]
66 fn write_entity(&mut self) {
67 self.output.push(0x23);
68 }
69
70 fn write_bool(&mut self, v: bool) {
71 if self.is_binary {
72 self.output.push(if v { 0x05 } else { 0x04 });
73 } else {
74 self.output
75 .extend_from_slice(if v { b"%true" } else { b"%false" });
76 }
77 }
78
79 fn write_i64(&mut self, v: i64) {
80 if self.is_binary {
81 self.output.push(0x02);
82 crate::varint::write_varint(v, &mut self.output);
83 } else {
84 self.output
85 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
86 }
87 }
88
89 fn write_u64(&mut self, v: u64) {
90 if self.is_binary {
91 self.output.push(0x06);
92 crate::varint::write_uvarint(v, &mut self.output);
93 } else {
94 self.output
95 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
96 self.output.push(b'u');
97 }
98 }
99
100 fn write_f64(&mut self, v: f64) {
101 if self.is_binary {
102 self.output.push(0x03);
103 self.output.extend_from_slice(&v.to_le_bytes());
104 } else if v.is_nan() {
105 self.output.extend_from_slice(b"%nan");
106 } else if v.is_infinite() {
107 self.output.extend_from_slice(if v.is_sign_negative() {
108 b"%-inf"
109 } else {
110 b"%inf"
111 });
112 } else {
113 let s = ryu::Buffer::new().format(v).to_owned();
114 self.output.extend_from_slice(s.as_bytes());
115 if !s.contains(&['.', 'e', 'E'][..]) {
116 self.output.extend_from_slice(b".0");
117 }
118 }
119 }
120
121 fn write_string(&mut self, v: &str) {
122 if self.is_binary {
123 self.output.push(0x01);
124 crate::varint::write_varint(v.len() as i64, &mut self.output);
125 self.output.extend_from_slice(v.as_bytes());
126 } else if is_safe_unquoted(v.as_bytes()) {
127 self.output.extend_from_slice(v.as_bytes());
128 } else {
129 self.output.push(b'"');
130 for &b in v.as_bytes() {
131 match b {
132 b'"' => self.output.extend_from_slice(b"\\\""),
133 b'\\' => self.output.extend_from_slice(b"\\\\"),
134 b'\n' => self.output.extend_from_slice(b"\\n"),
135 b'\r' => self.output.extend_from_slice(b"\\r"),
136 b'\t' => self.output.extend_from_slice(b"\\t"),
137 0x00..=0x1F => {
138 const HEX: &[u8] = b"0123456789abcdef";
139 self.output.extend_from_slice(&[
140 b'\\',
141 b'x',
142 HEX[(b >> 4) as usize],
143 HEX[(b & 0x0F) as usize],
144 ]);
145 }
146 _ => self.output.push(b),
147 }
148 }
149 self.output.push(b'"');
150 }
151 }
152}
153
154macro_rules! impl_serialize {
155 ($($name:ident($ty:ty) => $method:ident as $cast:ty),*) => {
157 $(fn $name(self, v: $ty) -> Result<(), Self::Error> { self.$method(v as $cast); Ok(()) })*
158 };
159 (@empty $($name:ident $(($($arg:ident: $ty:ty),*))?),*) => {
161 $(fn $name(self $(, $($arg: $ty),*)?) -> Result<(), Self::Error> { self.write_entity(); Ok(()) })*
162 };
163}
164
165impl<'a> ser::Serializer for &'a mut Serializer {
166 type Ok = ();
167 type Error = YsonError;
168 type SerializeSeq = Compound<'a>;
169 type SerializeTuple = Compound<'a>;
170 type SerializeTupleStruct = Compound<'a>;
171 type SerializeTupleVariant = Compound<'a>;
172 type SerializeMap = Compound<'a>;
173 type SerializeStruct = Compound<'a>;
174 type SerializeStructVariant = Compound<'a>;
175
176 impl_serialize! {
177 serialize_i8(i8) => write_i64 as i64, serialize_i16(i16) => write_i64 as i64,
178 serialize_i32(i32) => write_i64 as i64, serialize_i64(i64) => write_i64 as i64,
179 serialize_u8(u8) => write_u64 as u64, serialize_u16(u16) => write_u64 as u64,
180 serialize_u32(u32) => write_u64 as u64, serialize_u64(u64) => write_u64 as u64,
181 serialize_f32(f32) => write_f64 as f64, serialize_f64(f64) => write_f64 as f64
182 }
183
184 impl_serialize!(@empty serialize_none, serialize_unit, serialize_unit_struct(_n: &'static str));
185
186 fn serialize_bool(self, v: bool) -> Result<(), Self::Error> {
187 self.write_bool(v);
188 Ok(())
189 }
190 fn serialize_char(self, v: char) -> Result<(), Self::Error> {
191 self.write_string(&v.to_string());
192 Ok(())
193 }
194 fn serialize_str(self, v: &str) -> Result<(), Self::Error> {
195 self.write_string(v);
196 Ok(())
197 }
198
199 fn serialize_bytes(self, v: &[u8]) -> Result<(), Self::Error> {
200 if self.is_binary {
201 self.output.push(0x01);
202 crate::varint::write_varint(v.len() as i64, &mut self.output);
203 self.output.extend_from_slice(v);
204 } else {
205 self.output.push(b'"');
206 for &b in v {
207 match b {
208 b'"' => self.output.extend_from_slice(b"\\\""),
209 b'\\' => self.output.extend_from_slice(b"\\\\"),
210 b'\n' => self.output.extend_from_slice(b"\\n"),
211 b'\r' => self.output.extend_from_slice(b"\\r"),
212 b'\t' => self.output.extend_from_slice(b"\\t"),
213 0x20..=0x7E => self.output.push(b),
214 _ => {
215 const HEX: &[u8] = b"0123456789abcdef";
216 self.output.extend_from_slice(&[
217 b'\\',
218 b'x',
219 HEX[(b >> 4) as usize],
220 HEX[(b & 0x0F) as usize],
221 ]);
222 }
223 }
224 }
225 self.output.push(b'"');
226 }
227 Ok(())
228 }
229
230 fn serialize_some<T: ?Sized + Serialize>(self, v: &T) -> Result<(), Self::Error> {
231 v.serialize(self)
232 }
233 fn serialize_newtype_struct<T: ?Sized + Serialize>(
234 self,
235 _: &'static str,
236 v: &T,
237 ) -> Result<(), Self::Error> {
238 v.serialize(self)
239 }
240
241 fn serialize_unit_variant(
242 self,
243 _: &'static str,
244 _: u32,
245 variant: &'static str,
246 ) -> Result<(), Self::Error> {
247 self.write_string(variant);
248 Ok(())
249 }
250
251 fn serialize_newtype_variant<T: ?Sized + Serialize>(
252 self,
253 _: &'static str,
254 _: u32,
255 var: &'static str,
256 val: &T,
257 ) -> Result<(), Self::Error> {
258 self.output.push(b'{');
259 self.write_string(var);
260 self.output.push(b'=');
261 val.serialize(&mut *self)?;
262 self.output.push(b'}');
263 Ok(())
264 }
265
266 fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
267 self.output.push(b'[');
268 Ok(Compound {
269 ser: self,
270 first: true,
271 mode: CompoundMode::Seq,
272 })
273 }
274
275 fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
276 self.serialize_seq(Some(len))
277 }
278 fn serialize_tuple_struct(
279 self,
280 _: &'static str,
281 len: usize,
282 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
283 self.serialize_seq(Some(len))
284 }
285
286 fn serialize_tuple_variant(
287 self,
288 _: &'static str,
289 _: u32,
290 var: &'static str,
291 _: usize,
292 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
293 self.output.push(b'{');
294 self.write_string(var);
295 self.output.extend_from_slice(b"=[");
296 Ok(Compound {
297 ser: self,
298 first: true,
299 mode: CompoundMode::VariantSeq,
300 })
301 }
302
303 fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
304 let (open, mode) = if self.is_writing_attributes {
305 (b'<', CompoundMode::Attr)
306 } else {
307 (b'{', CompoundMode::Map)
308 };
309 self.output.push(open);
310 self.is_writing_attributes = false;
311 Ok(Compound {
312 ser: self,
313 first: true,
314 mode,
315 })
316 }
317
318 fn serialize_struct(
319 self,
320 name: &'static str,
321 _: usize,
322 ) -> Result<Self::SerializeStruct, Self::Error> {
323 let mode = if name == "$__yson_attributes" {
324 CompoundMode::AttrWrapper
325 } else if self.is_writing_attributes {
326 self.output.push(b'<');
327 self.is_writing_attributes = false;
328 CompoundMode::Attr
329 } else {
330 CompoundMode::Struct {
331 attr_open: false,
332 body_open: false,
333 }
334 };
335 Ok(Compound {
336 ser: self,
337 first: true,
338 mode,
339 })
340 }
341
342 fn serialize_struct_variant(
343 self,
344 _: &'static str,
345 _: u32,
346 var: &'static str,
347 _: usize,
348 ) -> Result<Self::SerializeStructVariant, Self::Error> {
349 self.output.push(b'{');
350 self.write_string(var);
351 self.output.extend_from_slice(b"={");
352 Ok(Compound {
353 ser: self,
354 first: true,
355 mode: CompoundMode::VariantMap,
356 })
357 }
358}
359
360#[derive(Clone, Copy)]
361enum CompoundMode {
362 Seq,
363 Map,
364 Attr,
365 AttrWrapper,
366 VariantSeq,
367 VariantMap,
368 Struct { attr_open: bool, body_open: bool },
369}
370
371pub struct Compound<'a> {
373 ser: &'a mut Serializer,
374 first: bool,
375 mode: CompoundMode,
376}
377
378impl Compound<'_> {
379 #[inline]
380 fn check_first(&mut self) {
381 if !self.first {
382 self.ser.output.push(b';');
383 }
384 self.first = false;
385 }
386}
387
388macro_rules! delegate_seq {
389 ($($trait:ident),*) => {
390 $(impl<'a> ser::$trait for Compound<'a> {
391 type Ok = (); type Error = YsonError;
392 fn serialize_element<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<(), Self::Error> {
393 self.check_first(); v.serialize(&mut *self.ser)
394 }
395 fn end(self) -> Result<(), Self::Error> { self.ser.output.push(b']'); Ok(()) }
396 })*
397 };
398}
399delegate_seq!(SerializeSeq, SerializeTuple);
400
401impl ser::SerializeTupleStruct for Compound<'_> {
402 type Ok = ();
403 type Error = YsonError;
404 fn serialize_field<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<(), Self::Error> {
405 self.check_first();
406 v.serialize(&mut *self.ser)
407 }
408 fn end(self) -> Result<(), Self::Error> {
409 self.ser.output.push(b']');
410 Ok(())
411 }
412}
413
414impl ser::SerializeTupleVariant for Compound<'_> {
415 type Ok = ();
416 type Error = YsonError;
417 fn serialize_field<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<(), Self::Error> {
418 self.check_first();
419 v.serialize(&mut *self.ser)
420 }
421 fn end(self) -> Result<(), Self::Error> {
422 self.ser.output.extend_from_slice(b"]}");
423 Ok(())
424 }
425}
426
427impl ser::SerializeMap for Compound<'_> {
428 type Ok = ();
429 type Error = YsonError;
430 fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<(), Self::Error> {
431 self.check_first();
432 key.serialize(&mut *self.ser)
433 }
434 fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> {
435 self.ser.output.push(b'=');
436 value.serialize(&mut *self.ser)
437 }
438 fn end(self) -> Result<(), Self::Error> {
439 self.ser
440 .output
441 .push(if matches!(self.mode, CompoundMode::Attr) {
442 b'>'
443 } else {
444 b'}'
445 });
446 Ok(())
447 }
448}
449
450impl ser::SerializeStruct for Compound<'_> {
451 type Ok = ();
452 type Error = YsonError;
453
454 fn serialize_field<T: ?Sized + Serialize>(
455 &mut self,
456 key: &'static str,
457 value: &T,
458 ) -> Result<(), Self::Error> {
459 match self.mode {
460 CompoundMode::AttrWrapper => {
461 if key == "$attributes" {
462 self.ser.is_writing_attributes = true;
463 value.serialize(&mut *self.ser)?;
464 } else if key == "$value" {
465 value.serialize(&mut *self.ser)?;
466 }
467 }
468 CompoundMode::Struct {
469 mut attr_open,
470 mut body_open,
471 } => {
472 if let Some(attr_name) = key.strip_prefix('@') {
473 if !attr_open {
474 self.ser.output.push(b'<');
475 attr_open = true;
476 self.first = true;
477 }
478 self.check_first();
479 self.ser.write_string(attr_name);
480 self.ser.output.push(b'=');
481 } else {
482 if attr_open {
483 self.ser.output.push(b'>');
484 attr_open = false;
485 }
486 if key != "$value" {
487 if !body_open {
488 self.ser.output.push(b'{');
489 body_open = true;
490 self.first = true;
491 }
492 self.check_first();
493 self.ser.write_string(key);
494 self.ser.output.push(b'=');
495 }
496 }
497
498 self.mode = CompoundMode::Struct {
499 attr_open,
500 body_open,
501 };
502 value.serialize(&mut *self.ser)?;
503 }
504 _ => {
505 self.check_first();
506 self.ser.write_string(key);
507 self.ser.output.push(b'=');
508 value.serialize(&mut *self.ser)?;
509 }
510 }
511 Ok(())
512 }
513
514 fn end(self) -> Result<(), Self::Error> {
515 match self.mode {
516 CompoundMode::Attr => self.ser.output.push(b'>'),
517 CompoundMode::Seq | CompoundMode::VariantSeq => self.ser.output.push(b']'),
518 CompoundMode::Struct {
519 attr_open,
520 body_open,
521 } => {
522 if attr_open {
523 self.ser.output.push(b'>');
524 }
525 if body_open {
526 self.ser.output.push(b'}');
527 }
528 }
529 CompoundMode::AttrWrapper => {}
530 _ => self.ser.output.push(b'}'),
531 }
532 Ok(())
533 }
534}
535
536impl ser::SerializeStructVariant for Compound<'_> {
537 type Ok = ();
538 type Error = YsonError;
539 fn serialize_field<T: ?Sized + Serialize>(
540 &mut self,
541 k: &'static str,
542 v: &T,
543 ) -> Result<(), Self::Error> {
544 ser::SerializeStruct::serialize_field(self, k, v)
545 }
546 fn end(self) -> Result<(), Self::Error> {
547 self.ser.output.extend_from_slice(b"}}");
548 Ok(())
549 }
550}
551
552fn is_safe_unquoted(b: &[u8]) -> bool {
553 matches!(b.first(), Some(f) if f.is_ascii_alphabetic() || *f == b'_')
554 && b.iter()
555 .all(|&c| c.is_ascii_alphanumeric() || b"_-.".contains(&c))
556}