summaryrefslogtreecommitdiffstats
path: root/third_party/rust/plist/src/value.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/plist/src/value.rs
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/plist/src/value.rs')
-rw-r--r--third_party/rust/plist/src/value.rs816
1 files changed, 816 insertions, 0 deletions
diff --git a/third_party/rust/plist/src/value.rs b/third_party/rust/plist/src/value.rs
new file mode 100644
index 0000000000..607479e400
--- /dev/null
+++ b/third_party/rust/plist/src/value.rs
@@ -0,0 +1,816 @@
+use std::{
+ fs::File,
+ io::{BufReader, BufWriter, Read, Seek, Write},
+ path::Path,
+};
+
+use crate::{
+ error::{self, Error, ErrorKind, EventKind},
+ stream::{
+ BinaryWriter, Event, Events, OwnedEvent, Reader, Writer, XmlReader, XmlWriteOptions,
+ XmlWriter,
+ },
+ u64_to_usize, Date, Dictionary, Integer, Uid,
+};
+
+/// Represents any plist value.
+#[derive(Clone, Debug, PartialEq)]
+#[non_exhaustive]
+pub enum Value {
+ Array(Vec<Value>),
+ Dictionary(Dictionary),
+ Boolean(bool),
+ Data(Vec<u8>),
+ Date(Date),
+ Real(f64),
+ Integer(Integer),
+ String(String),
+ Uid(Uid),
+}
+
+impl Value {
+ /// Reads a `Value` from a plist file of any encoding.
+ pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Value, Error> {
+ let file = File::open(path).map_err(error::from_io_without_position)?;
+ Value::from_reader(BufReader::new(file))
+ }
+
+ /// Reads a `Value` from a seekable byte stream containing a plist of any encoding.
+ pub fn from_reader<R: Read + Seek>(reader: R) -> Result<Value, Error> {
+ let reader = Reader::new(reader);
+ Value::from_events(reader)
+ }
+
+ /// Reads a `Value` from a seekable byte stream containing an XML encoded plist.
+ pub fn from_reader_xml<R: Read>(reader: R) -> Result<Value, Error> {
+ let reader = XmlReader::new(reader);
+ Value::from_events(reader)
+ }
+
+ /// Serializes a `Value` to a file as a binary encoded plist.
+ pub fn to_file_binary<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
+ let mut file = File::create(path).map_err(error::from_io_without_position)?;
+ self.to_writer_binary(BufWriter::new(&mut file))?;
+ file.sync_all().map_err(error::from_io_without_position)?;
+ Ok(())
+ }
+
+ /// Serializes a `Value` to a file as an XML encoded plist.
+ pub fn to_file_xml<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
+ let mut file = File::create(path).map_err(error::from_io_without_position)?;
+ self.to_writer_xml(BufWriter::new(&mut file))?;
+ file.sync_all().map_err(error::from_io_without_position)?;
+ Ok(())
+ }
+
+ /// Serializes a `Value` to a byte stream as a binary encoded plist.
+ pub fn to_writer_binary<W: Write>(&self, writer: W) -> Result<(), Error> {
+ let mut writer = BinaryWriter::new(writer);
+ self.to_writer_inner(&mut writer)
+ }
+
+ /// Serializes a `Value` to a byte stream as an XML encoded plist.
+ pub fn to_writer_xml<W: Write>(&self, writer: W) -> Result<(), Error> {
+ self.to_writer_xml_with_options(writer, &XmlWriteOptions::default())
+ }
+
+ /// Serializes a `Value` to a stream, using custom [`XmlWriteOptions`].
+ ///
+ /// If you need to serialize to a file, you must acquire an appropriate
+ /// `Write` handle yourself.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::{BufWriter, Write};
+ /// use std::fs::File;
+ /// use plist::{Dictionary, Value, XmlWriteOptions};
+ ///
+ /// let value: Value = Dictionary::new().into();
+ /// // .. add some keys & values
+ /// let mut file = File::create("com.example.myPlist.plist").unwrap();
+ /// let options = XmlWriteOptions::default().indent_string(" ");
+ /// value.to_writer_xml_with_options(BufWriter::new(&mut file), &options).unwrap();
+ /// file.sync_all().unwrap();
+ /// ```
+ pub fn to_writer_xml_with_options<W: Write>(
+ &self,
+ writer: W,
+ options: &XmlWriteOptions,
+ ) -> Result<(), Error> {
+ let mut writer = XmlWriter::new_with_options(writer, options);
+ self.to_writer_inner(&mut writer)
+ }
+
+ fn to_writer_inner(&self, writer: &mut dyn Writer) -> Result<(), Error> {
+ let events = self.events();
+ for event in events {
+ writer.write(&event)?;
+ }
+ Ok(())
+ }
+
+ /// Builds a single `Value` from an `Event` iterator.
+ /// On success any excess `Event`s will remain in the iterator.
+ #[cfg(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps")]
+ pub fn from_events<T>(events: T) -> Result<Value, Error>
+ where
+ T: IntoIterator<Item = Result<OwnedEvent, Error>>,
+ {
+ Builder::new(events.into_iter()).build()
+ }
+
+ /// Builds a single `Value` from an `Event` iterator.
+ /// On success any excess `Event`s will remain in the iterator.
+ #[cfg(not(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"))]
+ pub(crate) fn from_events<T>(events: T) -> Result<Value, Error>
+ where
+ T: IntoIterator<Item = Result<OwnedEvent, Error>>,
+ {
+ Builder::new(events.into_iter()).build()
+ }
+
+ /// Converts a `Value` into an `Event` iterator.
+ #[cfg(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps")]
+ #[doc(hidden)]
+ #[deprecated(since = "1.2.0", note = "use Value::events instead")]
+ pub fn into_events(&self) -> Events {
+ self.events()
+ }
+
+ /// Creates an `Event` iterator for this `Value`.
+ #[cfg(not(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"))]
+ pub(crate) fn events(&self) -> Events {
+ Events::new(self)
+ }
+
+ /// Creates an `Event` iterator for this `Value`.
+ #[cfg(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps")]
+ pub fn events(&self) -> Events {
+ Events::new(self)
+ }
+
+ /// If the `Value` is a Array, returns the underlying `Vec`.
+ ///
+ /// Returns `None` otherwise.
+ ///
+ /// This method consumes the `Value`. To get a reference instead, use
+ /// `as_array`.
+ pub fn into_array(self) -> Option<Vec<Value>> {
+ match self {
+ Value::Array(dict) => Some(dict),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is an Array, returns the associated `Vec`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_array(&self) -> Option<&Vec<Value>> {
+ match *self {
+ Value::Array(ref array) => Some(array),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is an Array, returns the associated mutable `Vec`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
+ match *self {
+ Value::Array(ref mut array) => Some(array),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Dictionary, returns the associated `BTreeMap`.
+ ///
+ /// Returns `None` otherwise.
+ ///
+ /// This method consumes the `Value`. To get a reference instead, use
+ /// `as_dictionary`.
+ pub fn into_dictionary(self) -> Option<Dictionary> {
+ match self {
+ Value::Dictionary(dict) => Some(dict),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Dictionary, returns the associated `BTreeMap`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_dictionary(&self) -> Option<&Dictionary> {
+ match *self {
+ Value::Dictionary(ref dict) => Some(dict),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Dictionary, returns the associated mutable `BTreeMap`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_dictionary_mut(&mut self) -> Option<&mut Dictionary> {
+ match *self {
+ Value::Dictionary(ref mut dict) => Some(dict),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Boolean, returns the associated `bool`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_boolean(&self) -> Option<bool> {
+ match *self {
+ Value::Boolean(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Data, returns the underlying `Vec`.
+ ///
+ /// Returns `None` otherwise.
+ ///
+ /// This method consumes the `Value`. If this is not desired, please use
+ /// `as_data` method.
+ pub fn into_data(self) -> Option<Vec<u8>> {
+ match self {
+ Value::Data(data) => Some(data),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Data, returns the associated `Vec`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_data(&self) -> Option<&[u8]> {
+ match *self {
+ Value::Data(ref data) => Some(data),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Date, returns the associated `Date`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_date(&self) -> Option<Date> {
+ match *self {
+ Value::Date(date) => Some(date),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Real, returns the associated `f64`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_real(&self) -> Option<f64> {
+ match *self {
+ Value::Real(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a signed Integer, returns the associated `i64`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_signed_integer(&self) -> Option<i64> {
+ match *self {
+ Value::Integer(v) => v.as_signed(),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is an unsigned Integer, returns the associated `u64`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_unsigned_integer(&self) -> Option<u64> {
+ match *self {
+ Value::Integer(v) => v.as_unsigned(),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a String, returns the underlying `String`.
+ ///
+ /// Returns `None` otherwise.
+ ///
+ /// This method consumes the `Value`. If this is not desired, please use
+ /// `as_string` method.
+ pub fn into_string(self) -> Option<String> {
+ match self {
+ Value::String(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a String, returns the associated `str`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_string(&self) -> Option<&str> {
+ match *self {
+ Value::String(ref v) => Some(v),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Uid, returns the underlying `Uid`.
+ ///
+ /// Returns `None` otherwise.
+ ///
+ /// This method consumes the `Value`. If this is not desired, please use
+ /// `as_uid` method.
+ pub fn into_uid(self) -> Option<Uid> {
+ match self {
+ Value::Uid(u) => Some(u),
+ _ => None,
+ }
+ }
+
+ /// If the `Value` is a Uid, returns the associated `Uid`.
+ ///
+ /// Returns `None` otherwise.
+ pub fn as_uid(&self) -> Option<&Uid> {
+ match *self {
+ Value::Uid(ref u) => Some(u),
+ _ => None,
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+pub mod serde_impls {
+ use serde::{
+ de,
+ de::{EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor},
+ ser,
+ };
+
+ use crate::{
+ date::serde_impls::DATE_NEWTYPE_STRUCT_NAME, uid::serde_impls::UID_NEWTYPE_STRUCT_NAME,
+ Dictionary, Value,
+ };
+
+ pub const VALUE_NEWTYPE_STRUCT_NAME: &str = "PLIST-VALUE";
+
+ impl ser::Serialize for Value {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ match *self {
+ Value::Array(ref v) => v.serialize(serializer),
+ Value::Dictionary(ref m) => m.serialize(serializer),
+ Value::Boolean(b) => serializer.serialize_bool(b),
+ Value::Data(ref v) => serializer.serialize_bytes(v),
+ Value::Date(d) => d.serialize(serializer),
+ Value::Real(n) => serializer.serialize_f64(n),
+ Value::Integer(n) => n.serialize(serializer),
+ Value::String(ref s) => serializer.serialize_str(s),
+ Value::Uid(ref u) => u.serialize(serializer),
+ }
+ }
+ }
+
+ impl<'de> de::Deserialize<'de> for Value {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ struct ValueVisitor;
+
+ impl<'de> Visitor<'de> for ValueVisitor {
+ type Value = Value;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ formatter.write_str("any supported plist value")
+ }
+
+ fn visit_bool<E>(self, value: bool) -> Result<Value, E> {
+ Ok(Value::Boolean(value))
+ }
+
+ fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Value, E> {
+ Ok(Value::Data(v))
+ }
+
+ fn visit_bytes<E>(self, v: &[u8]) -> Result<Value, E> {
+ Ok(Value::Data(v.to_vec()))
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Value, E> {
+ Ok(Value::Integer(value.into()))
+ }
+
+ fn visit_u64<E>(self, value: u64) -> Result<Value, E> {
+ Ok(Value::Integer(value.into()))
+ }
+
+ fn visit_f64<E>(self, value: f64) -> Result<Value, E> {
+ Ok(Value::Real(value))
+ }
+
+ fn visit_map<V>(self, mut map: V) -> Result<Value, V::Error>
+ where
+ V: MapAccess<'de>,
+ {
+ let mut values = Dictionary::new();
+ while let Some((k, v)) = map.next_entry()? {
+ values.insert(k, v);
+ }
+ Ok(Value::Dictionary(values))
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Value, E> {
+ Ok(Value::String(value.to_owned()))
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Value, E> {
+ Ok(Value::String(value))
+ }
+
+ fn visit_newtype_struct<T>(self, deserializer: T) -> Result<Value, T::Error>
+ where
+ T: de::Deserializer<'de>,
+ {
+ deserializer.deserialize_any(self)
+ }
+
+ fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or(0));
+ while let Some(elem) = seq.next_element()? {
+ vec.push(elem);
+ }
+ Ok(Value::Array(vec))
+ }
+
+ fn visit_enum<A>(self, data: A) -> Result<Value, A::Error>
+ where
+ A: EnumAccess<'de>,
+ {
+ let (name, variant) = data.variant::<String>()?;
+ match &*name {
+ DATE_NEWTYPE_STRUCT_NAME => Ok(Value::Date(variant.newtype_variant()?)),
+ UID_NEWTYPE_STRUCT_NAME => Ok(Value::Uid(variant.newtype_variant()?)),
+ _ => Err(de::Error::unknown_variant(
+ &name,
+ &[DATE_NEWTYPE_STRUCT_NAME, UID_NEWTYPE_STRUCT_NAME],
+ )),
+ }
+ }
+ }
+
+ // Serde serialisers are encouraged to treat newtype structs as insignificant
+ // wrappers around the data they contain. That means not parsing anything other
+ // than the contained value. Therefore, this should not prevent using `Value`
+ // with other `Serializer`s.
+ deserializer.deserialize_newtype_struct(VALUE_NEWTYPE_STRUCT_NAME, ValueVisitor)
+ }
+ }
+}
+
+impl From<Vec<Value>> for Value {
+ fn from(from: Vec<Value>) -> Value {
+ Value::Array(from)
+ }
+}
+
+impl From<Dictionary> for Value {
+ fn from(from: Dictionary) -> Value {
+ Value::Dictionary(from)
+ }
+}
+
+impl From<bool> for Value {
+ fn from(from: bool) -> Value {
+ Value::Boolean(from)
+ }
+}
+
+impl<'a> From<&'a bool> for Value {
+ fn from(from: &'a bool) -> Value {
+ Value::Boolean(*from)
+ }
+}
+
+impl From<Date> for Value {
+ fn from(from: Date) -> Value {
+ Value::Date(from)
+ }
+}
+
+impl<'a> From<&'a Date> for Value {
+ fn from(from: &'a Date) -> Value {
+ Value::Date(*from)
+ }
+}
+
+impl From<f64> for Value {
+ fn from(from: f64) -> Value {
+ Value::Real(from)
+ }
+}
+
+impl From<f32> for Value {
+ fn from(from: f32) -> Value {
+ Value::Real(from.into())
+ }
+}
+
+impl From<i64> for Value {
+ fn from(from: i64) -> Value {
+ Value::Integer(Integer::from(from))
+ }
+}
+
+impl From<i32> for Value {
+ fn from(from: i32) -> Value {
+ Value::Integer(Integer::from(from))
+ }
+}
+
+impl From<i16> for Value {
+ fn from(from: i16) -> Value {
+ Value::Integer(Integer::from(from))
+ }
+}
+
+impl From<i8> for Value {
+ fn from(from: i8) -> Value {
+ Value::Integer(Integer::from(from))
+ }
+}
+
+impl From<u64> for Value {
+ fn from(from: u64) -> Value {
+ Value::Integer(Integer::from(from))
+ }
+}
+
+impl From<u32> for Value {
+ fn from(from: u32) -> Value {
+ Value::Integer(Integer::from(from))
+ }
+}
+
+impl From<u16> for Value {
+ fn from(from: u16) -> Value {
+ Value::Integer(Integer::from(from))
+ }
+}
+
+impl From<u8> for Value {
+ fn from(from: u8) -> Value {
+ Value::Integer(Integer::from(from))
+ }
+}
+
+impl<'a> From<&'a f64> for Value {
+ fn from(from: &'a f64) -> Value {
+ Value::Real(*from)
+ }
+}
+
+impl<'a> From<&'a f32> for Value {
+ fn from(from: &'a f32) -> Value {
+ Value::Real((*from).into())
+ }
+}
+
+impl<'a> From<&'a i64> for Value {
+ fn from(from: &'a i64) -> Value {
+ Value::Integer(Integer::from(*from))
+ }
+}
+
+impl<'a> From<&'a i32> for Value {
+ fn from(from: &'a i32) -> Value {
+ Value::Integer(Integer::from(*from))
+ }
+}
+
+impl<'a> From<&'a i16> for Value {
+ fn from(from: &'a i16) -> Value {
+ Value::Integer(Integer::from(*from))
+ }
+}
+
+impl<'a> From<&'a i8> for Value {
+ fn from(from: &'a i8) -> Value {
+ Value::Integer(Integer::from(*from))
+ }
+}
+
+impl<'a> From<&'a u64> for Value {
+ fn from(from: &'a u64) -> Value {
+ Value::Integer(Integer::from(*from))
+ }
+}
+
+impl<'a> From<&'a u32> for Value {
+ fn from(from: &'a u32) -> Value {
+ Value::Integer(Integer::from(*from))
+ }
+}
+
+impl<'a> From<&'a u16> for Value {
+ fn from(from: &'a u16) -> Value {
+ Value::Integer((*from).into())
+ }
+}
+
+impl<'a> From<&'a u8> for Value {
+ fn from(from: &'a u8) -> Value {
+ Value::Integer((*from).into())
+ }
+}
+
+impl From<String> for Value {
+ fn from(from: String) -> Value {
+ Value::String(from)
+ }
+}
+
+impl<'a> From<&'a str> for Value {
+ fn from(from: &'a str) -> Value {
+ Value::String(from.into())
+ }
+}
+
+struct Builder<T> {
+ stream: T,
+ token: Option<OwnedEvent>,
+}
+
+impl<T: Iterator<Item = Result<OwnedEvent, Error>>> Builder<T> {
+ fn new(stream: T) -> Builder<T> {
+ Builder {
+ stream,
+ token: None,
+ }
+ }
+
+ fn build(mut self) -> Result<Value, Error> {
+ self.bump()?;
+ self.build_value()
+ }
+
+ fn bump(&mut self) -> Result<(), Error> {
+ self.token = match self.stream.next() {
+ Some(Ok(token)) => Some(token),
+ Some(Err(err)) => return Err(err),
+ None => None,
+ };
+ Ok(())
+ }
+
+ fn build_value(&mut self) -> Result<Value, Error> {
+ match self.token.take() {
+ Some(Event::StartArray(len)) => Ok(Value::Array(self.build_array(len)?)),
+ Some(Event::StartDictionary(len)) => Ok(Value::Dictionary(self.build_dict(len)?)),
+
+ Some(Event::Boolean(b)) => Ok(Value::Boolean(b)),
+ Some(Event::Data(d)) => Ok(Value::Data(d.into_owned())),
+ Some(Event::Date(d)) => Ok(Value::Date(d)),
+ Some(Event::Integer(i)) => Ok(Value::Integer(i)),
+ Some(Event::Real(f)) => Ok(Value::Real(f)),
+ Some(Event::String(s)) => Ok(Value::String(s.into_owned())),
+ Some(Event::Uid(u)) => Ok(Value::Uid(u)),
+
+ Some(event @ Event::EndCollection) => Err(error::unexpected_event_type(
+ EventKind::ValueOrStartCollection,
+ &event,
+ )),
+
+ None => Err(ErrorKind::UnexpectedEndOfEventStream.without_position()),
+ }
+ }
+
+ fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Value>, Error> {
+ let mut values = match len.and_then(u64_to_usize) {
+ Some(len) => Vec::with_capacity(len),
+ None => Vec::new(),
+ };
+
+ loop {
+ self.bump()?;
+ if let Some(Event::EndCollection) = self.token {
+ self.token.take();
+ return Ok(values);
+ }
+ values.push(self.build_value()?);
+ }
+ }
+
+ fn build_dict(&mut self, _len: Option<u64>) -> Result<Dictionary, Error> {
+ let mut dict = Dictionary::new();
+
+ loop {
+ self.bump()?;
+ match self.token.take() {
+ Some(Event::EndCollection) => return Ok(dict),
+ Some(Event::String(s)) => {
+ self.bump()?;
+ dict.insert(s.into_owned(), self.build_value()?);
+ }
+ Some(event) => {
+ return Err(error::unexpected_event_type(
+ EventKind::DictionaryKeyOrEndCollection,
+ &event,
+ ))
+ }
+ None => return Err(ErrorKind::UnexpectedEndOfEventStream.without_position()),
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::time::SystemTime;
+
+ use super::*;
+ use crate::{stream::Event::*, Date, Dictionary, Value};
+
+ #[test]
+ fn value_accessors() {
+ let vec = vec![Value::Real(0.0)];
+ let mut array = Value::Array(vec.clone());
+ assert_eq!(array.as_array(), Some(&vec.clone()));
+ assert_eq!(array.as_array_mut(), Some(&mut vec.clone()));
+
+ let mut map = Dictionary::new();
+ map.insert("key1".to_owned(), Value::String("value1".to_owned()));
+ let mut dict = Value::Dictionary(map.clone());
+ assert_eq!(dict.as_dictionary(), Some(&map.clone()));
+ assert_eq!(dict.as_dictionary_mut(), Some(&mut map.clone()));
+
+ assert_eq!(Value::Boolean(true).as_boolean(), Some(true));
+
+ let slice: &[u8] = &[1, 2, 3];
+ assert_eq!(Value::Data(slice.to_vec()).as_data(), Some(slice));
+ assert_eq!(
+ Value::Data(slice.to_vec()).into_data(),
+ Some(slice.to_vec())
+ );
+
+ let date: Date = SystemTime::now().into();
+ assert_eq!(Value::Date(date.clone()).as_date(), Some(date));
+
+ assert_eq!(Value::Real(0.0).as_real(), Some(0.0));
+ assert_eq!(Value::Integer(1.into()).as_signed_integer(), Some(1));
+ assert_eq!(Value::Integer(1.into()).as_unsigned_integer(), Some(1));
+ assert_eq!(Value::Integer((-1).into()).as_unsigned_integer(), None);
+ assert_eq!(
+ Value::Integer((i64::max_value() as u64 + 1).into()).as_signed_integer(),
+ None
+ );
+ assert_eq!(Value::String("2".to_owned()).as_string(), Some("2"));
+ assert_eq!(
+ Value::String("t".to_owned()).into_string(),
+ Some("t".to_owned())
+ );
+ }
+
+ #[test]
+ fn builder() {
+ // Input
+ let events = vec![
+ StartDictionary(None),
+ String("Author".into()),
+ String("William Shakespeare".into()),
+ String("Lines".into()),
+ StartArray(None),
+ String("It is a tale told by an idiot,".into()),
+ String("Full of sound and fury, signifying nothing.".into()),
+ EndCollection,
+ String("Birthdate".into()),
+ Integer(1564.into()),
+ String("Height".into()),
+ Real(1.60),
+ EndCollection,
+ ];
+
+ let builder = Builder::new(events.into_iter().map(|e| Ok(e)));
+ let plist = builder.build();
+
+ // Expected output
+ let mut lines = Vec::new();
+ lines.push(Value::String("It is a tale told by an idiot,".to_owned()));
+ lines.push(Value::String(
+ "Full of sound and fury, signifying nothing.".to_owned(),
+ ));
+
+ let mut dict = Dictionary::new();
+ dict.insert(
+ "Author".to_owned(),
+ Value::String("William Shakespeare".to_owned()),
+ );
+ dict.insert("Lines".to_owned(), Value::Array(lines));
+ dict.insert("Birthdate".to_owned(), Value::Integer(1564.into()));
+ dict.insert("Height".to_owned(), Value::Real(1.60));
+
+ assert_eq!(plist.unwrap(), Value::Dictionary(dict));
+ }
+}