blob: 27df83304ce87fbe316b50fa506f298844d97115 [file] [log] [blame]
use std::collections::BTreeMap;
use std::io::{Read, Seek};
use {builder, Date, EventReader, PlistEvent, Result};
#[derive(Clone, Debug, PartialEq)]
pub enum Plist {
Array(Vec<Plist>),
Dictionary(BTreeMap<String, Plist>),
Boolean(bool),
Data(Vec<u8>),
Date(Date),
Real(f64),
Integer(i64),
String(String),
}
impl Plist {
pub fn read<R: Read + Seek>(reader: R) -> Result<Plist> {
let reader = EventReader::new(reader);
Plist::from_events(reader)
}
pub fn from_events<T>(events: T) -> Result<Plist>
where T: IntoIterator<Item = Result<PlistEvent>>
{
let iter = events.into_iter();
let builder = builder::Builder::new(iter);
builder.build()
}
pub fn into_events(self) -> Vec<PlistEvent> {
let mut events = Vec::new();
self.into_events_inner(&mut events);
events
}
fn into_events_inner(self, events: &mut Vec<PlistEvent>) {
match self {
Plist::Array(array) => {
events.push(PlistEvent::StartArray(Some(array.len() as u64)));
for value in array {
value.into_events_inner(events);
}
events.push(PlistEvent::EndArray);
}
Plist::Dictionary(dict) => {
events.push(PlistEvent::StartDictionary(Some(dict.len() as u64)));
for (key, value) in dict {
events.push(PlistEvent::StringValue(key));
value.into_events_inner(events);
}
events.push(PlistEvent::EndDictionary);
}
Plist::Boolean(value) => events.push(PlistEvent::BooleanValue(value)),
Plist::Data(value) => events.push(PlistEvent::DataValue(value)),
Plist::Date(value) => events.push(PlistEvent::DateValue(value)),
Plist::Real(value) => events.push(PlistEvent::RealValue(value)),
Plist::Integer(value) => events.push(PlistEvent::IntegerValue(value)),
Plist::String(value) => events.push(PlistEvent::StringValue(value)),
}
}
/// If the `Plist` is an Array, returns the associated Vec.
/// Returns None otherwise.
pub fn as_array(&self) -> Option<&Vec<Plist>> {
match *self {
Plist::Array(ref array) => Some(array),
_ => None,
}
}
/// If the `Plist` is an Array, returns the associated mutable Vec.
/// Returns None otherwise.
pub fn as_array_mut(&mut self) -> Option<&mut Vec<Plist>> {
match *self {
Plist::Array(ref mut array) => Some(array),
_ => None,
}
}
/// If the `Plist` is a Dictionary, returns the associated BTreeMap.
/// Returns None otherwise.
pub fn as_dictionary(&self) -> Option<&BTreeMap<String, Plist>> {
match *self {
Plist::Dictionary(ref map) => Some(map),
_ => None,
}
}
/// If the `Plist` is a Dictionary, returns the associated mutable BTreeMap.
/// Returns None otherwise.
pub fn as_dictionary_mut(&mut self) -> Option<&mut BTreeMap<String, Plist>> {
match *self {
Plist::Dictionary(ref mut map) => Some(map),
_ => None,
}
}
/// If the `Plist` is a Boolean, returns the associated bool.
/// Returns None otherwise.
pub fn as_boolean(&self) -> Option<bool> {
match *self {
Plist::Boolean(v) => Some(v),
_ => None,
}
}
/// If the `Plist` is a Data, returns the underlying Vec.
/// Returns None otherwise.
///
/// This method consumes the `Plist`. If this is not desired, please use
/// `as_data` method.
pub fn into_data(self) -> Option<Vec<u8>> {
match self {
Plist::Data(data) => Some(data),
_ => None,
}
}
/// If the `Plist` is a Data, returns the associated Vec.
/// Returns None otherwise.
pub fn as_data(&self) -> Option<&[u8]> {
match *self {
Plist::Data(ref data) => Some(data),
_ => None,
}
}
/// If the `Plist` is a Date, returns the associated DateTime.
/// Returns None otherwise.
pub fn as_date(&self) -> Option<&Date> {
match *self {
Plist::Date(ref date) => Some(date),
_ => None,
}
}
/// If the `Plist` is a Real, returns the associated f64.
/// Returns None otherwise.
pub fn as_real(&self) -> Option<f64> {
match *self {
Plist::Real(v) => Some(v),
_ => None,
}
}
/// If the `Plist` is an Integer, returns the associated i64.
/// Returns None otherwise.
pub fn as_integer(&self) -> Option<i64> {
match *self {
Plist::Integer(v) => Some(v),
_ => None,
}
}
/// If the `Plist` is a String, returns the underlying String.
/// Returns None otherwise.
///
/// This method consumes the `Plist`. If this is not desired, please use
/// `as_string` method.
pub fn into_string(self) -> Option<String> {
match self {
Plist::String(v) => Some(v),
_ => None,
}
}
/// If the `Plist` is a String, returns the associated str.
/// Returns None otherwise.
pub fn as_string(&self) -> Option<&str> {
match *self {
Plist::String(ref v) => Some(v),
_ => None,
}
}
}
impl From<Vec<Plist>> for Plist {
fn from(from: Vec<Plist>) -> Plist {
Plist::Array(from)
}
}
impl From<BTreeMap<String, Plist>> for Plist {
fn from(from: BTreeMap<String, Plist>) -> Plist {
Plist::Dictionary(from)
}
}
impl From<bool> for Plist {
fn from(from: bool) -> Plist {
Plist::Boolean(from)
}
}
impl<'a> From<&'a bool> for Plist {
fn from(from: &'a bool) -> Plist {
Plist::Boolean(*from)
}
}
impl From<Date> for Plist {
fn from(from: Date) -> Plist {
Plist::Date(from)
}
}
impl<'a> From<&'a Date> for Plist {
fn from(from: &'a Date) -> Plist {
Plist::Date(from.clone())
}
}
impl From<f64> for Plist {
fn from(from: f64) -> Plist {
Plist::Real(from)
}
}
impl From<f32> for Plist {
fn from(from: f32) -> Plist {
Plist::Real(from as f64)
}
}
impl From<i64> for Plist {
fn from(from: i64) -> Plist {
Plist::Integer(from)
}
}
impl From<i32> for Plist {
fn from(from: i32) -> Plist {
Plist::Integer(from as i64)
}
}
impl From<i16> for Plist {
fn from(from: i16) -> Plist {
Plist::Integer(from as i64)
}
}
impl From<i8> for Plist {
fn from(from: i8) -> Plist {
Plist::Integer(from as i64)
}
}
impl From<u32> for Plist {
fn from(from: u32) -> Plist {
Plist::Integer(from as i64)
}
}
impl From<u16> for Plist {
fn from(from: u16) -> Plist {
Plist::Integer(from as i64)
}
}
impl From<u8> for Plist {
fn from(from: u8) -> Plist {
Plist::Integer(from as i64)
}
}
impl<'a> From<&'a f64> for Plist {
fn from(from: &'a f64) -> Plist {
Plist::Real(*from)
}
}
impl<'a> From<&'a f32> for Plist {
fn from(from: &'a f32) -> Plist {
Plist::Real(*from as f64)
}
}
impl<'a> From<&'a i64> for Plist {
fn from(from: &'a i64) -> Plist {
Plist::Integer(*from)
}
}
impl<'a> From<&'a i32> for Plist {
fn from(from: &'a i32) -> Plist {
Plist::Integer(*from as i64)
}
}
impl<'a> From<&'a i16> for Plist {
fn from(from: &'a i16) -> Plist {
Plist::Integer(*from as i64)
}
}
impl<'a> From<&'a i8> for Plist {
fn from(from: &'a i8) -> Plist {
Plist::Integer(*from as i64)
}
}
impl<'a> From<&'a u32> for Plist {
fn from(from: &'a u32) -> Plist {
Plist::Integer(*from as i64)
}
}
impl<'a> From<&'a u16> for Plist {
fn from(from: &'a u16) -> Plist {
Plist::Integer(*from as i64)
}
}
impl<'a> From<&'a u8> for Plist {
fn from(from: &'a u8) -> Plist {
Plist::Integer(*from as i64)
}
}
impl From<String> for Plist {
fn from(from: String) -> Plist {
Plist::String(from)
}
}
impl<'a> From<&'a str> for Plist {
fn from(from: &'a str) -> Plist {
Plist::String(from.into())
}
}
#[cfg(test)]
mod tests {
use super::Plist;
#[test]
fn test_plist_access() {
use std::collections::BTreeMap;
use chrono::prelude::*;
use super::Date;
let vec = vec![Plist::Real(0.0)];
let mut array = Plist::Array(vec.clone());
assert_eq!(array.as_array(), Some(&vec.clone()));
assert_eq!(array.as_array_mut(), Some(&mut vec.clone()));
let mut map = BTreeMap::new();
map.insert("key1".to_owned(), Plist::String("value1".to_owned()));
let mut dict = Plist::Dictionary(map.clone());
assert_eq!(dict.as_dictionary(), Some(&map.clone()));
assert_eq!(dict.as_dictionary_mut(), Some(&mut map.clone()));
assert_eq!(Plist::Boolean(true).as_boolean(), Some(true));
let slice: &[u8] = &[1, 2, 3];
assert_eq!(Plist::Data(slice.to_vec()).as_data(), Some(slice));
assert_eq!(Plist::Data(slice.to_vec()).into_data(),
Some(slice.to_vec()));
let date: Date = Utc::now().into();
assert_eq!(Plist::Date(date.clone()).as_date(), Some(&date));
assert_eq!(Plist::Real(0.0).as_real(), Some(0.0));
assert_eq!(Plist::Integer(1).as_integer(), Some(1));
assert_eq!(Plist::String("2".to_owned()).as_string(), Some("2"));
assert_eq!(Plist::String("t".to_owned()).into_string(),
Some("t".to_owned()));
}
}