Skip to main content

deser_plist/
ser.rs

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/// Configures how values are serialized to property lists.
19///
20/// The [`set_format`](Self::set_format) selects the encoding, by default XML is
21/// written.
22///
23/// ```
24/// use deser_plist::{Format, SerializerConfig};
25///
26/// const BINARY: SerializerConfig = SerializerConfig::builder().format(Format::Binary).build();
27/// let bytes = BINARY.to_vec(&vec![1, 2, 3]).unwrap();
28/// assert!(bytes.starts_with(b"bplist00"));
29///
30/// const ASCII: SerializerConfig = SerializerConfig::builder().format(Format::Ascii).build();
31/// assert_eq!(ASCII.to_string(&vec![1, 2, 3]).unwrap(), "(\n\t1,\n\t2,\n\t3,\n)\n");
32/// ```
33#[derive(Debug, Clone, Default, PartialEq, Eq)]
34pub struct SerializerConfig {
35    format: Format,
36    context: deser_core::Context,
37}
38
39impl SerializerConfig {
40    /// Creates the default configuration.
41    pub const fn new() -> SerializerConfig {
42        SerializerConfig {
43            format: Format::Xml,
44            context: deser_core::Context::new(),
45        }
46    }
47
48    /// Returns a builder for the configuration (see [`SerializerConfigBuilder`]).
49    pub const fn builder() -> SerializerConfigBuilder {
50        SerializerConfigBuilder::new()
51    }
52
53    /// Returns a builder that starts with this configuration.
54    pub const fn into_builder(self) -> SerializerConfigBuilder {
55        SerializerConfigBuilder { value: self }
56    }
57
58    /// Sets the context the values are serialized in.
59    ///
60    /// The values of the context are the defaults of the extension values
61    /// of the state (see [`Context`](deser_core::Context)), for instance
62    /// the [`BytesFormat`](deser_core::BytesFormat).  The serializers and
63    /// writers created with the configuration use this context.  A context set on
64    /// the driver takes precedence.
65    pub fn set_context(&mut self, context: deser_core::Context) {
66        self.context = context;
67    }
68
69    /// Returns the context the values are serialized in.
70    pub fn context(&self) -> &deser_core::Context {
71        &self.context
72    }
73
74    /// Gives the context to a driver which has none.
75    #[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    /// Sets the format to write.
83    pub const fn set_format(&mut self, format: Format) {
84        self.format = format;
85    }
86
87    /// Serializes the given value.
88    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    /// Serializes the given value with a configured driver.
93    ///
94    /// The callback is invoked with the driver before the serialization
95    /// starts, for instance to add [`Layer`](deser_core::ser::Layer)s.
96    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    /// Serializes a value whose type is erased (see
111    /// [`to_vec`](Self::to_vec)).
112    ///
113    /// This is not generic: the code that exists for every type only
114    /// erases it.
115    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    /// Serializes the given value into a string.
122    ///
123    /// This fails for the binary format.
124    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        // the text writers only write UTF-8
133        Ok(String::from_utf8(bytes).unwrap())
134    }
135
136    /// Serializes the value of a driver.
137    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    /// Returns `true` if the output can be written in parts.
154    pub(crate) fn is_text(&self) -> bool {
155        self.format.is_text()
156    }
157
158    /// Serializes (a part of) the value of a driver as text property list
159    /// and appends it to the output.
160    ///
161    /// The progress of the value is kept in `value` (see
162    /// `StreamSerializer::drive_partial`), `true` is returned once the
163    /// value is complete.  If this fails, what was appended by the call is
164    /// removed from the output.
165    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        // the writer writes into an empty output directly, otherwise its
174        // output is appended
175        let adopt = out.is_empty();
176        let buffer = match adopt {
177            // the output only holds text if it's not empty
178            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            // a value that is written at once does not box the writer
188            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                // the value is abandoned
221                *value = None;
222                out.truncate(len);
223                Err(err)
224            }
225        }
226    }
227}
228
229/// Builds a [`SerializerConfig`].
230///
231/// The methods have the names of the setters of [`SerializerConfig`] (without `set_`).
232#[derive(Debug, Clone)]
233#[must_use]
234pub struct SerializerConfigBuilder {
235    value: SerializerConfig,
236}
237
238impl SerializerConfigBuilder {
239    /// Creates a builder that starts with the default.
240    pub const fn new() -> SerializerConfigBuilder {
241        SerializerConfigBuilder {
242            value: SerializerConfig::new(),
243        }
244    }
245
246    /// Sets the format to write.
247    ///
248    /// See [`SerializerConfig::set_format`].
249    pub const fn format(mut self, format: Format) -> SerializerConfigBuilder {
250        self.value.set_format(format);
251        self
252    }
253
254    /// Sets the context the values are serialized in.
255    ///
256    /// See [`SerializerConfig::set_context`].
257    pub fn context(mut self, context: deser_core::Context) -> SerializerConfigBuilder {
258        self.value.set_context(context);
259        self
260    }
261
262    /// Returns the built [`SerializerConfig`].
263    pub const fn build(self) -> SerializerConfig {
264        // the value cannot be moved out of the builder in a const fn as the
265        // builder needs dropping (the context has a destructor)
266        // SAFETY: the value is read once and the builder is forgotten
267        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/// Serializes values into property lists.
280///
281/// A property list holds a single value.
282///
283/// ```
284/// use deser_plist::Serializer;
285///
286/// let mut serializer = Serializer::new();
287/// serializer.serialize(&true).unwrap();
288/// assert!(serializer.output().ends_with(b"<plist version=\"1.0\">\n<true/>\n</plist>\n"));
289/// ```
290///
291/// The serializer is also the stream serializer of property lists (see
292/// [`StreamSerializer`](ser::StreamSerializer)).  XML and OpenStep
293/// property lists can be written in parts, binary property lists are
294/// written once the value is complete as the object table needs all
295/// objects.  To write to a [`Write`](std::io::Write) use
296/// [`SerializerConfig::writer`].
297#[derive(Default)]
298pub struct Serializer {
299    config: SerializerConfig,
300    out: Vec<u8>,
301    written: bool,
302    // the value that is written in parts
303    value: Option<Box<TextWriter>>,
304    // a value was started with `drive_partial` and is not complete
305    in_progress: bool,
306}
307
308impl Clone for Serializer {
309    /// Clones the serializer.
310    ///
311    /// The clone of a serializer that writes a value in parts cannot write
312    /// more values (see
313    /// [`StreamSerializer::in_progress`](ser::StreamSerializer::in_progress)).
314    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    /// Creates a serializer.
338    pub fn new() -> Serializer {
339        Serializer::with_config(SerializerConfig::new())
340    }
341
342    /// Creates a serializer with the given configuration.
343    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    /// Returns the configuration.
354    pub fn config(&self) -> &SerializerConfig {
355        &self.config
356    }
357
358    /// Returns `true` once the value was written.
359    pub fn written(&self) -> bool {
360        self.written
361    }
362
363    /// Serializes a value.
364    ///
365    /// A property list holds a single value, serializing a second value
366    /// fails.
367    pub fn serialize<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
368        ser::Serializer::serialize(self, value)
369    }
370
371    /// Serializes a value with a configured driver.
372    ///
373    /// The callback is invoked with the driver before the value is
374    /// serialized, for instance to add [`Layer`](deser_core::ser::Layer)s.
375    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    /// Returns the output written so far (that was not cleared).
387    pub fn output(&self) -> &[u8] {
388        &self.out
389    }
390
391    /// Returns the output.
392    pub fn finish(self) -> Vec<u8> {
393        self.out
394    }
395
396    /// Fails if a value was written or is being written.
397    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    /// XML and OpenStep property lists are written in parts.
439    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        // the parts of a value that failed stay written (see
459        // `in_progress`)
460        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    /// Creates a writer of a property list (see
480    /// [`deser::io::Writer`](deser_core::io::Writer)).
481    ///
482    /// A stream holds a single property list, writing a second value fails.
483    /// XML and OpenStep property lists are written in parts while the value
484    /// is serialized.  Binary property lists are written once the value is
485    /// complete as the object table needs all objects.
486    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    /// Serializes a value to a writer.
491    ///
492    /// See [`to_writer`].
493    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/// Serializes a value to a writer as XML property list.
503///
504/// To write other formats use [`SerializerConfig::to_writer`].
505///
506/// ```
507/// let mut out = Vec::new();
508/// deser_plist::to_writer(&mut out, &true).unwrap();
509/// assert!(out.ends_with(b"<true/>\n</plist>\n"));
510/// ```
511#[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
519/// Serializes a value to an XML property list.
520///
521/// This uses the default [`SerializerConfig`].
522///
523/// ```
524/// let bytes = deser_plist::to_vec(&vec!["a", "b"]).unwrap();
525/// assert!(bytes.ends_with(b"<array>\n\t<string>a</string>\n\t<string>b</string>\n</array>\n</plist>\n"));
526/// ```
527pub fn to_vec<T: Serialize + ?Sized>(value: &T) -> Result<Vec<u8>, Error> {
528    SerializerConfig::new().to_vec(value)
529}
530
531/// Serializes a value to an XML property list in a string.
532///
533/// This uses the default [`SerializerConfig`].
534pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, Error> {
535    SerializerConfig::new().to_string(value)
536}
537
538/// A value of a property list.
539pub(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
552/// The values of a property list, the first one is the top value.
553pub(crate) struct Tree {
554    pub(crate) nodes: Vec<Node>,
555}
556
557/// An open container of the builder.
558enum Open {
559    Array(usize, Vec<usize>),
560    Dict(usize, Vec<(String, usize)>, Option<String>),
561}
562
563/// Builds the tree from serialization events.
564#[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                // map entries with null values are skipped
614                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    /// Returns the open container a value was added to.
638    ///
639    /// If the value opened a container, it's on top of the stack and the
640    /// parent is below it.
641    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    /// Closes the innermost container.
664    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    /// Adds the value of the first event of a value.  Maps and sequences
677    /// are pushed to the stack.  Returns `None` for null.
678    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                // binary property lists store dates as seconds in a float
683                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
711/// Converts an atom into a node.  Returns `None` for null.
712pub(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        // property lists have binary data, bytes are never encoded
723        Atom::Bytes(value) => Node::Data(value.into_owned()),
724        Atom::Ext(ref ext) => return convert_ext(ext),
725        // values whose type was inferred from text are written as value
726        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    // offset date-times are instants, other date-times are strings
740    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    // numbers from text formats are integers if their text is one
759    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
773/// Converts a key into a string.
774pub(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}