1use alloc::boxed::Box;
2use alloc::format;
3use alloc::string::{String, ToString};
4use alloc::vec::Vec;
5
6use deser_core::State;
7use deser_core::ext::{BigInt, Datetime, ExtValue, Number, Timestamp};
8use deser_core::ser::SerializeRef;
9use deser_core::ser::{self, SerializeDriver};
10use deser_core::{Atom, Error, ErrorKind, Event, Serialize};
11
12use crate::common::{timestamp_from_plist, timestamp_to_plist};
13use crate::format::Format;
14use crate::uid::Uid;
15use crate::write_binary;
16use crate::write_text::TextWriter;
17
18#[derive(Debug, Clone, Default, PartialEq, Eq)]
34pub struct SerializerConfig {
35 format: Format,
36 context: deser_core::Context,
37}
38
39impl SerializerConfig {
40 pub const fn new() -> SerializerConfig {
42 SerializerConfig {
43 format: Format::Xml,
44 context: deser_core::Context::new(),
45 }
46 }
47
48 pub const fn builder() -> SerializerConfigBuilder {
50 SerializerConfigBuilder::new()
51 }
52
53 pub const fn into_builder(self) -> SerializerConfigBuilder {
55 SerializerConfigBuilder { value: self }
56 }
57
58 pub fn set_context(&mut self, context: deser_core::Context) {
66 self.context = context;
67 }
68
69 pub fn context(&self) -> &deser_core::Context {
71 &self.context
72 }
73
74 #[inline]
76 fn apply_context(&self, driver: &mut SerializeDriver<'_>) {
77 if !self.context.is_empty() {
78 driver.set_default_context(self.context.clone());
79 }
80 }
81
82 pub const fn set_format(&mut self, format: Format) {
84 self.format = format;
85 }
86
87 pub fn to_vec<T: Serialize + ?Sized>(&self, value: &T) -> Result<Vec<u8>, Error> {
89 self.to_vec_ref(SerializeRef::new(&value))
90 }
91
92 pub fn to_vec_with<F, T: Serialize + ?Sized>(
97 &self,
98 value: &T,
99 setup: F,
100 ) -> Result<Vec<u8>, Error>
101 where
102 F: FnOnce(&mut SerializeDriver<'_>),
103 {
104 let mut driver = SerializeDriver::new(&value);
105 setup(&mut driver);
106 self.apply_context(&mut driver);
107 self.serialize_driver(&mut driver)
108 }
109
110 fn to_vec_ref(&self, value: SerializeRef<'_>) -> Result<Vec<u8>, Error> {
116 let mut driver = SerializeDriver::from_ref(value);
117 self.apply_context(&mut driver);
118 self.serialize_driver(&mut driver)
119 }
120
121 pub fn to_string<T: Serialize + ?Sized>(&self, value: &T) -> Result<String, Error> {
125 if !self.format.is_text() {
126 return Err(Error::new(
127 ErrorKind::UnsupportedType,
128 "binary property lists cannot be written to strings",
129 ));
130 }
131 let bytes = self.to_vec(value)?;
132 Ok(String::from_utf8(bytes).unwrap())
134 }
135
136 pub(crate) fn serialize_driver(
138 &self,
139 driver: &mut SerializeDriver<'_>,
140 ) -> Result<Vec<u8>, Error> {
141 if self.format.is_text() {
142 let mut writer = TextWriter::new(self.format, String::with_capacity(256));
143 driver.drive_sink(&mut writer)?;
144 writer.finish()?;
145 return Ok(writer.out.into_bytes());
146 }
147 let mut builder = Builder::default();
148 driver.drive_sink(&mut builder)?;
149 let tree = builder.finish()?;
150 Ok(write_binary::write(&tree))
151 }
152
153 pub(crate) fn is_text(&self) -> bool {
155 self.format.is_text()
156 }
157
158 pub(crate) fn serialize_part(
166 &self,
167 value: &mut Option<Box<TextWriter>>,
168 driver: &mut SerializeDriver<'_>,
169 out: &mut Vec<u8>,
170 limit: usize,
171 ) -> Result<bool, Error> {
172 let len = out.len();
173 let adopt = out.is_empty();
176 let buffer = match adopt {
177 true => String::new(),
179 false => String::with_capacity(256),
180 };
181 let mut local;
182 let writer: &mut TextWriter = match value {
183 Some(writer) => {
184 writer.out = buffer;
185 writer
186 }
187 None if limit == usize::MAX => {
189 local = TextWriter::new(self.format, buffer);
190 &mut local
191 }
192 None => value.insert(Box::new(TextWriter::new(self.format, buffer))),
193 };
194 let rv = if limit == usize::MAX {
195 driver.drive_sink(writer).map(|()| true)
196 } else {
197 writer.limit = limit;
198 driver.drive_until(writer)
199 };
200 let rv = rv.and_then(|done| {
201 if done {
202 writer.finish()?;
203 }
204 Ok(done)
205 });
206 let output = core::mem::take(&mut writer.out).into_bytes();
207 match rv {
208 Ok(done) => {
209 if adopt {
210 *out = output;
211 } else {
212 out.extend_from_slice(&output);
213 }
214 if done {
215 *value = None;
216 }
217 Ok(done)
218 }
219 Err(err) => {
220 *value = None;
222 out.truncate(len);
223 Err(err)
224 }
225 }
226 }
227}
228
229#[derive(Debug, Clone)]
233#[must_use]
234pub struct SerializerConfigBuilder {
235 value: SerializerConfig,
236}
237
238impl SerializerConfigBuilder {
239 pub const fn new() -> SerializerConfigBuilder {
241 SerializerConfigBuilder {
242 value: SerializerConfig::new(),
243 }
244 }
245
246 pub const fn format(mut self, format: Format) -> SerializerConfigBuilder {
250 self.value.set_format(format);
251 self
252 }
253
254 pub fn context(mut self, context: deser_core::Context) -> SerializerConfigBuilder {
258 self.value.set_context(context);
259 self
260 }
261
262 pub const fn build(self) -> SerializerConfig {
264 let value = unsafe { core::ptr::read(&self.value) };
268 core::mem::forget(self);
269 value
270 }
271}
272
273impl Default for SerializerConfigBuilder {
274 fn default() -> SerializerConfigBuilder {
275 SerializerConfigBuilder::new()
276 }
277}
278
279#[derive(Default)]
298pub struct Serializer {
299 config: SerializerConfig,
300 out: Vec<u8>,
301 written: bool,
302 value: Option<Box<TextWriter>>,
304 in_progress: bool,
306}
307
308impl Clone for Serializer {
309 fn clone(&self) -> Serializer {
315 Serializer {
316 config: self.config.clone(),
317 out: self.out.clone(),
318 written: self.written,
319 value: None,
320 in_progress: self.in_progress,
321 }
322 }
323}
324
325impl core::fmt::Debug for Serializer {
326 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
327 f.debug_struct("Serializer")
328 .field("config", &self.config)
329 .field("output", &self.out)
330 .field("written", &self.written)
331 .field("in_progress", &self.in_progress)
332 .finish()
333 }
334}
335
336impl Serializer {
337 pub fn new() -> Serializer {
339 Serializer::with_config(SerializerConfig::new())
340 }
341
342 pub fn with_config(config: SerializerConfig) -> Serializer {
344 Serializer {
345 config,
346 out: Vec::new(),
347 written: false,
348 value: None,
349 in_progress: false,
350 }
351 }
352
353 pub fn config(&self) -> &SerializerConfig {
355 &self.config
356 }
357
358 pub fn written(&self) -> bool {
360 self.written
361 }
362
363 pub fn serialize<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
368 ser::Serializer::serialize(self, value)
369 }
370
371 pub fn serialize_with<F, T: Serialize + ?Sized>(
376 &mut self,
377 value: &T,
378 setup: F,
379 ) -> Result<(), Error>
380 where
381 F: FnOnce(&mut SerializeDriver<'_>),
382 {
383 ser::Serializer::serialize_with(self, value, setup)
384 }
385
386 pub fn output(&self) -> &[u8] {
388 &self.out
389 }
390
391 pub fn finish(self) -> Vec<u8> {
393 self.out
394 }
395
396 fn check_single(&self) -> Result<(), Error> {
398 if self.in_progress {
399 return Err(Error::in_progress());
400 }
401 if self.written {
402 return Err(Error::new(
403 ErrorKind::InvalidState,
404 "a property list holds a single value",
405 ));
406 }
407 Ok(())
408 }
409}
410
411impl ser::Serializer for Serializer {
412 fn drive(&mut self, driver: &mut SerializeDriver<'_>) -> Result<(), Error> {
413 if !self.config.context.is_empty() {
414 driver.set_default_context(self.config.context.clone());
415 }
416 self.check_single()?;
417 if self.config.is_text() {
418 self.config
419 .serialize_part(&mut self.value, driver, &mut self.out, usize::MAX)?;
420 } else {
421 let bytes = self.config.serialize_driver(driver)?;
422 self.out.extend_from_slice(&bytes);
423 }
424 self.written = true;
425 Ok(())
426 }
427}
428
429impl ser::StreamSerializer for Serializer {
430 fn output(&self) -> &[u8] {
431 &self.out
432 }
433
434 fn clear_output(&mut self) {
435 self.out.clear();
436 }
437
438 fn supports_partial(&self) -> bool {
440 self.config.is_text()
441 }
442
443 fn drive_partial(
444 &mut self,
445 driver: &mut SerializeDriver<'_>,
446 limit: usize,
447 ) -> Result<bool, Error> {
448 if !self.config.context.is_empty() {
449 driver.set_default_context(self.config.context.clone());
450 }
451 if self.value.is_none() {
452 if limit == usize::MAX || !self.config.is_text() {
453 ser::Serializer::drive(self, driver)?;
454 return Ok(true);
455 }
456 self.check_single()?;
457 }
458 if !self
461 .config
462 .serialize_part(&mut self.value, driver, &mut self.out, limit)?
463 {
464 self.in_progress = true;
465 return Ok(false);
466 }
467 self.in_progress = false;
468 self.written = true;
469 Ok(true)
470 }
471
472 fn in_progress(&self) -> bool {
473 self.in_progress
474 }
475}
476
477#[cfg(feature = "io")]
478impl SerializerConfig {
479 pub fn writer<W: std::io::Write>(&self, writer: W) -> deser_core::io::Writer<W, Serializer> {
487 deser_core::io::Writer::new(writer, Serializer::with_config(self.clone()))
488 }
489
490 pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
494 &self,
495 writer: W,
496 value: &T,
497 ) -> Result<(), Error> {
498 self.writer(writer).write(value)
499 }
500}
501
502#[cfg(feature = "io")]
512pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
513 writer: W,
514 value: &T,
515) -> Result<(), Error> {
516 SerializerConfig::new().to_writer(writer, value)
517}
518
519pub fn to_vec<T: Serialize + ?Sized>(value: &T) -> Result<Vec<u8>, Error> {
528 SerializerConfig::new().to_vec(value)
529}
530
531pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, Error> {
535 SerializerConfig::new().to_string(value)
536}
537
538pub(crate) enum Node {
540 Bool(bool),
541 Int(i128),
542 Real(f64),
543 Real32(f32),
544 Str(String),
545 Data(Vec<u8>),
546 Date(Timestamp),
547 Uid(u64),
548 Array(Vec<usize>),
549 Dict(Vec<(String, usize)>),
550}
551
552pub(crate) struct Tree {
554 pub(crate) nodes: Vec<Node>,
555}
556
557enum Open {
559 Array(usize, Vec<usize>),
560 Dict(usize, Vec<(String, usize)>, Option<String>),
561}
562
563#[derive(Default)]
565struct Builder {
566 nodes: Vec<Node>,
567 stack: Vec<Open>,
568}
569
570impl ser::EventSink for Builder {
571 fn event(
572 &mut self,
573 event: Event,
574 _value: SerializeRef<'_>,
575 _state: &mut State,
576 ) -> Result<(), Error> {
577 Builder::event(self, event)
578 }
579}
580
581impl Builder {
582 fn finish(self) -> Result<Tree, Error> {
583 if self.nodes.is_empty() || !self.stack.is_empty() {
584 return Err(Error::new(ErrorKind::InvalidState, "incomplete value"));
585 }
586 Ok(Tree { nodes: self.nodes })
587 }
588
589 fn event(&mut self, event: Event) -> Result<(), Error> {
590 let Some(open) = self.stack.last_mut() else {
591 if !self.nodes.is_empty() {
592 return Err(Error::new(ErrorKind::InvalidState, "unexpected event"));
593 }
594 return match self.value(event)? {
595 Some(_) => Ok(()),
596 None => Err(Error::new(
597 ErrorKind::UnsupportedType,
598 "property lists cannot hold null values",
599 )),
600 };
601 };
602 match open {
603 Open::Dict(_, _, key @ None) => match event {
604 Event::Atom(atom) => {
605 *key = Some(key_to_string(atom)?);
606 Ok(())
607 }
608 Event::MapEnd => self.close(),
609 _ => Err(unsupported_key()),
610 },
611 Open::Dict(_, _, key @ Some(_)) => {
612 let key = key.take().unwrap();
613 if let Some(value) = self.value(event)? {
615 self.add_entry(key, value);
616 }
617 Ok(())
618 }
619 Open::Array(..) => {
620 if event == Event::SeqEnd {
621 return self.close();
622 }
623 match self.value(event)? {
624 Some(value) => {
625 self.add_item(value);
626 Ok(())
627 }
628 None => Err(Error::new(
629 ErrorKind::UnsupportedType,
630 "property lists cannot hold null values in arrays",
631 )),
632 }
633 }
634 }
635 }
636
637 fn parent(&mut self, value: usize) -> &mut Open {
642 let len = self.stack.len();
643 let opened = match self.stack[len - 1] {
644 Open::Array(id, _) | Open::Dict(id, _, _) => id == value,
645 };
646 &mut self.stack[if opened { len - 2 } else { len - 1 }]
647 }
648
649 fn add_entry(&mut self, key: String, value: usize) {
650 match self.parent(value) {
651 Open::Dict(_, entries, _) => entries.push((key, value)),
652 Open::Array(..) => unreachable!(),
653 }
654 }
655
656 fn add_item(&mut self, value: usize) {
657 match self.parent(value) {
658 Open::Array(_, items) => items.push(value),
659 Open::Dict(..) => unreachable!(),
660 }
661 }
662
663 fn close(&mut self) -> Result<(), Error> {
665 match self.stack.pop() {
666 Some(Open::Array(id, items)) => self.nodes[id] = Node::Array(items),
667 Some(Open::Dict(id, entries, None)) => self.nodes[id] = Node::Dict(entries),
668 Some(Open::Dict(_, _, Some(_))) => {
669 return Err(Error::new(ErrorKind::InvalidState, "map without value"));
670 }
671 None => return Err(Error::new(ErrorKind::InvalidState, "unexpected end")),
672 }
673 Ok(())
674 }
675
676 fn value(&mut self, event: Event) -> Result<Option<usize>, Error> {
679 let id = self.nodes.len();
680 let node = match event {
681 Event::Atom(atom) => match convert_atom(atom)? {
682 Some(Node::Date(value))
684 if timestamp_from_plist(timestamp_to_plist(&value)).is_none() =>
685 {
686 return Err(Error::new(
687 ErrorKind::OutOfRange,
688 "date out of range for binary property lists",
689 ));
690 }
691 Some(node) => node,
692 None => return Ok(None),
693 },
694 Event::MapStart(_) => {
695 self.stack.push(Open::Dict(id, Vec::new(), None));
696 Node::Dict(Vec::new())
697 }
698 Event::SeqStart(_) => {
699 self.stack.push(Open::Array(id, Vec::new()));
700 Node::Array(Vec::new())
701 }
702 Event::MapEnd | Event::SeqEnd => {
703 return Err(Error::new(ErrorKind::InvalidState, "unexpected end event"));
704 }
705 };
706 self.nodes.push(node);
707 Ok(Some(id))
708 }
709}
710
711pub(crate) fn convert_atom(atom: Atom) -> Result<Option<Node>, Error> {
713 Ok(Some(match atom {
714 Atom::Null => return Ok(None),
715 Atom::Bool(value) => Node::Bool(value),
716 Atom::Str(value) | Atom::Lexical(value) => Node::Str(value.into_owned()),
717 Atom::Char(value) => Node::Str(value.to_string()),
718 Atom::U64(value) => Node::Int(value.into()),
719 Atom::I64(value) => Node::Int(value.into()),
720 Atom::F64(value) => Node::Real(value),
721 Atom::F32(value) => Node::Real32(value),
722 Atom::Bytes(value) => Node::Data(value.into_owned()),
724 Atom::Ext(ref ext) => return convert_ext(ext),
725 Atom::Implicit(value) => return convert_atom(value.value().to_atom()),
727 _ => return Err(Error::new(ErrorKind::UnsupportedType, "unknown atom")),
728 }))
729}
730
731#[cold]
732fn convert_ext(ext: &ExtValue) -> Result<Option<Node>, Error> {
733 if let Some(value) = ext.downcast_ref::<Uid>() {
734 return Ok(Some(Node::Uid(value.get())));
735 }
736 if let Some(&value) = ext.downcast_ref::<Timestamp>() {
737 return Ok(Some(Node::Date(value)));
738 }
739 if let Some(&value) = ext.downcast_ref::<Datetime>()
741 && value.offset.is_some()
742 && let Ok(value) = Timestamp::try_from(value)
743 {
744 return Ok(Some(Node::Date(value)));
745 }
746 let out_of_range = || Error::new(ErrorKind::OutOfRange, "integer out of range for plist");
747 if let Some(&value) = ext.downcast_ref::<u128>() {
748 return Ok(Some(Node::Int(
749 i128::try_from(value).map_err(|_| out_of_range())?,
750 )));
751 }
752 if let Some(&value) = ext.downcast_ref::<i128>() {
753 return Ok(Some(Node::Int(value)));
754 }
755 if let Some(value) = ext.downcast_ref::<BigInt>().and_then(|x| x.to_i128()) {
756 return Ok(Some(Node::Int(value)));
757 }
758 if let Some(value) = ext.downcast_value_ref::<Number>()
760 && let Ok(value) = value.as_str().parse::<i128>()
761 {
762 return Ok(Some(Node::Int(value)));
763 }
764 match ext.fallback() {
765 Atom::Ext(_) => Err(Error::new(
766 ErrorKind::UnsupportedType,
767 format!("property lists do not support {}", ext.name()),
768 )),
769 fallback => convert_atom(fallback),
770 }
771}
772
773pub(crate) fn key_to_string(atom: Atom) -> Result<String, Error> {
775 Ok(match atom {
776 Atom::Implicit(value) => return key_to_string(value.value().to_atom()),
777 Atom::Str(value) | Atom::Lexical(value) => value.into_owned(),
778 Atom::Char(value) => value.to_string(),
779 Atom::U64(value) => value.to_string(),
780 Atom::I64(value) => value.to_string(),
781 Atom::Bool(value) => value.to_string(),
782 Atom::Ext(ref ext) => {
783 if let Some(value) = ext.downcast_ref::<u128>() {
784 value.to_string()
785 } else if let Some(value) = ext.downcast_ref::<i128>() {
786 value.to_string()
787 } else {
788 match ext.fallback() {
789 Atom::Ext(_) => return Err(unsupported_key()),
790 fallback => return key_to_string(fallback),
791 }
792 }
793 }
794 _ => return Err(unsupported_key()),
795 })
796}
797
798#[cold]
799pub(crate) fn unsupported_key() -> Error {
800 Error::new(
801 ErrorKind::UnsupportedType,
802 "dictionary keys of property lists must be strings",
803 )
804}