table 0.4.0

A specialized map for storing values of varying types.
Documentation
// Copyright (C) 2018  Project Tsukurou!
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use std::borrow::Cow;
use std::cmp;

use serde::{Serialize, Deserialize};

use list::List;
use table::Table;
use error::Error;
use ser::ValueSerializer;

/// Defines the types of data that can be stored in a table.
#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {

    /// A type with a single value; also called nil or unit. Can be used to
    /// indicate presence of a key but absence of a significant value.
    Null,

    /// A type with two values, `true` and `false`.
    Bool(bool),

    /// A signed 64-bit integer type.
    I64(i64),

    /// A floating-point type with 64-bit precision.
    F64(f64),

    /// A slice of bytes wrapped with a clone-on-write container.
    Bytes(Box<Cow<'a, [u8]>>),

    /// A UTF-8 string wrapped with a clone-on-write container.
    String(Box<Cow<'a, str>>),

    /// A nested list wrapped with a clone-on-write container.
    List(Box<Cow<'a, List<'a>>>),

    /// A nested table wrapped with a clone-on-write container.
    Table(Box<Cow<'a, Table<'a>>>),
}

impl<'a> Value<'a> {
    /// Serializes the given value into a `Value`.
    ///
    /// # Examples
    ///
    /// ```
    /// use table::Value;
    ///
    /// assert_eq!(Value::serialize(&328), Ok(Value::I64(328)));
    /// ```
    pub fn serialize<T>(value: &T) -> Result<Value<'static>, Error>
    where
        T: Serialize + ?Sized,
    {
        value.serialize(ValueSerializer)
    }

    /// Deserializes the referenced `Value` into a value of another type.
    ///
    /// # Examples
    ///
    /// ```
    /// use table::Value;
    ///
    /// assert_eq!(Value::Bool(false).deserialize(), Ok(false));
    /// ```
    pub fn deserialize<'b: 'a, T>(&'b self) -> Result<T, Error>
    where
        T: Deserialize<'b>,
    {
        T::deserialize(self)
    }

    /// Deserializes the `Value` into a value of another type, consuming the
    /// `Value` and taking ownership to avoid copying buffers.
    /// 
    /// # Examples
    ///
    /// ```
    /// use table::Value;
    ///
    /// assert_eq!(Value::Null.deserialize_into(), Ok(()));
    /// ```
    pub fn deserialize_into<T>(self) -> Result<T, Error>
    where
        T: Deserialize<'a>,
    {
        T::deserialize(self)
    }
}

convert!(enum Value<'a>, variant Value::Bool: type bool);
convert!(enum Value<'a>, variant Value::I64: type i64);
convert!(enum Value<'a>, variant Value::F64: type f64);
convert!(enum Value<'a>, variant Value::Bytes: type Box<Cow<'a, [u8]>>);
convert!(enum Value<'a>, variant Value::String: type Box<Cow<'a, str>>);
convert!(enum Value<'a>, variant Value::List: type Box<Cow<'a, List<'a>>>);
convert!(enum Value<'a>, variant Value::Table: type Box<Cow<'a, Table<'a>>>);

convert!(enum Value<'a>, type i64: from i8, i16, i32, u8, u16, u32);
convert!(enum Value<'a>, type i64: from_as u64, isize, usize);
convert!(enum Value<'a>, type f64: from f32);
convert!(enum Value<'a>, type Box<Cow<'a, [u8]>>: from Cow<'a, [u8]>);
convert!(enum Value<'a>, type Box<Cow<'a, [u8]>>: ref Cow<'a, [u8]>);
convert!(enum Value<'a>, type Box<Cow<'a, str>>: from Cow<'a, str>);
convert!(enum Value<'a>, type Box<Cow<'a, str>>: ref Cow<'a, str>);
convert!(enum Value<'a>, type Box<Cow<'a, List<'a>>>: from Cow<'a, List<'a>>);
convert!(enum Value<'a>, type Box<Cow<'a, List<'a>>>: ref Cow<'a, List<'a>>);
convert!(enum Value<'a>, type Box<Cow<'a, Table<'a>>>: from Cow<'a, Table<'a>>);
convert!(enum Value<'a>, type Box<Cow<'a, Table<'a>>>: ref Cow<'a, Table<'a>>);
convert!(enum Value<'a>: cow [u8], Vec<u8>);
convert!(enum Value<'a>: cow str, String);
convert!(enum Value<'a>: cow List<'a>, List<'a>);
convert!(enum Value<'a>: cow Table<'a>, Table<'a>);

impl<'a> Default for Value<'a> {
    fn default() -> Self {
        Value::Null
    }
}

impl<'a> AsRef<Value<'a>> for Value<'a> {
    fn as_ref(&self) -> &Value<'a> {
        self
    }
}

impl<'a> AsMut<Value<'a>> for Value<'a> {
    fn as_mut(&mut self) -> &mut Value<'a> {
        self
    }
}

impl<'a> PartialOrd for Value<'a> {
    fn partial_cmp(&self, other: &Value<'a>) -> Option<cmp::Ordering> {
        use Value::*;

        match (self, other) {
            (Null, Null) => Some(cmp::Ordering::Equal),
            (Bool(x), Bool(y)) => x.partial_cmp(y),
            (I64(x), I64(y)) => x.partial_cmp(y),
            (F64(x), F64(y)) => x.partial_cmp(y),
            (Bytes(x), Bytes(y)) => x.partial_cmp(y),
            (String(x), String(y)) => x.partial_cmp(y),
            _ => None,
        }
    }
}