зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1770894 - Update plist to 1.2.1. r=webdriver-reviewers,jgraham
Differential Revision: https://phabricator.services.mozilla.com/D147252
This commit is contained in:
Родитель
acda3972e3
Коммит
9cbe1bbc92
|
@ -4007,11 +4007,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "0.5.5"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b59eb8d91dfa89208ec74a920e3b55f840476cf46568026c18dbaa2999e0d48"
|
||||
checksum = "a38d026d73eeaf2ade76309d0c65db5a35ecf649e3cec428db316243ea9d6711"
|
||||
dependencies = [
|
||||
"base64 0.10.1",
|
||||
"base64 0.13.0",
|
||||
"chrono",
|
||||
"indexmap",
|
||||
"line-wrap",
|
||||
|
|
|
@ -10,7 +10,7 @@ edition = "2018"
|
|||
[dependencies]
|
||||
log = "0.4"
|
||||
mozprofile = { path = "../mozprofile", version = "0.8" }
|
||||
plist = "0.5"
|
||||
plist = "1.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winreg = "0.5"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"6aa3f3fc9add0eca0664cee0ad9b97a86b532964d053a09a860979e6ad94c0ab","LICENCE":"5b0ae40d1a35f7ae6591a28e44771240e6a88cb03a66c9189a45b9681639b466","README.md":"98860ec5d46ac8f1d3a3f33600629b942f774a35a511ddedffc9a227a3822e2c","rustfmt.toml":"9bbb759b3914c49c8060bcdeeb7786f4aec083d30bcfe236bbd48d8388d06103","src/date.rs":"c14f616d03708b44b53c4e7037129f31e07e9f45dc63e282bdd2d744a52c3b95","src/de.rs":"dad0b0409227223deb2778a3f63c7d355c1b642f406fc448e59224de61882770","src/dictionary.rs":"9b8194d3e339a300de5d0fb39529d976a5f86947f3997086594d2be2f795859b","src/error.rs":"2ed8ce5c33071847abb00b27472be352d5bceb92a6ad0b8724f630570e956430","src/integer.rs":"131f528878adc5c0f33c8ad1563c06b397cb2ae5148c2bb9318203a2477d70e0","src/lib.rs":"1fa5d06242ec2731f16d244e070710476caf165eb1707a1d688357928eae2310","src/ser.rs":"ea4ed049abef09c7230b94296a3d050ade3228cfededea2c17383028b594fe10","src/serde_tests.rs":"9b273b56936bfc88ecd8e763b3d49c5e911dc7267f1794437959cb61b2c6cdd3","src/stream/binary_reader.rs":"e3fe72e3c6bf6bf4dd271919018c9f8bfd90d4ddf203c80242f8f6ca705b1d49","src/stream/binary_writer.rs":"1b10bbf287ad48be3a82c36cebbc32f7232fff42995142e09f98d2a2eb1fb628","src/stream/mod.rs":"2482d63cd50cceaf4b4fc46ddb11119b1a7c55bf3350e69ce2546317ff3f89e2","src/stream/xml_reader.rs":"b7de932fa9f521eaa13a908a01235d8a1d66b2254425a361268b6ccb9e35996d","src/stream/xml_writer.rs":"6bbd2beed1e82aa8de4f3523a5a483b5132e8e7c2119bf789555d88f2dadbb9a","src/uid.rs":"adb51121ee251941f173d83417631cd2fdfbc7104998205c538d93e4b3c3e676","src/value.rs":"8fca3d563723a55be3fc6f71cd17fe7e6ad33240d83d20e6420e718033c066cd","tests/data/binary.plist":"728985bb53486a92fdcc901a3c08a904835f0225efab7b85be2734e2dcd4af83","tests/data/binary_NSKeyedArchiver.plist":"54dc8b87acd364de6b2160ff805514bc04bf0577e4f57d08d7f3578d218362f0","tests/data/binary_circular_array.plist":"825aed6ce83a8abdbe15d4686ce35157f4eb861bd792f0ce790115fb4ec48805","tests/data/binary_zero_offset_size.plist":"020953c8211989d01b5edf42e025560f46ece3b604ceda03708819bd2587a1a1","tests/data/book.plist":"3b18050f073cab956f38f1775e89dedc88d1e56dd388bc99e277efb19e50dffd","tests/data/utf16_bplist.plist":"c0b7d33001021df98d8631c604c8471e74e4b4599bac51a8bed149ca82adbcd5","tests/data/xml.plist":"9669e8ad25a661ca052d30d8d74b7495e859a0a7faf01f2aeade7fcebb2aa5b7","tests/data/xml_error.plist":"3718f7dd2c716a4a6c36d1f7055b78d86c982c812c19964f85a6f62eff1589ea","tests/fuzzer.rs":"ea9e7812c936e4c1e42ce234513fa8c839277222c0746c069d62e7b77870b858"},"package":"9b59eb8d91dfa89208ec74a920e3b55f840476cf46568026c18dbaa2999e0d48"}
|
||||
{"files":{"Cargo.toml":"bde02d9bcdc1cc5ef099fb2afa21345f170b2646afd18cbbf9a3bfab563a6bf9","LICENCE":"5b0ae40d1a35f7ae6591a28e44771240e6a88cb03a66c9189a45b9681639b466","README.md":"25091b2b53ea578f6fc369259070938eaeea06a0b7ba7a81b50da503198345ed","rustfmt.toml":"9bbb759b3914c49c8060bcdeeb7786f4aec083d30bcfe236bbd48d8388d06103","src/date.rs":"c14f616d03708b44b53c4e7037129f31e07e9f45dc63e282bdd2d744a52c3b95","src/de.rs":"12de6721323a6bc47238388e23c345664ca9efd8a106c9705e1c0510b62bd963","src/dictionary.rs":"96815436417473ab0b1c4909f3c46ec14274cc20ec10945c8e19ee1fcf773156","src/error.rs":"cd4d6e85e003995d9ecdf8acb43f6c2379f1c910c5c3d78835c28ae32556b3d2","src/integer.rs":"131f528878adc5c0f33c8ad1563c06b397cb2ae5148c2bb9318203a2477d70e0","src/lib.rs":"893b8c3e019c772edc116c907069eeb55874f245fb26d71b95d6f25c938e00f6","src/ser.rs":"960ee6ecc00a2b0478b1e2f5e65fd192af9474af9921c1b871659707ac4a33a5","src/serde_tests.rs":"bfb0a2376f8c2a8b12169742f2c52537bb5e9caf1bf285b373e9c9f096f8a0bf","src/stream/binary_reader.rs":"c2506a3f62dbaf23e8238969222d1582f04cf74d333cc94d766a74f717d5eab8","src/stream/binary_writer.rs":"1b10bbf287ad48be3a82c36cebbc32f7232fff42995142e09f98d2a2eb1fb628","src/stream/mod.rs":"b9210324a764bd0a9f5a5a0e22981024856fba1478f81594a123db59d16b7108","src/stream/xml_reader.rs":"5461e9601ad4e4a2853bab6ffb24062f9053f89a33cbcb91eca9566b20183354","src/stream/xml_writer.rs":"b39b4d67c62233b2761573b5c1256448c4af21d3deca4391b0e7d15cc015dac8","src/uid.rs":"adb51121ee251941f173d83417631cd2fdfbc7104998205c538d93e4b3c3e676","src/value.rs":"88fc4a74f7fe9d2424479d4c43740c0f1499b8f3fae40261f489d3e934c265f3","tests/data/binary.plist":"728985bb53486a92fdcc901a3c08a904835f0225efab7b85be2734e2dcd4af83","tests/data/binary_NSKeyedArchiver.plist":"54dc8b87acd364de6b2160ff805514bc04bf0577e4f57d08d7f3578d218362f0","tests/data/binary_circular_array.plist":"825aed6ce83a8abdbe15d4686ce35157f4eb861bd792f0ce790115fb4ec48805","tests/data/binary_zero_offset_size.plist":"020953c8211989d01b5edf42e025560f46ece3b604ceda03708819bd2587a1a1","tests/data/book.plist":"3b18050f073cab956f38f1775e89dedc88d1e56dd388bc99e277efb19e50dffd","tests/data/utf16_bplist.plist":"c0b7d33001021df98d8631c604c8471e74e4b4599bac51a8bed149ca82adbcd5","tests/data/xml.plist":"9669e8ad25a661ca052d30d8d74b7495e859a0a7faf01f2aeade7fcebb2aa5b7","tests/data/xml_error.plist":"3718f7dd2c716a4a6c36d1f7055b78d86c982c812c19964f85a6f62eff1589ea","tests/fuzzer.rs":"ea9e7812c936e4c1e42ce234513fa8c839277222c0746c069d62e7b77870b858"},"package":"a38d026d73eeaf2ade76309d0c65db5a35ecf649e3cec428db316243ea9d6711"}
|
|
@ -13,16 +13,16 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "plist"
|
||||
version = "0.5.5"
|
||||
version = "1.2.1"
|
||||
authors = ["Ed Barnard <eabarnard@gmail.com>"]
|
||||
description = "A rusty plist parser. Supports Serde serialization."
|
||||
documentation = "https://docs.rs/plist/0.5.5/plist/"
|
||||
documentation = "https://docs.rs/plist/1.2.1/plist/"
|
||||
keywords = ["plist", "parser"]
|
||||
categories = ["config", "encoding", "parser-implementations"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/ebarnard/rust-plist/"
|
||||
[dependencies.base64]
|
||||
version = "0.10.1"
|
||||
version = "0.13.0"
|
||||
|
||||
[dependencies.chrono]
|
||||
version = "0.4.11"
|
||||
|
|
|
@ -4,6 +4,4 @@ A rusty plist parser.
|
|||
|
||||
Many features from previous versions are now hidden behind the `enable_unstable_features_that_may_break_with_minor_version_bumps` feature. These will break in minor version releases after the 1.0 release. If you really really must use them you should specify a tilde requirement e.g. `plist = "~1.0.3"` in you `Cargo.toml` so that the plist crate is not automatically updated to version 1.1.
|
||||
|
||||
[![Build Status](https://travis-ci.org/ebarnard/rust-plist.svg?branch=master)](https://travis-ci.org/ebarnard/rust-plist)
|
||||
|
||||
[Documentation](https://docs.rs/plist/)
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
|||
|
||||
use crate::{
|
||||
error::{self, Error, ErrorKind, EventKind},
|
||||
stream::{self, Event},
|
||||
stream::{self, Event, OwnedEvent},
|
||||
u64_to_usize,
|
||||
};
|
||||
|
||||
|
@ -53,7 +53,7 @@ enum OptionMode {
|
|||
/// A structure that deserializes plist event streams into Rust values.
|
||||
pub struct Deserializer<I>
|
||||
where
|
||||
I: IntoIterator<Item = Result<Event, Error>>,
|
||||
I: IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
events: Peekable<<I as IntoIterator>::IntoIter>,
|
||||
option_mode: OptionMode,
|
||||
|
@ -61,7 +61,7 @@ where
|
|||
|
||||
impl<I> Deserializer<I>
|
||||
where
|
||||
I: IntoIterator<Item = Result<Event, Error>>,
|
||||
I: IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
pub fn new(iter: I) -> Deserializer<I> {
|
||||
Deserializer {
|
||||
|
@ -84,7 +84,7 @@ where
|
|||
|
||||
impl<'de, 'a, I> de::Deserializer<'de> for &'a mut Deserializer<I>
|
||||
where
|
||||
I: IntoIterator<Item = Result<Event, Error>>,
|
||||
I: IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
|
@ -111,7 +111,7 @@ where
|
|||
)),
|
||||
|
||||
Event::Boolean(v) => visitor.visit_bool(v),
|
||||
Event::Data(v) => visitor.visit_byte_buf(v),
|
||||
Event::Data(v) => visitor.visit_byte_buf(v.into_owned()),
|
||||
Event::Date(v) => visitor.visit_string(v.to_rfc3339()),
|
||||
Event::Integer(v) => {
|
||||
if let Some(v) = v.as_unsigned() {
|
||||
|
@ -123,7 +123,7 @@ where
|
|||
}
|
||||
}
|
||||
Event::Real(v) => visitor.visit_f64(v),
|
||||
Event::String(v) => visitor.visit_string(v),
|
||||
Event::String(v) => visitor.visit_string(v.into_owned()),
|
||||
Event::Uid(v) => visitor.visit_u64(v.get()),
|
||||
|
||||
Event::__Nonexhaustive => unreachable!(),
|
||||
|
@ -207,13 +207,19 @@ where
|
|||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_enum: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
name: &'static str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
// `plist` since v1.1 serialises unit enum variants as plain strings.
|
||||
if let Some(Ok(Event::String(s))) = self.events.peek() {
|
||||
return de::IntoDeserializer::into_deserializer(s.as_ref())
|
||||
.deserialize_enum(name, variants, visitor);
|
||||
}
|
||||
|
||||
expect!(self.events.next(), EventKind::StartDictionary);
|
||||
let ret = visitor.visit_enum(&mut *self)?;
|
||||
expect!(self.events.next(), EventKind::EndCollection);
|
||||
|
@ -223,7 +229,7 @@ where
|
|||
|
||||
impl<'de, 'a, I> de::EnumAccess<'de> for &'a mut Deserializer<I>
|
||||
where
|
||||
I: IntoIterator<Item = Result<Event, Error>>,
|
||||
I: IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
type Error = Error;
|
||||
type Variant = Self;
|
||||
|
@ -238,7 +244,7 @@ where
|
|||
|
||||
impl<'de, 'a, I> de::VariantAccess<'de> for &'a mut Deserializer<I>
|
||||
where
|
||||
I: IntoIterator<Item = Result<Event, Error>>,
|
||||
I: IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
|
@ -275,7 +281,7 @@ where
|
|||
|
||||
struct MapAndSeqAccess<'a, I>
|
||||
where
|
||||
I: 'a + IntoIterator<Item = Result<Event, Error>>,
|
||||
I: 'a + IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
de: &'a mut Deserializer<I>,
|
||||
is_struct: bool,
|
||||
|
@ -284,7 +290,7 @@ where
|
|||
|
||||
impl<'a, I> MapAndSeqAccess<'a, I>
|
||||
where
|
||||
I: 'a + IntoIterator<Item = Result<Event, Error>>,
|
||||
I: 'a + IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
fn new(
|
||||
de: &'a mut Deserializer<I>,
|
||||
|
@ -301,7 +307,7 @@ where
|
|||
|
||||
impl<'de, 'a, I> de::SeqAccess<'de> for MapAndSeqAccess<'a, I>
|
||||
where
|
||||
I: 'a + IntoIterator<Item = Result<Event, Error>>,
|
||||
I: 'a + IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
|
@ -326,7 +332,7 @@ where
|
|||
|
||||
impl<'de, 'a, I> de::MapAccess<'de> for MapAndSeqAccess<'a, I>
|
||||
where
|
||||
I: 'a + IntoIterator<Item = Result<Event, Error>>,
|
||||
I: 'a + IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
|
|
|
@ -70,6 +70,27 @@ impl Dictionary {
|
|||
self.map.remove(key)
|
||||
}
|
||||
|
||||
/// Scan through each key-value pair in the map and keep those where the
|
||||
/// closure `keep` returns `true`.
|
||||
#[inline]
|
||||
pub fn retain<F>(&mut self, keep: F)
|
||||
where
|
||||
F: FnMut(&String, &mut Value) -> bool,
|
||||
{
|
||||
self.map.retain(keep)
|
||||
}
|
||||
|
||||
/// Sort the dictionary keys.
|
||||
///
|
||||
/// This uses the default ordering defined on [`str`].
|
||||
///
|
||||
/// This function is useful if you are serializing to XML, and wish to
|
||||
/// ensure a consistent key order.
|
||||
#[inline]
|
||||
pub fn sort_keys(&mut self) {
|
||||
self.map.sort_keys()
|
||||
}
|
||||
|
||||
/// Gets the given key's corresponding entry in the dictionary for in-place manipulation.
|
||||
// Entry functionality is unstable until I can figure out how to use either Cow<str> or
|
||||
// T: AsRef<str> + Into<String>
|
||||
|
|
|
@ -128,7 +128,24 @@ impl error::Error for Error {
|
|||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.inner.kind, f)
|
||||
if let Some(position) = &self.inner.file_position {
|
||||
write!(f, "{:?} ({})", &self.inner.kind, position)
|
||||
} else {
|
||||
fmt::Debug::fmt(&self.inner.kind, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FilePosition {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
FilePosition::LineColumn(line, column) => {
|
||||
write!(f, "line {}, column {}", line, column)
|
||||
}
|
||||
FilePosition::Offset(offset) => {
|
||||
write!(f, "offset {}", offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! plist = "0.5"
|
||||
//! plist = "1"
|
||||
//! ```
|
||||
//!
|
||||
//! And put this in your crate root:
|
||||
|
@ -89,6 +89,7 @@ pub use date::Date;
|
|||
pub use dictionary::Dictionary;
|
||||
pub use error::Error;
|
||||
pub use integer::Integer;
|
||||
pub use stream::XmlWriteOptions;
|
||||
pub use uid::Uid;
|
||||
pub use value::Value;
|
||||
|
||||
|
@ -111,7 +112,9 @@ pub use self::{de::Deserializer, ser::Serializer};
|
|||
#[cfg(feature = "serde")]
|
||||
pub use self::{
|
||||
de::{from_bytes, from_file, from_reader, from_reader_xml},
|
||||
ser::{to_file_binary, to_file_xml, to_writer_binary, to_writer_xml},
|
||||
ser::{
|
||||
to_file_binary, to_file_xml, to_writer_binary, to_writer_xml, to_writer_xml_with_options,
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(all(test, feature = "serde"))]
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
error::{self, Error, ErrorKind},
|
||||
stream::{self, Writer},
|
||||
uid::serde_impls::UID_NEWTYPE_STRUCT_NAME,
|
||||
Date, Integer, Uid,
|
||||
Date, Integer, Uid, XmlWriteOptions,
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -234,10 +234,8 @@ impl<'a, W: Writer> ser::Serializer for &'a mut Serializer<W> {
|
|||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<(), Error> {
|
||||
self.write_start_dictionary(Some(1))?;
|
||||
self.write_string(variant)?;
|
||||
self.serialize_unit()?;
|
||||
self.write_end_collection()
|
||||
// `plist` since v1.1 serialises unit enum variants as plain strings.
|
||||
self.write_string(variant)
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized + ser::Serialize>(
|
||||
|
@ -791,7 +789,16 @@ pub fn to_writer_binary<W: Write, T: ser::Serialize>(writer: W, value: &T) -> Re
|
|||
|
||||
/// Serializes the given data structure to a byte stream as an XML encoded plist.
|
||||
pub fn to_writer_xml<W: Write, T: ser::Serialize>(writer: W, value: &T) -> Result<(), Error> {
|
||||
let writer = stream::XmlWriter::new(writer);
|
||||
to_writer_xml_with_options(writer, value, &XmlWriteOptions::default())
|
||||
}
|
||||
|
||||
/// Serializes to a byte stream as an XML encoded plist, using custom [`XmlWriteOptions`].
|
||||
pub fn to_writer_xml_with_options<W: Write, T: ser::Serialize>(
|
||||
writer: W,
|
||||
value: &T,
|
||||
options: &XmlWriteOptions,
|
||||
) -> Result<(), Error> {
|
||||
let writer = stream::XmlWriter::new_with_options(writer, options);
|
||||
let mut ser = Serializer::new(writer);
|
||||
value.serialize(&mut ser)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
use serde::{de::DeserializeOwned, ser::Serialize};
|
||||
use serde::{
|
||||
de::{Deserialize, DeserializeOwned},
|
||||
ser::Serialize,
|
||||
};
|
||||
use std::{collections::BTreeMap, fmt::Debug};
|
||||
|
||||
use crate::{
|
||||
stream::{private::Sealed, Event, Writer},
|
||||
stream::{private::Sealed, Event, OwnedEvent, Writer},
|
||||
Date, Deserializer, Error, Integer, Serializer, Uid,
|
||||
};
|
||||
|
||||
struct VecWriter {
|
||||
events: Vec<Event>,
|
||||
events: Vec<OwnedEvent>,
|
||||
}
|
||||
|
||||
impl VecWriter {
|
||||
|
@ -15,7 +18,7 @@ impl VecWriter {
|
|||
VecWriter { events: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> Vec<Event> {
|
||||
pub fn into_inner(self) -> Vec<OwnedEvent> {
|
||||
self.events
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +45,7 @@ impl Writer for VecWriter {
|
|||
}
|
||||
|
||||
fn write_data(&mut self, value: &[u8]) -> Result<(), Error> {
|
||||
self.events.push(Event::Data(value.to_owned()));
|
||||
self.events.push(Event::Data(value.to_owned().into()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -62,7 +65,7 @@ impl Writer for VecWriter {
|
|||
}
|
||||
|
||||
fn write_string(&mut self, value: &str) -> Result<(), Error> {
|
||||
self.events.push(Event::String(value.to_owned()));
|
||||
self.events.push(Event::String(value.to_owned().into()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -78,7 +81,7 @@ fn new_serializer() -> Serializer<VecWriter> {
|
|||
Serializer::new(VecWriter::new())
|
||||
}
|
||||
|
||||
fn new_deserializer(events: Vec<Event>) -> Deserializer<Vec<Result<Event, Error>>> {
|
||||
fn new_deserializer(events: Vec<OwnedEvent>) -> Deserializer<Vec<Result<OwnedEvent, Error>>> {
|
||||
let result_events = events.into_iter().map(Ok).collect();
|
||||
Deserializer::new(result_events)
|
||||
}
|
||||
|
@ -133,12 +136,7 @@ struct DogInner {
|
|||
fn cow() {
|
||||
let cow = Animal::Cow;
|
||||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Cow".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::EndCollection,
|
||||
];
|
||||
let comparison = &[Event::String("Cow".into())];
|
||||
|
||||
assert_roundtrip(cow, Some(comparison));
|
||||
}
|
||||
|
@ -156,21 +154,21 @@ fn dog() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Dog".to_owned()),
|
||||
Event::String("Dog".into()),
|
||||
Event::StartDictionary(None),
|
||||
Event::String("inner".to_owned()),
|
||||
Event::String("inner".into()),
|
||||
Event::StartArray(Some(1)),
|
||||
Event::StartDictionary(None),
|
||||
Event::String("a".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("b".to_owned()),
|
||||
Event::String("a".into()),
|
||||
Event::String("".into()),
|
||||
Event::String("b".into()),
|
||||
Event::Integer(12.into()),
|
||||
Event::String("c".to_owned()),
|
||||
Event::String("c".into()),
|
||||
Event::StartArray(Some(2)),
|
||||
Event::String("a".to_owned()),
|
||||
Event::String("b".to_owned()),
|
||||
Event::String("a".into()),
|
||||
Event::String("b".into()),
|
||||
Event::EndCollection,
|
||||
Event::String("d".to_owned()),
|
||||
Event::String("d".into()),
|
||||
Event::Uid(Uid::new(42)),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
|
@ -190,14 +188,14 @@ fn frog() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Frog".to_owned()),
|
||||
Event::String("Frog".into()),
|
||||
Event::StartArray(Some(2)),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Ok".to_owned()),
|
||||
Event::String("hello".to_owned()),
|
||||
Event::String("Ok".into()),
|
||||
Event::String("hello".into()),
|
||||
Event::EndCollection,
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::StartArray(Some(5)),
|
||||
Event::Real(1.0),
|
||||
Event::Real(2.0),
|
||||
|
@ -223,13 +221,13 @@ fn cat_with_firmware() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Cat".to_owned()),
|
||||
Event::String("Cat".into()),
|
||||
Event::StartDictionary(None),
|
||||
Event::String("age".to_owned()),
|
||||
Event::String("age".into()),
|
||||
Event::Integer(12.into()),
|
||||
Event::String("name".to_owned()),
|
||||
Event::String("Paws".to_owned()),
|
||||
Event::String("firmware".to_owned()),
|
||||
Event::String("name".into()),
|
||||
Event::String("Paws".into()),
|
||||
Event::String("firmware".into()),
|
||||
Event::StartArray(Some(9)),
|
||||
Event::Integer(0.into()),
|
||||
Event::Integer(1.into()),
|
||||
|
@ -258,12 +256,12 @@ fn cat_without_firmware() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Cat".to_owned()),
|
||||
Event::String("Cat".into()),
|
||||
Event::StartDictionary(None),
|
||||
Event::String("age".to_owned()),
|
||||
Event::String("age".into()),
|
||||
Event::Integer(Integer::from(-12)),
|
||||
Event::String("name".to_owned()),
|
||||
Event::String("Paws".to_owned()),
|
||||
Event::String("name".into()),
|
||||
Event::String("Paws".into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
];
|
||||
|
@ -315,18 +313,18 @@ fn type_with_options() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(None),
|
||||
Event::String("a".to_owned()),
|
||||
Event::String("hello".to_owned()),
|
||||
Event::String("b".to_owned()),
|
||||
Event::String("a".into()),
|
||||
Event::String("hello".into()),
|
||||
Event::String("b".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("None".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("None".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
Event::String("c".to_owned()),
|
||||
Event::String("c".into()),
|
||||
Event::StartDictionary(None),
|
||||
Event::String("b".to_owned()),
|
||||
Event::String("b".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::Integer(12.into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
|
@ -353,9 +351,9 @@ fn type_with_date() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(None),
|
||||
Event::String("a".to_owned()),
|
||||
Event::String("a".into()),
|
||||
Event::Integer(28.into()),
|
||||
Event::String("b".to_owned()),
|
||||
Event::String("b".into()),
|
||||
Event::Date(date),
|
||||
Event::EndCollection,
|
||||
];
|
||||
|
@ -387,7 +385,7 @@ fn option_some_some() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::Integer(12.into()),
|
||||
Event::EndCollection,
|
||||
];
|
||||
|
@ -401,8 +399,8 @@ fn option_some_none() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("None".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("None".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
];
|
||||
|
||||
|
@ -418,24 +416,24 @@ fn option_dictionary_values() {
|
|||
|
||||
let comparison = &[
|
||||
Event::StartDictionary(Some(3)),
|
||||
Event::String("a".to_owned()),
|
||||
Event::String("a".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("None".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("None".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
Event::String("b".to_owned()),
|
||||
Event::String("b".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("None".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("None".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
Event::String("c".to_owned()),
|
||||
Event::String("c".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::Integer(144.into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
|
@ -455,22 +453,22 @@ fn option_dictionary_keys() {
|
|||
let comparison = &[
|
||||
Event::StartDictionary(Some(3)),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("None".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("None".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
Event::Integer(1.into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("None".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("None".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
Event::Integer(2.into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::Integer(144.into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
|
@ -488,20 +486,20 @@ fn option_array() {
|
|||
let comparison = &[
|
||||
Event::StartArray(Some(3)),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("None".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("None".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("None".to_owned()),
|
||||
Event::String("".to_owned()),
|
||||
Event::String("None".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Some".to_owned()),
|
||||
Event::String("Some".into()),
|
||||
Event::Integer(144.into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
|
@ -510,3 +508,78 @@ fn option_array() {
|
|||
|
||||
assert_roundtrip(obj, Some(comparison));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_variant_types() {
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
enum Foo {
|
||||
Unit,
|
||||
Newtype(u32),
|
||||
Tuple(u32, String),
|
||||
Struct { v: u32, s: String },
|
||||
}
|
||||
|
||||
let expected = &[Event::String("Unit".into())];
|
||||
assert_roundtrip(Foo::Unit, Some(expected));
|
||||
|
||||
let expected = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Newtype".into()),
|
||||
Event::Integer(42.into()),
|
||||
Event::EndCollection,
|
||||
];
|
||||
assert_roundtrip(Foo::Newtype(42), Some(expected));
|
||||
|
||||
let expected = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Tuple".into()),
|
||||
Event::StartArray(Some(2)),
|
||||
Event::Integer(42.into()),
|
||||
Event::String("bar".into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
];
|
||||
assert_roundtrip(Foo::Tuple(42, "bar".into()), Some(expected));
|
||||
|
||||
let expected = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Struct".into()),
|
||||
Event::StartDictionary(None),
|
||||
Event::String("v".into()),
|
||||
Event::Integer(42.into()),
|
||||
Event::String("s".into()),
|
||||
Event::String("bar".into()),
|
||||
Event::EndCollection,
|
||||
Event::EndCollection,
|
||||
];
|
||||
assert_roundtrip(
|
||||
Foo::Struct {
|
||||
v: 42,
|
||||
s: "bar".into(),
|
||||
},
|
||||
Some(expected),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialise_old_enum_unit_variant_encoding() {
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
enum Foo {
|
||||
Bar,
|
||||
Baz,
|
||||
}
|
||||
|
||||
// `plist` before v1.1 serialised unit enum variants as if they were newtype variants
|
||||
// containing an empty string.
|
||||
let events = &[
|
||||
Event::StartDictionary(Some(1)),
|
||||
Event::String("Baz".into()),
|
||||
Event::String("".into()),
|
||||
Event::EndCollection,
|
||||
];
|
||||
|
||||
let mut de = new_deserializer(events.to_vec());
|
||||
let obj = Foo::deserialize(&mut de).unwrap();
|
||||
|
||||
assert_eq!(obj, Foo::Baz);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
use crate::{
|
||||
date::{Date, InfiniteOrNanDate},
|
||||
error::{Error, ErrorKind},
|
||||
stream::Event,
|
||||
stream::{Event, OwnedEvent},
|
||||
u64_to_usize, Uid,
|
||||
};
|
||||
|
||||
|
@ -208,7 +208,7 @@ impl<R: Read + Seek> BinaryReader<R> {
|
|||
item
|
||||
}
|
||||
|
||||
fn read_next(&mut self) -> Result<Option<Event>, Error> {
|
||||
fn read_next(&mut self) -> Result<Option<OwnedEvent>, Error> {
|
||||
let object_ref = if self.ref_size == 0 {
|
||||
// Initialise here rather than in new
|
||||
self.read_trailer()?;
|
||||
|
@ -268,7 +268,7 @@ impl<R: Read + Seek> BinaryReader<R> {
|
|||
(0x4, n) => {
|
||||
// Data
|
||||
let len = self.read_object_len(n)?;
|
||||
Some(Event::Data(self.read_data(len)?))
|
||||
Some(Event::Data(self.read_data(len)?.into()))
|
||||
}
|
||||
(0x5, n) => {
|
||||
// ASCII string
|
||||
|
@ -276,7 +276,7 @@ impl<R: Read + Seek> BinaryReader<R> {
|
|||
let raw = self.read_data(len)?;
|
||||
let string = String::from_utf8(raw)
|
||||
.map_err(|_| self.with_pos(ErrorKind::InvalidUtf8String))?;
|
||||
Some(Event::String(string))
|
||||
Some(Event::String(string.into()))
|
||||
}
|
||||
(0x6, n) => {
|
||||
// UTF-16 string
|
||||
|
@ -289,7 +289,7 @@ impl<R: Read + Seek> BinaryReader<R> {
|
|||
|
||||
let string = String::from_utf16(&raw_utf16)
|
||||
.map_err(|_| self.with_pos(ErrorKind::InvalidUtf16String))?;
|
||||
Some(Event::String(string))
|
||||
Some(Event::String(string.into()))
|
||||
}
|
||||
(0x8, n) if n < 8 => {
|
||||
// Uid
|
||||
|
@ -392,9 +392,9 @@ impl<R: Read + Seek> BinaryReader<R> {
|
|||
}
|
||||
|
||||
impl<R: Read + Seek> Iterator for BinaryReader<R> {
|
||||
type Item = Result<Event, Error>;
|
||||
type Item = Result<OwnedEvent, Error>;
|
||||
|
||||
fn next(&mut self) -> Option<Result<Event, Error>> {
|
||||
fn next(&mut self) -> Option<Result<OwnedEvent, Error>> {
|
||||
match self.read_next() {
|
||||
Ok(Some(event)) => Some(Ok(event)),
|
||||
Err(err) => {
|
||||
|
@ -454,7 +454,7 @@ mod tests {
|
|||
String("IsTrue".into()),
|
||||
Boolean(true),
|
||||
String("Data".into()),
|
||||
Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
|
||||
Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0].into()),
|
||||
EndCollection,
|
||||
];
|
||||
|
||||
|
@ -467,7 +467,7 @@ mod tests {
|
|||
let streaming_parser = BinaryReader::new(reader);
|
||||
let mut events: Vec<Event> = streaming_parser.map(|e| e.unwrap()).collect();
|
||||
|
||||
assert_eq!(events[2], Event::String("\u{2605} or better".to_owned()));
|
||||
assert_eq!(events[2], Event::String("\u{2605} or better".into()));
|
||||
|
||||
let poem = if let Event::String(ref mut poem) = events[4] {
|
||||
poem
|
||||
|
@ -475,7 +475,7 @@ mod tests {
|
|||
panic!("not a string")
|
||||
};
|
||||
assert_eq!(poem.len(), 643);
|
||||
assert_eq!(poem.pop().unwrap(), '\u{2605}');
|
||||
assert_eq!(poem.to_mut().pop().unwrap(), '\u{2605}');
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -13,6 +13,7 @@ mod xml_writer;
|
|||
pub use self::xml_writer::XmlWriter;
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
io::{self, Read, Seek, SeekFrom},
|
||||
vec,
|
||||
};
|
||||
|
@ -37,8 +38,17 @@ use crate::{
|
|||
/// Integer(28) // Value
|
||||
/// EndDictionary
|
||||
/// ```
|
||||
///
|
||||
/// ## Lifetimes
|
||||
///
|
||||
/// This type has a lifetime parameter; during serialization, data is borrowed
|
||||
/// from a [`Value`], and the lifetime of the event is the lifetime of the
|
||||
/// [`Value`] being serialized.
|
||||
///
|
||||
/// During deserialization, data is always copied anyway, and this lifetime
|
||||
/// is always `'static`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Event {
|
||||
pub enum Event<'a> {
|
||||
// While the length of an array or dict cannot be feasably greater than max(usize) this better
|
||||
// conveys the concept of an effectively unbounded event stream.
|
||||
StartArray(Option<u64>),
|
||||
|
@ -46,46 +56,81 @@ pub enum Event {
|
|||
EndCollection,
|
||||
|
||||
Boolean(bool),
|
||||
Data(Vec<u8>),
|
||||
Data(Cow<'a, [u8]>),
|
||||
Date(Date),
|
||||
Integer(Integer),
|
||||
Real(f64),
|
||||
String(String),
|
||||
String(Cow<'a, str>),
|
||||
Uid(Uid),
|
||||
|
||||
#[doc(hidden)]
|
||||
__Nonexhaustive,
|
||||
}
|
||||
|
||||
/// An owned [`Event`].
|
||||
///
|
||||
/// During deserialization, events are always owned; this type alias helps
|
||||
/// keep that code a bit clearer.
|
||||
pub type OwnedEvent = Event<'static>;
|
||||
|
||||
/// An `Event` stream returned by `Value::into_events`.
|
||||
pub struct IntoEvents {
|
||||
stack: Vec<StackItem>,
|
||||
pub struct Events<'a> {
|
||||
stack: Vec<StackItem<'a>>,
|
||||
}
|
||||
|
||||
enum StackItem {
|
||||
Root(Value),
|
||||
Array(vec::IntoIter<Value>),
|
||||
Dict(dictionary::IntoIter),
|
||||
DictValue(Value),
|
||||
enum StackItem<'a> {
|
||||
Root(&'a Value),
|
||||
Array(std::slice::Iter<'a, Value>),
|
||||
Dict(dictionary::Iter<'a>),
|
||||
DictValue(&'a Value),
|
||||
}
|
||||
|
||||
impl IntoEvents {
|
||||
pub(crate) fn new(value: Value) -> IntoEvents {
|
||||
IntoEvents {
|
||||
/// Options for customizing serialization of XML plists.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct XmlWriteOptions {
|
||||
indent_str: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl XmlWriteOptions {
|
||||
/// Specify the sequence of characters used for indentation.
|
||||
///
|
||||
/// This may be either an `&'static str` or an owned `String`.
|
||||
///
|
||||
/// The default is `\t`.
|
||||
pub fn indent_string(mut self, indent_str: impl Into<Cow<'static, str>>) -> Self {
|
||||
self.indent_str = indent_str.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for XmlWriteOptions {
|
||||
fn default() -> Self {
|
||||
XmlWriteOptions {
|
||||
indent_str: Cow::Borrowed("\t"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Events<'a> {
|
||||
pub(crate) fn new(value: &'a Value) -> Events<'a> {
|
||||
Events {
|
||||
stack: vec![StackItem::Root(value)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for IntoEvents {
|
||||
type Item = Event;
|
||||
impl<'a> Iterator for Events<'a> {
|
||||
type Item = Event<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Event> {
|
||||
fn handle_value(value: Value, stack: &mut Vec<StackItem>) -> Event {
|
||||
fn next(&mut self) -> Option<Event<'a>> {
|
||||
fn handle_value<'c, 'b: 'c>(
|
||||
value: &'b Value,
|
||||
stack: &'c mut Vec<StackItem<'b>>,
|
||||
) -> Event<'b> {
|
||||
match value {
|
||||
Value::Array(array) => {
|
||||
let len = array.len();
|
||||
let iter = array.into_iter();
|
||||
let iter = array.iter();
|
||||
stack.push(StackItem::Array(iter));
|
||||
Event::StartArray(Some(len as u64))
|
||||
}
|
||||
|
@ -95,13 +140,13 @@ impl Iterator for IntoEvents {
|
|||
stack.push(StackItem::Dict(iter));
|
||||
Event::StartDictionary(Some(len as u64))
|
||||
}
|
||||
Value::Boolean(value) => Event::Boolean(value),
|
||||
Value::Data(value) => Event::Data(value),
|
||||
Value::Date(value) => Event::Date(value),
|
||||
Value::Real(value) => Event::Real(value),
|
||||
Value::Integer(value) => Event::Integer(value),
|
||||
Value::String(value) => Event::String(value),
|
||||
Value::Uid(value) => Event::Uid(value),
|
||||
Value::Boolean(value) => Event::Boolean(*value),
|
||||
Value::Data(value) => Event::Data(Cow::Borrowed(&value)),
|
||||
Value::Date(value) => Event::Date(*value),
|
||||
Value::Real(value) => Event::Real(*value),
|
||||
Value::Integer(value) => Event::Integer(*value),
|
||||
Value::String(value) => Event::String(Cow::Borrowed(value.as_str())),
|
||||
Value::Uid(value) => Event::Uid(*value),
|
||||
Value::__Nonexhaustive => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +169,7 @@ impl Iterator for IntoEvents {
|
|||
// The next event to be returned must be the dictionary value.
|
||||
self.stack.push(StackItem::DictValue(value));
|
||||
// Return the key event now.
|
||||
Event::String(key)
|
||||
Event::String(Cow::Borrowed(key))
|
||||
} else {
|
||||
Event::EndCollection
|
||||
}
|
||||
|
@ -162,25 +207,23 @@ impl<R: Read + Seek> Reader<R> {
|
|||
}
|
||||
|
||||
impl<R: Read + Seek> Iterator for Reader<R> {
|
||||
type Item = Result<Event, Error>;
|
||||
type Item = Result<OwnedEvent, Error>;
|
||||
|
||||
fn next(&mut self) -> Option<Result<Event, Error>> {
|
||||
fn next(&mut self) -> Option<Result<OwnedEvent, Error>> {
|
||||
let mut reader = match self.0 {
|
||||
ReaderInner::Xml(ref mut parser) => return parser.next(),
|
||||
ReaderInner::Binary(ref mut parser) => return parser.next(),
|
||||
ReaderInner::Uninitialized(ref mut reader) => reader.take().unwrap(),
|
||||
};
|
||||
|
||||
let event_reader = match Reader::is_binary(&mut reader) {
|
||||
Ok(true) => ReaderInner::Binary(BinaryReader::new(reader)),
|
||||
Ok(false) => ReaderInner::Xml(XmlReader::new(reader)),
|
||||
match Reader::is_binary(&mut reader) {
|
||||
Ok(true) => self.0 = ReaderInner::Binary(BinaryReader::new(reader)),
|
||||
Ok(false) => self.0 = ReaderInner::Xml(XmlReader::new(reader)),
|
||||
Err(err) => {
|
||||
::std::mem::replace(&mut self.0, ReaderInner::Uninitialized(Some(reader)));
|
||||
self.0 = ReaderInner::Uninitialized(Some(reader));
|
||||
return Some(Err(err));
|
||||
}
|
||||
};
|
||||
|
||||
::std::mem::replace(&mut self.0, event_reader);
|
||||
}
|
||||
|
||||
self.next()
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use xml_rs::{
|
|||
|
||||
use crate::{
|
||||
error::{Error, ErrorKind, FilePosition},
|
||||
stream::Event,
|
||||
stream::{Event, OwnedEvent},
|
||||
Date, Integer,
|
||||
};
|
||||
|
||||
|
@ -75,7 +75,7 @@ impl<R: Read> XmlReader<R> {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_next(&mut self) -> Result<Option<Event>, Error> {
|
||||
fn read_next(&mut self) -> Result<Option<OwnedEvent>, Error> {
|
||||
loop {
|
||||
match self.next_event() {
|
||||
Ok(XmlEvent::StartDocument { .. }) => {}
|
||||
|
@ -87,7 +87,7 @@ impl<R: Read> XmlReader<R> {
|
|||
"plist" => (),
|
||||
"array" => return Ok(Some(Event::StartArray(None))),
|
||||
"dict" => return Ok(Some(Event::StartDictionary(None))),
|
||||
"key" => return Ok(Some(Event::String(self.read_content()?))),
|
||||
"key" => return Ok(Some(Event::String(self.read_content()?.into()))),
|
||||
"true" => return Ok(Some(Event::Boolean(true))),
|
||||
"false" => return Ok(Some(Event::Boolean(false))),
|
||||
"data" => {
|
||||
|
@ -96,7 +96,7 @@ impl<R: Read> XmlReader<R> {
|
|||
s.retain(|c| !c.is_ascii_whitespace());
|
||||
let data = base64::decode(&s)
|
||||
.map_err(|_| self.with_pos(ErrorKind::InvalidDataString))?;
|
||||
return Ok(Some(Event::Data(data)));
|
||||
return Ok(Some(Event::Data(data.into())));
|
||||
}
|
||||
"date" => {
|
||||
let s = self.read_content()?;
|
||||
|
@ -120,7 +120,7 @@ impl<R: Read> XmlReader<R> {
|
|||
Err(_) => return Err(self.with_pos(ErrorKind::InvalidRealString)),
|
||||
}
|
||||
}
|
||||
"string" => return Ok(Some(Event::String(self.read_content()?))),
|
||||
"string" => return Ok(Some(Event::String(self.read_content()?.into()))),
|
||||
_ => return Err(self.with_pos(ErrorKind::UnknownXmlElement)),
|
||||
}
|
||||
}
|
||||
|
@ -169,9 +169,9 @@ impl<R: Read> XmlReader<R> {
|
|||
}
|
||||
|
||||
impl<R: Read> Iterator for XmlReader<R> {
|
||||
type Item = Result<Event, Error>;
|
||||
type Item = Result<OwnedEvent, Error>;
|
||||
|
||||
fn next(&mut self) -> Option<Result<Event, Error>> {
|
||||
fn next(&mut self) -> Option<Result<OwnedEvent, Error>> {
|
||||
if self.finished {
|
||||
None
|
||||
} else {
|
||||
|
@ -231,28 +231,28 @@ mod tests {
|
|||
|
||||
let comparison = &[
|
||||
StartDictionary(None),
|
||||
String("Author".to_owned()),
|
||||
String("William Shakespeare".to_owned()),
|
||||
String("Lines".to_owned()),
|
||||
String("Author".into()),
|
||||
String("William Shakespeare".into()),
|
||||
String("Lines".into()),
|
||||
StartArray(None),
|
||||
String("It is a tale told by an idiot,".to_owned()),
|
||||
String("Full of sound and fury, signifying nothing.".to_owned()),
|
||||
String("It is a tale told by an idiot,".into()),
|
||||
String("Full of sound and fury, signifying nothing.".into()),
|
||||
EndCollection,
|
||||
String("Death".to_owned()),
|
||||
String("Death".into()),
|
||||
Integer(1564.into()),
|
||||
String("Height".to_owned()),
|
||||
String("Height".into()),
|
||||
Real(1.60),
|
||||
String("Data".to_owned()),
|
||||
Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
|
||||
String("Birthdate".to_owned()),
|
||||
String("Data".into()),
|
||||
Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0].into()),
|
||||
String("Birthdate".into()),
|
||||
Date(super::Date::from_rfc3339("1981-05-16T11:32:06Z").unwrap()),
|
||||
String("Blank".to_owned()),
|
||||
String("".to_owned()),
|
||||
String("BiggestNumber".to_owned()),
|
||||
String("Blank".into()),
|
||||
String("".into()),
|
||||
String("BiggestNumber".into()),
|
||||
Integer(18446744073709551615u64.into()),
|
||||
String("SmallestNumber".to_owned()),
|
||||
String("SmallestNumber".into()),
|
||||
Integer((-9223372036854775808i64).into()),
|
||||
String("HexademicalNumber".to_owned()),
|
||||
String("HexademicalNumber".into()),
|
||||
Integer(0xdead_beef_u64.into()),
|
||||
String("IsTrue".into()),
|
||||
Boolean(true),
|
||||
|
|
|
@ -9,7 +9,7 @@ use xml_rs::{
|
|||
|
||||
use crate::{
|
||||
error::{self, Error, ErrorKind, EventKind},
|
||||
stream::Writer,
|
||||
stream::{Writer, XmlWriteOptions},
|
||||
Date, Integer, Uid,
|
||||
};
|
||||
|
||||
|
@ -35,15 +35,21 @@ pub struct XmlWriter<W: Write> {
|
|||
|
||||
impl<W: Write> XmlWriter<W> {
|
||||
pub fn new(writer: W) -> XmlWriter<W> {
|
||||
let opts = XmlWriteOptions::default();
|
||||
XmlWriter::new_with_options(writer, &opts)
|
||||
}
|
||||
|
||||
pub fn new_with_options(writer: W, opts: &XmlWriteOptions) -> XmlWriter<W> {
|
||||
let config = EmitterConfig::new()
|
||||
.line_separator("\n")
|
||||
.indent_string("\t")
|
||||
.indent_string(opts.indent_str.clone())
|
||||
.perform_indent(true)
|
||||
.write_document_declaration(false)
|
||||
.normalize_empty_elements(true)
|
||||
.cdata_to_characters(true)
|
||||
.keep_element_names_stack(false)
|
||||
.autopad_comments(true);
|
||||
.autopad_comments(true)
|
||||
.pad_self_closing(false);
|
||||
|
||||
XmlWriter {
|
||||
xml_writer: EventWriter::new_with_config(writer, config),
|
||||
|
@ -300,27 +306,27 @@ mod tests {
|
|||
fn streaming_parser() {
|
||||
let plist = &[
|
||||
Event::StartDictionary(None),
|
||||
Event::String("Author".to_owned()),
|
||||
Event::String("William Shakespeare".to_owned()),
|
||||
Event::String("Lines".to_owned()),
|
||||
Event::String("Author".into()),
|
||||
Event::String("William Shakespeare".into()),
|
||||
Event::String("Lines".into()),
|
||||
Event::StartArray(None),
|
||||
Event::String("It is a tale told by an idiot,".to_owned()),
|
||||
Event::String("Full of sound and fury, signifying nothing.".to_owned()),
|
||||
Event::Data((0..128).collect::<Vec<_>>()),
|
||||
Event::String("It is a tale told by an idiot,".into()),
|
||||
Event::String("Full of sound and fury, signifying nothing.".into()),
|
||||
Event::Data((0..128).collect::<Vec<_>>().into()),
|
||||
Event::EndCollection,
|
||||
Event::String("Death".to_owned()),
|
||||
Event::String("Death".into()),
|
||||
Event::Integer(1564.into()),
|
||||
Event::String("Height".to_owned()),
|
||||
Event::String("Height".into()),
|
||||
Event::Real(1.60),
|
||||
Event::String("Data".to_owned()),
|
||||
Event::Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
|
||||
Event::String("Birthdate".to_owned()),
|
||||
Event::String("Data".into()),
|
||||
Event::Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0].into()),
|
||||
Event::String("Birthdate".into()),
|
||||
Event::Date(super::Date::from_rfc3339("1981-05-16T11:32:06Z").unwrap()),
|
||||
Event::String("Comment".to_owned()),
|
||||
Event::String("2 < 3".to_owned()), // make sure characters are escaped
|
||||
Event::String("BiggestNumber".to_owned()),
|
||||
Event::String("Comment".into()),
|
||||
Event::String("2 < 3".into()), // make sure characters are escaped
|
||||
Event::String("BiggestNumber".into()),
|
||||
Event::Integer(18446744073709551615u64.into()),
|
||||
Event::String("SmallestNumber".to_owned()),
|
||||
Event::String("SmallestNumber".into()),
|
||||
Event::Integer((-9223372036854775808i64).into()),
|
||||
Event::String("IsTrue".into()),
|
||||
Event::Boolean(true),
|
||||
|
@ -372,9 +378,9 @@ mod tests {
|
|||
\t<key>SmallestNumber</key>
|
||||
\t<integer>-9223372036854775808</integer>
|
||||
\t<key>IsTrue</key>
|
||||
\t<true />
|
||||
\t<true/>
|
||||
\t<key>IsNotFalse</key>
|
||||
\t<false />
|
||||
\t<false/>
|
||||
</dict>
|
||||
</plist>";
|
||||
|
||||
|
|
|
@ -6,7 +6,10 @@ use std::{
|
|||
|
||||
use crate::{
|
||||
error::{self, Error, ErrorKind, EventKind},
|
||||
stream::{BinaryWriter, Event, IntoEvents, Reader, Writer, XmlReader, XmlWriter},
|
||||
stream::{
|
||||
BinaryWriter, Event, Events, OwnedEvent, Reader, Writer, XmlReader, XmlWriteOptions,
|
||||
XmlWriter,
|
||||
},
|
||||
u64_to_usize, Date, Dictionary, Integer, Uid,
|
||||
};
|
||||
|
||||
|
@ -69,12 +72,39 @@ impl Value {
|
|||
|
||||
/// Serializes a `Value` to a byte stream as an XML encoded plist.
|
||||
pub fn to_writer_xml<W: Write>(&self, writer: W) -> Result<(), Error> {
|
||||
let mut writer = XmlWriter::new(writer);
|
||||
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.clone().into_events();
|
||||
let events = self.events();
|
||||
for event in events {
|
||||
writer.write(&event)?;
|
||||
}
|
||||
|
@ -86,7 +116,7 @@ impl Value {
|
|||
#[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<Event, Error>>,
|
||||
T: IntoIterator<Item = Result<OwnedEvent, Error>>,
|
||||
{
|
||||
Builder::new(events.into_iter()).build()
|
||||
}
|
||||
|
@ -96,21 +126,29 @@ impl Value {
|
|||
#[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<Event, Error>>,
|
||||
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")]
|
||||
pub fn into_events(self) -> IntoEvents {
|
||||
IntoEvents::new(self)
|
||||
#[doc(hidden)]
|
||||
#[deprecated(since = "1.2.0", note = "use Value::events instead")]
|
||||
pub fn into_events(&self) -> Events {
|
||||
self.events()
|
||||
}
|
||||
|
||||
/// Converts a `Value` into an `Event` iterator.
|
||||
/// Creates an `Event` iterator for this `Value`.
|
||||
#[cfg(not(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"))]
|
||||
pub(crate) fn into_events(self) -> IntoEvents {
|
||||
IntoEvents::new(self)
|
||||
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`.
|
||||
|
@ -446,10 +484,10 @@ impl<'a> From<&'a str> for Value {
|
|||
|
||||
struct Builder<T> {
|
||||
stream: T,
|
||||
token: Option<Event>,
|
||||
token: Option<OwnedEvent>,
|
||||
}
|
||||
|
||||
impl<T: Iterator<Item = Result<Event, Error>>> Builder<T> {
|
||||
impl<T: Iterator<Item = Result<OwnedEvent, Error>>> Builder<T> {
|
||||
fn new(stream: T) -> Builder<T> {
|
||||
Builder {
|
||||
stream,
|
||||
|
@ -477,11 +515,11 @@ impl<T: Iterator<Item = Result<Event, Error>>> Builder<T> {
|
|||
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)),
|
||||
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)),
|
||||
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(
|
||||
|
@ -520,7 +558,7 @@ impl<T: Iterator<Item = Result<Event, Error>>> Builder<T> {
|
|||
Some(Event::EndCollection) => return Ok(dict),
|
||||
Some(Event::String(s)) => {
|
||||
self.bump()?;
|
||||
dict.insert(s, self.build_value()?);
|
||||
dict.insert(s.into_owned(), self.build_value()?);
|
||||
}
|
||||
Some(event) => {
|
||||
return Err(error::unexpected_event_type(
|
||||
|
@ -586,16 +624,16 @@ mod tests {
|
|||
// Input
|
||||
let events = vec![
|
||||
StartDictionary(None),
|
||||
String("Author".to_owned()),
|
||||
String("William Shakespeare".to_owned()),
|
||||
String("Lines".to_owned()),
|
||||
String("Author".into()),
|
||||
String("William Shakespeare".into()),
|
||||
String("Lines".into()),
|
||||
StartArray(None),
|
||||
String("It is a tale told by an idiot,".to_owned()),
|
||||
String("Full of sound and fury, signifying nothing.".to_owned()),
|
||||
String("It is a tale told by an idiot,".into()),
|
||||
String("Full of sound and fury, signifying nothing.".into()),
|
||||
EndCollection,
|
||||
String("Birthdate".to_owned()),
|
||||
String("Birthdate".into()),
|
||||
Integer(1564.into()),
|
||||
String("Height".to_owned()),
|
||||
String("Height".into()),
|
||||
Real(1.60),
|
||||
EndCollection,
|
||||
];
|
||||
|
|
Загрузка…
Ссылка в новой задаче