<commit_before>use std::mem;
use common::err::{Error, TResult};
use common::string_slice::StringSlice;

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Ty {
  Bool,
  Int1,
  Int2,
  Int4,
  Int8,
  Float4,
  Float8,
  Date,
  Time,
  Timestamp,
  Interval,
  Char,
  Varchar,
  Text,
  Blob
}

pub trait HasTy {
  fn ty(&self) -> Ty;
}

pub trait HasDataTy {
  fn data_ty(&self) -> &DataType;
}

#[allow(non_camel_case_types)]
pub type BOOL_T      = bool;
#[allow(non_camel_case_types)]
pub type INT1_T      = i8;
#[allow(non_camel_case_types)]
pub type INT2_T      = i16;
#[allow(non_camel_case_types)]
pub type INT4_T      = i32;
#[allow(non_camel_case_types)]
pub type INT8_T      = i64;
#[allow(non_camel_case_types)]
pub type FLOAT4_T    = f32;
#[allow(non_camel_case_types)]
pub type FLOAT8_T    = f64;
#[allow(non_camel_case_types)]
pub type DATE_T      = i32;
#[allow(non_camel_case_types)]
pub type TIME_T      = i64;
#[allow(non_camel_case_types)]
pub type TIMESTAMP_T = i64;
#[allow(non_camel_case_types)]
pub type TEXT_T      = StringSlice;

/// Data Domain for each field
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct DataType {
  pub ty : Ty,
  pub len : u32, // for CHAR, VARCHAR
  pub precision : u8, // for numeric or decimal
  pub scale : u8 // for numeric or decimal
}

impl DataType {
  pub fn new (ty : Ty) -> DataType {
    return DataType {ty: ty, len : 0, precision: 0, scale: 0};
  }

  pub fn new_vartype(ty : Ty, len: u32) -> DataType {
    return DataType {ty: ty, len : len, precision: 0, scale: 0};
  }

  pub fn bytes_len(&self) -> u32 {
    DataType::size_of(self)
  }

  #[inline(always)]
  pub fn size_of(data_type: &DataType) -> u32 {
    match data_type.ty {
      Ty::Bool => 1,
      Ty::Int1 => 1,
      Ty::Int2 => 2,
      Ty::Int4 => 4,
      Ty::Int8 => 8,
      Ty::Float4 => 4,
      Ty::Float8 => 8,
      Ty::Date => 4,
      Ty::Time => 8,
      Ty::Timestamp => 8,
      Ty::Interval => 12,
      Ty::Char => data_type.len,
      Ty::Text => mem::size_of::<TEXT_T>()as u32,
      Ty::Varchar | Ty::Blob => 12,
    }
  }

  pub fn has_length(data_type: &DataType) -> bool {
    match data_type.ty {
      Ty::Char | Ty::Varchar | Ty::Blob => true,
      _ => false
    }
  }

  pub fn is_variable(data_type: &DataType) -> bool {
    match data_type.ty {
      Ty::Varchar | Ty::Blob => true,
      _ => false
    }
  }
}

impl HasDataTy for DataType {
  #[inline]
  fn data_ty(&self) -> &DataType {
    &self
  }
}

impl HasTy for DataType {
  #[inline]
  fn ty(&self) -> Ty {
   self.ty
  }
}

pub fn result_data_ty(&lhs_ty: &DataType, &rhs_ty: &DataType) -> TResult<DataType> {
  match lhs_ty.ty() {

    Ty::Bool => {
      match rhs_ty.ty() {
        Ty::Bool => Ok(DataType::new(Ty::Bool)),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Int1 => {
      match rhs_ty.ty() {
        Ty::Int1 | Ty::Int2 | Ty::Int4 | Ty::Int8 | Ty::Float4 | Ty::Float8 =>{
          Ok(rhs_ty.clone())
        },
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Int2 => {
      match rhs_ty.ty() {
        Ty::Int2 | Ty::Int4 | Ty::Int8 | Ty::Float4 | Ty::Float8 => {
          Ok(rhs_ty.clone())
        },
        Ty::Int1 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Int4 => {
      match rhs_ty.ty() {
        Ty::Int4 | Ty::Int8 | Ty::Float4 | Ty::Float8 => Ok(rhs_ty.clone()),
        Ty::Int1 | Ty::Int2 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Int8 => {
      match rhs_ty.ty() {
        Ty::Int8 | Ty::Float4 | Ty::Float8 => Ok(rhs_ty.clone()),
        Ty::Int1 | Ty::Int2 | Ty::Int4 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Float4 => {
      match rhs_ty.ty() {
        Ty::Float4 | Ty::Float8 => Ok(rhs_ty.clone()),
        Ty::Int1 | Ty::Int2 | Ty::Int4 | Ty::Int8 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Float8 => {
      match rhs_ty.ty() {
        Ty::Float8 => Ok(rhs_ty.clone()),
        Ty::Int1 | Ty::Int2 | Ty::Int4 | Ty::Int8 | Ty::Float4 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Time => {
      Err(Error::UndefinedOperator)
    },

    Ty::Date => {
      Err(Error::UndefinedOperator)
    },

    Ty::Timestamp => {
      Err(Error::UndefinedOperator)
    },

    Ty::Interval => {
      Err(Error::UndefinedOperator)
    },

    Ty::Char | Ty::Varchar => {
      Err(Error::UndefinedOperator)
    },

    Ty::Text => {
      match rhs_ty.ty() {
        Ty::Text => Ok(rhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Blob => {
      Err(Error::UndefinedOperator)
    }
  }
}<commit_msg>Add comment for result_data_ty.<commit_after>use std::mem;
use common::err::{Error, TResult};
use common::string_slice::StringSlice;

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Ty {
  Bool,
  Int1,
  Int2,
  Int4,
  Int8,
  Float4,
  Float8,
  Date,
  Time,
  Timestamp,
  Interval,
  Char,
  Varchar,
  Text,
  Blob
}

pub trait HasTy {
  fn ty(&self) -> Ty;
}

pub trait HasDataTy {
  fn data_ty(&self) -> &DataType;
}

#[allow(non_camel_case_types)]
pub type BOOL_T      = bool;
#[allow(non_camel_case_types)]
pub type INT1_T      = i8;
#[allow(non_camel_case_types)]
pub type INT2_T      = i16;
#[allow(non_camel_case_types)]
pub type INT4_T      = i32;
#[allow(non_camel_case_types)]
pub type INT8_T      = i64;
#[allow(non_camel_case_types)]
pub type FLOAT4_T    = f32;
#[allow(non_camel_case_types)]
pub type FLOAT8_T    = f64;
#[allow(non_camel_case_types)]
pub type DATE_T      = i32;
#[allow(non_camel_case_types)]
pub type TIME_T      = i64;
#[allow(non_camel_case_types)]
pub type TIMESTAMP_T = i64;
#[allow(non_camel_case_types)]
pub type TEXT_T      = StringSlice;

/// Data Domain for each field
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct DataType {
  pub ty : Ty,
  pub len : u32, // for CHAR, VARCHAR
  pub precision : u8, // for numeric or decimal
  pub scale : u8 // for numeric or decimal
}

impl DataType {
  pub fn new (ty : Ty) -> DataType {
    return DataType {ty: ty, len : 0, precision: 0, scale: 0};
  }

  pub fn new_vartype(ty : Ty, len: u32) -> DataType {
    return DataType {ty: ty, len : len, precision: 0, scale: 0};
  }

  pub fn bytes_len(&self) -> u32 {
    DataType::size_of(self)
  }

  #[inline(always)]
  pub fn size_of(data_type: &DataType) -> u32 {
    match data_type.ty {
      Ty::Bool => 1,
      Ty::Int1 => 1,
      Ty::Int2 => 2,
      Ty::Int4 => 4,
      Ty::Int8 => 8,
      Ty::Float4 => 4,
      Ty::Float8 => 8,
      Ty::Date => 4,
      Ty::Time => 8,
      Ty::Timestamp => 8,
      Ty::Interval => 12,
      Ty::Char => data_type.len,
      Ty::Text => mem::size_of::<TEXT_T>()as u32,
      Ty::Varchar | Ty::Blob => 12,
    }
  }

  pub fn has_length(data_type: &DataType) -> bool {
    match data_type.ty {
      Ty::Char | Ty::Varchar | Ty::Blob => true,
      _ => false
    }
  }

  pub fn is_variable(data_type: &DataType) -> bool {
    match data_type.ty {
      Ty::Varchar | Ty::Blob => true,
      _ => false
    }
  }
}

impl HasDataTy for DataType {
  #[inline]
  fn data_ty(&self) -> &DataType {
    &self
  }
}

impl HasTy for DataType {
  #[inline]
  fn ty(&self) -> Ty {
   self.ty
  }
}

/// Determine a result data type from two expression data types.
pub fn result_data_ty(&lhs_ty: &DataType, &rhs_ty: &DataType) -> TResult<DataType> {
  match lhs_ty.ty() {

    Ty::Bool => {
      match rhs_ty.ty() {
        Ty::Bool => Ok(DataType::new(Ty::Bool)),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Int1 => {
      match rhs_ty.ty() {
        Ty::Int1 | Ty::Int2 | Ty::Int4 | Ty::Int8 | Ty::Float4 | Ty::Float8 =>{
          Ok(rhs_ty.clone())
        },
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Int2 => {
      match rhs_ty.ty() {
        Ty::Int2 | Ty::Int4 | Ty::Int8 | Ty::Float4 | Ty::Float8 => {
          Ok(rhs_ty.clone())
        },
        Ty::Int1 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Int4 => {
      match rhs_ty.ty() {
        Ty::Int4 | Ty::Int8 | Ty::Float4 | Ty::Float8 => Ok(rhs_ty.clone()),
        Ty::Int1 | Ty::Int2 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Int8 => {
      match rhs_ty.ty() {
        Ty::Int8 | Ty::Float4 | Ty::Float8 => Ok(rhs_ty.clone()),
        Ty::Int1 | Ty::Int2 | Ty::Int4 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Float4 => {
      match rhs_ty.ty() {
        Ty::Float4 | Ty::Float8 => Ok(rhs_ty.clone()),
        Ty::Int1 | Ty::Int2 | Ty::Int4 | Ty::Int8 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Float8 => {
      match rhs_ty.ty() {
        Ty::Float8 => Ok(rhs_ty.clone()),
        Ty::Int1 | Ty::Int2 | Ty::Int4 | Ty::Int8 | Ty::Float4 => Ok(lhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Time => {
      Err(Error::UndefinedOperator)
    },

    Ty::Date => {
      Err(Error::UndefinedOperator)
    },

    Ty::Timestamp => {
      Err(Error::UndefinedOperator)
    },

    Ty::Interval => {
      Err(Error::UndefinedOperator)
    },

    Ty::Char | Ty::Varchar => {
      Err(Error::UndefinedOperator)
    },

    Ty::Text => {
      match rhs_ty.ty() {
        Ty::Text => Ok(rhs_ty.clone()),
        _ => Err(Error::UndefinedOperator)
      }
    },

    Ty::Blob => {
      Err(Error::UndefinedOperator)
    }
  }
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt::Display;
use error::*;

/// Underlying kind of the configuration value.
#[derive(Debug, Clone)]
pub enum ValueKind {
    Nil,
    Boolean(bool),
    Integer(i64),
    Float(f64),
    String(String),
    Table(Table),
    Array(Array),
}

pub type Array = Vec<Value>;
pub type Table = HashMap<String, Value>;

impl Default for ValueKind {
    fn default() -> Self {
        ValueKind::Nil
    }
}

impl<T> From<Option<T>> for ValueKind
    where T: Into<ValueKind>
{
    fn from(value: Option<T>) -> Self {
        match value {
            Some(value) => value.into(),
            None => ValueKind::Nil,
        }
    }
}

impl From<String> for ValueKind {
    fn from(value: String) -> Self {
        ValueKind::String(value.into())
    }
}

impl<'a> From<&'a str> for ValueKind {
    fn from(value: &'a str) -> Self {
        ValueKind::String(value.into())
    }
}

impl From<i64> for ValueKind {
    fn from(value: i64) -> Self {
        ValueKind::Integer(value)
    }
}

impl From<f64> for ValueKind {
    fn from(value: f64) -> Self {
        ValueKind::Float(value)
    }
}

impl From<bool> for ValueKind {
    fn from(value: bool) -> Self {
        ValueKind::Boolean(value)
    }
}

impl<T> From<HashMap<String, T>> for ValueKind
    where T: Into<Value>
{
    fn from(values: HashMap<String, T>) -> Self {
        let mut r = HashMap::new();

        for (k, v) in values {
            r.insert(k.clone(), v.into());
        }

        ValueKind::Table(r)
    }
}

impl<T> From<Vec<T>> for ValueKind
    where T: Into<Value>
{
    fn from(values: Vec<T>) -> Self {
        let mut l = Vec::new();

        for v in values {
            l.push(v.into());
        }

        ValueKind::Array(l)
    }
}

/// A configuration value.
#[derive(Default, Debug, Clone)]
pub struct Value {
    /// A description of the original location of the value.
    ///
    /// A Value originating from a File might contain:
    /// ```
    /// Settings.toml at line 1 column 2
    /// ```
    ///
    /// A Value originating from the environment would contain:
    /// ```
    /// the envrionment
    /// ```
    ///
    /// A Value originating from a remote source might contain:
    /// ```
    /// etcd+http://127.0.0.1:2379
    /// ```
    origin: Option<String>,

    /// Underlying kind of the configuration value.
    pub kind: ValueKind,
}

impl Value {
    pub fn new<V>(origin: Option<&String>, kind: V) -> Self
        where V: Into<ValueKind>
    {
        Value {
            origin: origin.cloned(),
            kind: kind.into(),
        }
    }

    /// Returns `self` as a bool, if possible.
    pub fn into_bool(self) -> Result<bool> {
        match self.kind {
            ValueKind::Boolean(value) => Ok(value),
            ValueKind::Integer(value) => Ok(value != 0),
            ValueKind::Float(value) => Ok(value != 0.0),

            ValueKind::String(ref value) => {
                match value.to_lowercase().as_ref() {
                    "1" | "true" | "on" | "yes" => Ok(true),
                    "0" | "false" | "off" | "no" => Ok(false),

                    // Unexpected string value
                    s @ _ => {
                        Err(ConfigError::invalid_type(self.origin.clone(),
                                                      Unexpected::Str(s.into()),
                                                      "a boolean"))
                    }
                }
            }

            // Unexpected type
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Unit, "a boolean"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Map, "a boolean"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Seq, "a boolean"))
            }
        }
    }

    /// Returns `self` into an i64, if possible.
    pub fn into_int(self) -> Result<i64> {
        match self.kind {
            ValueKind::Integer(value) => Ok(value),

            ValueKind::String(ref s) => {
                match s.to_lowercase().as_ref() {
                    "true" | "on" | "yes" => Ok(1),
                    "false" | "off" | "no" => Ok(0),
                    _ => {
                        s.parse().map_err(|_| {
                                              // Unexpected string
                                              ConfigError::invalid_type(self.origin.clone(),
                                                                        Unexpected::Str(s.clone()),
                                                                        "an integer")
                                          })
                    }
                }
            }

            ValueKind::Boolean(value) => Ok(if value { 1 } else { 0 }),
            ValueKind::Float(value) => Ok(value.round() as i64),

            // Unexpected type
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Unit, "an integer"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Map, "an integer"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Seq, "an integer"))
            }
        }
    }

    /// Returns `self` into a f64, if possible.
    pub fn into_float(self) -> Result<f64> {
        match self.kind {
            ValueKind::Float(value) => Ok(value),

            ValueKind::String(ref s) => {
                match s.to_lowercase().as_ref() {
                    "true" | "on" | "yes" => Ok(1.0),
                    "false" | "off" | "no" => Ok(0.0),
                    _ => {
                        s.parse().map_err(|_| {
                                              // Unexpected string
                                              ConfigError::invalid_type(self.origin.clone(),
                                                                        Unexpected::Str(s.clone()),
                                                                        "a floating point")
                                          })
                    }
                }
            }

            ValueKind::Integer(value) => Ok(value as f64),
            ValueKind::Boolean(value) => Ok(if value { 1.0 } else { 0.0 }),

            // Unexpected type
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin.clone(),
                                              Unexpected::Unit,
                                              "a floating point"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(),
                                              Unexpected::Map,
                                              "a floating point"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(),
                                              Unexpected::Seq,
                                              "a floating point"))
            }
        }
    }

    /// Returns `self` into a str, if possible.
    pub fn into_str(self) -> Result<String> {
        match self.kind {
            ValueKind::String(value) => Ok(value),

            ValueKind::Boolean(value) => Ok(value.to_string()),
            ValueKind::Integer(value) => Ok(value.to_string()),
            ValueKind::Float(value) => Ok(value.to_string()),

            // Cannot convert
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "a string"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Map, "a string"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Seq, "a string"))
            }
        }
    }

    /// Returns `self` into an array, if possible
    pub fn into_array(self) -> Result<Vec<Value>> {
        match self.kind {
            ValueKind::Array(value) => Ok(value),

            // Cannot convert
            ValueKind::Float(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Float(value), "an array"))
            }
            ValueKind::String(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Str(value), "an array"))
            }
            ValueKind::Integer(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Integer(value), "an array"))
            }
            ValueKind::Boolean(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Bool(value), "an array"))
            }
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "an array"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Map, "an array"))
            }
        }
    }

    /// If the `Value` is a Table, returns the associated Map.
    pub fn into_table(self) -> Result<HashMap<String, Value>> {
        match self.kind {
            ValueKind::Table(value) => Ok(value),

            // Cannot convert
            ValueKind::Float(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Float(value), "a map"))
            }
            ValueKind::String(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Str(value), "a map"))
            }
            ValueKind::Integer(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Integer(value), "a map"))
            }
            ValueKind::Boolean(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Bool(value), "a map"))
            }
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "a map"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Seq, "a map"))
            }
        }
    }
}

impl<T> From<T> for Value
    where T: Into<ValueKind>
{
    fn from(value: T) -> Self {
        Value {
            origin: None,
            kind: value.into(),
        }
    }
}
<commit_msg>Make Value itself be deserializable<commit_after>use std::collections::HashMap;
use std::fmt::Display;
use std::fmt;
use error::*;
use serde::de::{Deserialize, Deserializer, Visitor};

/// Underlying kind of the configuration value.
#[derive(Debug, Clone)]
pub enum ValueKind {
    Nil,
    Boolean(bool),
    Integer(i64),
    Float(f64),
    String(String),
    Table(Table),
    Array(Array),
}

pub type Array = Vec<Value>;
pub type Table = HashMap<String, Value>;

impl Default for ValueKind {
    fn default() -> Self {
        ValueKind::Nil
    }
}

impl<T> From<Option<T>> for ValueKind
    where T: Into<ValueKind>
{
    fn from(value: Option<T>) -> Self {
        match value {
            Some(value) => value.into(),
            None => ValueKind::Nil,
        }
    }
}

impl From<String> for ValueKind {
    fn from(value: String) -> Self {
        ValueKind::String(value.into())
    }
}

impl<'a> From<&'a str> for ValueKind {
    fn from(value: &'a str) -> Self {
        ValueKind::String(value.into())
    }
}

impl From<i64> for ValueKind {
    fn from(value: i64) -> Self {
        ValueKind::Integer(value)
    }
}

impl From<f64> for ValueKind {
    fn from(value: f64) -> Self {
        ValueKind::Float(value)
    }
}

impl From<bool> for ValueKind {
    fn from(value: bool) -> Self {
        ValueKind::Boolean(value)
    }
}

impl<T> From<HashMap<String, T>> for ValueKind
    where T: Into<Value>
{
    fn from(values: HashMap<String, T>) -> Self {
        let mut r = HashMap::new();

        for (k, v) in values {
            r.insert(k.clone(), v.into());
        }

        ValueKind::Table(r)
    }
}

impl<T> From<Vec<T>> for ValueKind
    where T: Into<Value>
{
    fn from(values: Vec<T>) -> Self {
        let mut l = Vec::new();

        for v in values {
            l.push(v.into());
        }

        ValueKind::Array(l)
    }
}

/// A configuration value.
#[derive(Default, Debug, Clone)]
pub struct Value {
    /// A description of the original location of the value.
    ///
    /// A Value originating from a File might contain:
    /// ```
    /// Settings.toml
    /// ```
    ///
    /// A Value originating from the environment would contain:
    /// ```
    /// the envrionment
    /// ```
    ///
    /// A Value originating from a remote source might contain:
    /// ```
    /// etcd+http://127.0.0.1:2379
    /// ```
    origin: Option<String>,

    /// Underlying kind of the configuration value.
    pub kind: ValueKind,
}

impl Value {
    pub fn new<V>(origin: Option<&String>, kind: V) -> Self
        where V: Into<ValueKind>
    {
        Value {
            origin: origin.cloned(),
            kind: kind.into(),
        }
    }

    pub fn try_into<'de, T: Deserialize<'de>>(self) -> Result<T> {
        return T::deserialize(self);
    }

    /// Returns `self` as a bool, if possible.
    pub fn into_bool(self) -> Result<bool> {
        match self.kind {
            ValueKind::Boolean(value) => Ok(value),
            ValueKind::Integer(value) => Ok(value != 0),
            ValueKind::Float(value) => Ok(value != 0.0),

            ValueKind::String(ref value) => {
                match value.to_lowercase().as_ref() {
                    "1" | "true" | "on" | "yes" => Ok(true),
                    "0" | "false" | "off" | "no" => Ok(false),

                    // Unexpected string value
                    s @ _ => {
                        Err(ConfigError::invalid_type(self.origin.clone(),
                                                      Unexpected::Str(s.into()),
                                                      "a boolean"))
                    }
                }
            }

            // Unexpected type
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Unit, "a boolean"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Map, "a boolean"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Seq, "a boolean"))
            }
        }
    }

    /// Returns `self` into an i64, if possible.
    pub fn into_int(self) -> Result<i64> {
        match self.kind {
            ValueKind::Integer(value) => Ok(value),

            ValueKind::String(ref s) => {
                match s.to_lowercase().as_ref() {
                    "true" | "on" | "yes" => Ok(1),
                    "false" | "off" | "no" => Ok(0),
                    _ => {
                        s.parse().map_err(|_| {
                                              // Unexpected string
                                              ConfigError::invalid_type(self.origin.clone(),
                                                                        Unexpected::Str(s.clone()),
                                                                        "an integer")
                                          })
                    }
                }
            }

            ValueKind::Boolean(value) => Ok(if value { 1 } else { 0 }),
            ValueKind::Float(value) => Ok(value.round() as i64),

            // Unexpected type
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Unit, "an integer"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Map, "an integer"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(), Unexpected::Seq, "an integer"))
            }
        }
    }

    /// Returns `self` into a f64, if possible.
    pub fn into_float(self) -> Result<f64> {
        match self.kind {
            ValueKind::Float(value) => Ok(value),

            ValueKind::String(ref s) => {
                match s.to_lowercase().as_ref() {
                    "true" | "on" | "yes" => Ok(1.0),
                    "false" | "off" | "no" => Ok(0.0),
                    _ => {
                        s.parse().map_err(|_| {
                                              // Unexpected string
                                              ConfigError::invalid_type(self.origin.clone(),
                                                                        Unexpected::Str(s.clone()),
                                                                        "a floating point")
                                          })
                    }
                }
            }

            ValueKind::Integer(value) => Ok(value as f64),
            ValueKind::Boolean(value) => Ok(if value { 1.0 } else { 0.0 }),

            // Unexpected type
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin.clone(),
                                              Unexpected::Unit,
                                              "a floating point"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(),
                                              Unexpected::Map,
                                              "a floating point"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin.clone(),
                                              Unexpected::Seq,
                                              "a floating point"))
            }
        }
    }

    /// Returns `self` into a str, if possible.
    pub fn into_str(self) -> Result<String> {
        match self.kind {
            ValueKind::String(value) => Ok(value),

            ValueKind::Boolean(value) => Ok(value.to_string()),
            ValueKind::Integer(value) => Ok(value.to_string()),
            ValueKind::Float(value) => Ok(value.to_string()),

            // Cannot convert
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "a string"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Map, "a string"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Seq, "a string"))
            }
        }
    }

    /// Returns `self` into an array, if possible
    pub fn into_array(self) -> Result<Vec<Value>> {
        match self.kind {
            ValueKind::Array(value) => Ok(value),

            // Cannot convert
            ValueKind::Float(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Float(value), "an array"))
            }
            ValueKind::String(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Str(value), "an array"))
            }
            ValueKind::Integer(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Integer(value), "an array"))
            }
            ValueKind::Boolean(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Bool(value), "an array"))
            }
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "an array"))
            }
            ValueKind::Table(_) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Map, "an array"))
            }
        }
    }

    /// If the `Value` is a Table, returns the associated Map.
    pub fn into_table(self) -> Result<HashMap<String, Value>> {
        match self.kind {
            ValueKind::Table(value) => Ok(value),

            // Cannot convert
            ValueKind::Float(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Float(value), "a map"))
            }
            ValueKind::String(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Str(value), "a map"))
            }
            ValueKind::Integer(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Integer(value), "a map"))
            }
            ValueKind::Boolean(value) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Bool(value), "a map"))
            }
            ValueKind::Nil => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Unit, "a map"))
            }
            ValueKind::Array(_) => {
                Err(ConfigError::invalid_type(self.origin, Unexpected::Seq, "a map"))
            }
        }
    }
}

impl<'de> Deserialize<'de> for Value {
    #[inline]
    fn deserialize<D>(deserializer: D) -> ::std::result::Result<Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct ValueVisitor;

        impl<'de> Visitor<'de> for ValueVisitor {
            type Value = Value;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("any valid configuration value")
            }

            #[inline]
            fn visit_bool<E>(self, value: bool) -> ::std::result::Result<Value, E> {
                Ok(value.into())
            }

            #[inline]
            fn visit_i8<E>(self, value: i8) -> ::std::result::Result<Value, E> {
                Ok((value as i64).into())
            }

            #[inline]
            fn visit_i16<E>(self, value: i16) -> ::std::result::Result<Value, E> {
                Ok((value as i64).into())
            }

            #[inline]
            fn visit_i32<E>(self, value: i32) -> ::std::result::Result<Value, E> {
                Ok((value as i64).into())
            }

            #[inline]
            fn visit_i64<E>(self, value: i64) -> ::std::result::Result<Value, E> {
                Ok(value.into())
            }

            #[inline]
            fn visit_u8<E>(self, value: u8) -> ::std::result::Result<Value, E> {
                Ok((value as i64).into())
            }

            #[inline]
            fn visit_u16<E>(self, value: u16) -> ::std::result::Result<Value, E> {
                Ok((value as i64).into())
            }

            #[inline]
            fn visit_u32<E>(self, value: u32) -> ::std::result::Result<Value, E> {
                Ok((value as i64).into())
            }

            #[inline]
            fn visit_u64<E>(self, value: u64) -> ::std::result::Result<Value, E> {
                // FIXME: This is bad
                Ok((value as i64).into())
            }

            #[inline]
            fn visit_f64<E>(self, value: f64) -> ::std::result::Result<Value, E> {
                Ok(value.into())
            }

            #[inline]
            fn visit_str<E>(self, value: &str) -> ::std::result::Result<Value, E>
            where
                E: ::serde::de::Error,
            {
                self.visit_string(String::from(value))
            }

            #[inline]
            fn visit_string<E>(self, value: String) -> ::std::result::Result<Value, E> {
                Ok(value.into())
            }

            #[inline]
            fn visit_none<E>(self) -> ::std::result::Result<Value, E> {
                Ok(Value::new(None, ValueKind::Nil))
            }

            #[inline]
            fn visit_some<D>(self, deserializer: D) -> ::std::result::Result<Value, D::Error>
                where D: Deserializer<'de>
            {
                Deserialize::deserialize(deserializer)
            }

            #[inline]
            fn visit_unit<E>(self) -> ::std::result::Result<Value, E> {
                Ok(Value::new(None, ValueKind::Nil))
            }

            #[inline]
            fn visit_seq<V>(self, mut visitor: V) -> ::std::result::Result<Value, V::Error>
            where
                V: ::serde::de::SeqAccess<'de>,
            {
                let mut vec = Array::new();

                while let Some(elem) = try!(visitor.next_element()) {
                    vec.push(elem);
                }

                Ok(vec.into())
            }

            fn visit_map<V>(self, mut visitor: V) -> ::std::result::Result<Value, V::Error>
            where
                V: ::serde::de::MapAccess<'de>,
            {
                let mut values = Table::new();

                while let Some((key, value)) = try!(visitor.next_entry()) {
                    values.insert(key, value);
                }

                Ok(values.into())
            }
        }

        deserializer.deserialize_any(ValueVisitor)
    }
}

impl<T> From<T> for Value
    where T: Into<ValueKind>
{
    fn from(value: T) -> Self {
        Value {
            origin: None,
            kind: value.into(),
        }
    }
}

pub struct ValueWithKey<'a>(pub Value, &'a str);

impl<'a> ValueWithKey<'a> {
    pub fn new(value: Value, key: &'a str) -> Self
    {
        ValueWithKey(value, key)
    }

    pub fn into_bool(self) -> Result<bool> {
        match self.0.into_bool() {
            Ok(value) => Ok(value),
            Err(error) => Err(error.extend_with_key(self.1))
        }
    }

    /// Returns `self` into an i64, if possible.
    pub fn into_int(self) -> Result<i64> {
        match self.0.into_int() {
            Ok(value) => Ok(value),
            Err(error) => Err(error.extend_with_key(self.1))
        }
    }

    /// Returns `self` into a f64, if possible.
    pub fn into_float(self) -> Result<f64> {
        match self.0.into_float() {
            Ok(value) => Ok(value),
            Err(error) => Err(error.extend_with_key(self.1))
        }
    }

    /// Returns `self` into a str, if possible.
    pub fn into_str(self) -> Result<String> {
        match self.0.into_str() {
            Ok(value) => Ok(value),
            Err(error) => Err(error.extend_with_key(self.1))
        }
    }

    /// Returns `self` into an array, if possible
    pub fn into_array(self) -> Result<Vec<Value>> {
        match self.0.into_array() {
            Ok(value) => Ok(value),
            Err(error) => Err(error.extend_with_key(self.1))
        }
    }

    /// If the `Value` is a Table, returns the associated Map.
    pub fn into_table(self) -> Result<HashMap<String, Value>> {
        match self.0.into_table() {
            Ok(value) => Ok(value),
            Err(error) => Err(error.extend_with_key(self.1))
        }
    }
}
<|endoftext|>


<commit_before>use std::marker;
use std::mem;
use libc::c_uint;

use {raw, Object, FileFavor};
use util::Binding;
use call::Convert;

/// annotated commits, the input to merge and rebase
pub struct AnnotatedCommit<'repo> {
    raw: *mut raw::git_annotated_commit,
    _marker: marker::PhantomData<Object<'repo>>,
}

/// merge options
// modeled after DiffFindOptions
pub struct MergeOptions {
    raw: raw::git_merge_options,
}

impl MergeOptions {
    /// Creates a default set of merge options.
    pub fn new() -> MergeOptions {
        let mut opts = MergeOptions {
            raw: unsafe { mem::zeroed() },
        };
        assert_eq!(unsafe {
            raw::git_merge_init_options(&mut opts.raw, 1)
        }, 0);
        opts
    }

    /// Similarity to consider a file renamed (default 50)
    pub fn rename_threshold(&mut self, thresh: u32) -> &mut MergeOptions {
        self.raw.rename_threshold = thresh;
        self
    }

    ///  Maximum similarity sources to examine for renames (default 200).
    /// If the number of rename candidates (add / delete pairs) is greater than this value,
    /// inexact rename detection is aborted. This setting overrides the `merge.renameLimit`
    /// configuration value.
    pub fn target_limit(&mut self, limit: u32) -> &mut MergeOptions {
        self.raw.target_limit = limit as c_uint;
        self
    }

    /// Specify a side to favor for resolving conflicts
    pub fn file_favor(&mut self, favor: FileFavor) -> &mut MergeOptions {
        self.raw.file_favor = favor.convert();
        self
    }

    fn flag(&mut self, opt: u32, val: bool) -> &mut MergeOptions {
        if val {
            self.raw.file_flags |= opt;
        } else {
            self.raw.file_flags &= !opt;
        }
        self
    }

    /// Create standard conflicted merge files
    pub fn standard_style(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_STYLE_MERGE, find)
    }

    /// Create diff3-style file
    pub fn diff3_style(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_STYLE_DIFF3, find)
    }

    /// Condense non-alphanumeric regions for simplified diff file
    pub fn simplify_alnum(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_SIMPLIFY_ALNUM, find)
    }

    /// Ignore all whitespace
    pub fn ignore_whitespace(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE, find)
    }

    /// Ignore changes in amount of whitespace
    pub fn ignore_whitespace_change(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE, find)
    }

    /// Ignore whitespace at end of line
    pub fn ignore_whitespace_eol(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL, find)
    }

    /// Use the "patience diff" algorithm
    pub fn patience(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_DIFF_PATIENCE, find)
    }

    /// Take extra time to find minimal diff
    pub fn minimal(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_DIFF_MINIMAL, find)
    }

    /// Acquire a pointer to the underlying raw options.
    ///
    /// This function is unsafe as the pointer is only valid so long as this
    /// structure is not moved, modified, or used elsewhere.
    // modeled after DiffOptions.raw()
    pub unsafe fn raw(&self) -> *const raw::git_merge_options {
        &self.raw as *const _
    }
}

impl<'repo> Binding for AnnotatedCommit<'repo> {
    type Raw = *mut raw::git_annotated_commit;
    unsafe fn from_raw(raw: *mut raw::git_annotated_commit) -> AnnotatedCommit<'repo> {
        AnnotatedCommit {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_annotated_commit { self.raw }
}

impl<'repo> Drop for AnnotatedCommit<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_annotated_commit_free(self.raw) }
    }
}
<commit_msg>Add find renames<commit_after>use std::marker;
use std::mem;
use libc::c_uint;

use {raw, Object, FileFavor};
use util::Binding;
use call::Convert;

/// annotated commits, the input to merge and rebase
pub struct AnnotatedCommit<'repo> {
    raw: *mut raw::git_annotated_commit,
    _marker: marker::PhantomData<Object<'repo>>,
}

/// merge options
// modeled after DiffFindOptions
pub struct MergeOptions {
    raw: raw::git_merge_options,
}

impl MergeOptions {
    /// Creates a default set of merge options.
    pub fn new() -> MergeOptions {
        let mut opts = MergeOptions {
            raw: unsafe { mem::zeroed() },
        };
        assert_eq!(unsafe {
            raw::git_merge_init_options(&mut opts.raw, 1)
        }, 0);
        opts
    }

    /// Detect file renames
    pub fn find_renames(&mut self, find: bool) -> &mut MergeOptions {
        if find {
            self.raw.tree_flags |= raw::GIT_MERGE_TREE_FIND_RENAMES;
        } else {
            self.raw.tree_flags &= !raw::GIT_MERGE_TREE_FIND_RENAMES;
        }
        self
    }

    /// Similarity to consider a file renamed (default 50)
    pub fn rename_threshold(&mut self, thresh: u32) -> &mut MergeOptions {
        self.raw.rename_threshold = thresh;
        self
    }

    ///  Maximum similarity sources to examine for renames (default 200).
    /// If the number of rename candidates (add / delete pairs) is greater than this value,
    /// inexact rename detection is aborted. This setting overrides the `merge.renameLimit`
    /// configuration value.
    pub fn target_limit(&mut self, limit: u32) -> &mut MergeOptions {
        self.raw.target_limit = limit as c_uint;
        self
    }

    /// Specify a side to favor for resolving conflicts
    pub fn file_favor(&mut self, favor: FileFavor) -> &mut MergeOptions {
        self.raw.file_favor = favor.convert();
        self
    }

    fn flag(&mut self, opt: u32, val: bool) -> &mut MergeOptions {
        if val {
            self.raw.file_flags |= opt;
        } else {
            self.raw.file_flags &= !opt;
        }
        self
    }

    /// Create standard conflicted merge files
    pub fn standard_style(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_STYLE_MERGE, find)
    }

    /// Create diff3-style file
    pub fn diff3_style(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_STYLE_DIFF3, find)
    }

    /// Condense non-alphanumeric regions for simplified diff file
    pub fn simplify_alnum(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_SIMPLIFY_ALNUM, find)
    }

    /// Ignore all whitespace
    pub fn ignore_whitespace(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE, find)
    }

    /// Ignore changes in amount of whitespace
    pub fn ignore_whitespace_change(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE, find)
    }

    /// Ignore whitespace at end of line
    pub fn ignore_whitespace_eol(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL, find)
    }

    /// Use the "patience diff" algorithm
    pub fn patience(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_DIFF_PATIENCE, find)
    }

    /// Take extra time to find minimal diff
    pub fn minimal(&mut self, find: bool) -> &mut MergeOptions {
        self.flag(raw::GIT_MERGE_FILE_DIFF_MINIMAL, find)
    }

    /// Acquire a pointer to the underlying raw options.
    ///
    /// This function is unsafe as the pointer is only valid so long as this
    /// structure is not moved, modified, or used elsewhere.
    // modeled after DiffOptions.raw()
    pub unsafe fn raw(&self) -> *const raw::git_merge_options {
        &self.raw as *const _
    }
}

impl<'repo> Binding for AnnotatedCommit<'repo> {
    type Raw = *mut raw::git_annotated_commit;
    unsafe fn from_raw(raw: *mut raw::git_annotated_commit) -> AnnotatedCommit<'repo> {
        AnnotatedCommit {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_annotated_commit { self.raw }
}

impl<'repo> Drop for AnnotatedCommit<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_annotated_commit_free(self.raw) }
    }
}
<|endoftext|>


<commit_before>use Model;
use linear_algebra::Vector;
use std::marker::PhantomData;

/// Models the target as a constant `c`
///
/// This model predicts a number. The cost function used during training decides
/// whether this number is a mean, median, or something else.
///
/// # Examples
///
/// Estimate mean
///
/// ```
/// use vikos::model::Constant;
/// use vikos::cost::LeastSquares;
/// use vikos::teacher::GradientDescentAl;
/// use vikos::learn_history;
///
/// let features = ();
/// let history = [1f64, 3.0, 4.0, 7.0, 8.0, 11.0, 29.0]; //mean is 9
///
/// let cost = LeastSquares{};
/// let mut model = Constant::new(0.0);
///
/// let teacher = GradientDescentAl{ l0 : 0.3, t : 4.0 };
/// learn_history(&teacher, &cost, &mut model, history.iter().cycle().map(|&y|((),y)).take(100));
/// println!("{}", model.c);
/// ```
#[derive(Debug, Default, RustcDecodable, RustcEncodable)]
pub struct Constant<Input> {
    /// Any prediction made by this model will have the value of `c`
    pub c: f64,
    _phantom: PhantomData<Input>,
}

impl<I> Constant<I> {
    /// Creates a new Constant from a `f64`
    pub fn new(c: f64) -> Constant<I> {
        Constant {
            c: c,
            _phantom: PhantomData::<I> {},
        }
    }
}

impl<I> Clone for Constant<I> {
    fn clone(&self) -> Self {
        Constant::new(self.c)
    }
}

impl<I> Model for Constant<I> {
    type Input = I;

    fn predict(&self, _: &I) -> f64 {
        self.c
    }

    fn num_coefficents(&self) -> usize {
        1
    }

    fn gradient(&self, coefficent: usize, _: &I) -> f64 {
        match coefficent {
            0 => 1.0,
            _ => panic!("coefficent index out of range"),
        }
    }

    fn coefficent(&mut self, coefficent: usize) -> &mut f64 {
        match coefficent {
            0 => &mut self.c,
            _ => panic!("coefficent index out of range"),
        }
    }
}

/// Models the target as `y = m * x + c`
#[derive(Debug, Clone, Default, RustcDecodable, RustcEncodable)]
pub struct Linear<V: Vector> {
    /// Slope
    pub m: V,
    /// Offset
    pub c: V::Scalar,
}

impl<V> Model for Linear<V>
    where V: Vector<Scalar = f64>
{
    type Input = V;

    fn predict(&self, input: &V) -> V::Scalar {
        self.m.dot(input) + self.c
    }

    fn num_coefficents(&self) -> usize {
        self.m.dimension() + 1
    }

    fn gradient(&self, coefficent: usize, input: &V) -> V::Scalar {

        use num::One;

        if coefficent == self.m.dimension() {
            V::Scalar::one() //c
        } else {
            input.at(coefficent)
        }
    }

    fn coefficent(&mut self, coefficent: usize) -> &mut V::Scalar {
        if coefficent == self.m.dimension() {
            &mut self.c
        } else {
            self.m.mut_at(coefficent)
        }
    }
}

/// Models target as `y = 1/(1+e^(m * x + c))`
#[derive(Debug, Clone, Default, RustcDecodable, RustcEncodable)]
pub struct Logistic<V: Vector>(Linear<V>);

impl<V> Model for Logistic<V>
    where V: Vector<Scalar = f64>
{
    type Input = V;

    fn predict(&self, input: &V) -> f64 {
        1.0 / (1.0 + self.0.predict(input).exp())
    }

    fn num_coefficents(&self) -> usize {
        self.0.num_coefficents()
    }

    fn gradient(&self, coefficent: usize, input: &V) -> f64 {
        let p = self.predict(input);
        -p * (1.0 - p) * self.0.gradient(coefficent, input)
    }

    fn coefficent(&mut self, coefficent: usize) -> &mut f64 {
        self.0.coefficent(coefficent)
    }
}

/// Models the target as `y = g(m*x + c)`
#[derive(Clone)]
pub struct GeneralizedLinearModel<V : Vector,G,Dg>{
    /// `Linear` term of the generalized linear `Model`
    pub linear : Linear<V>,
    /// Outer function applied to the result of `linear`
    pub g : G,
    /// Derivation of `g`
    pub g_derivate : Dg,
}

impl<V,G,Dg> GeneralizedLinearModel<V,G,Dg> where V: Vector{

    /// Creates new model with the coefficents set to zero
    pub fn new(g : G, g_derivate : Dg) -> GeneralizedLinearModel<V,G,Dg>
    where V : Default {
        GeneralizedLinearModel{ linear: Linear::default(), g : g, g_derivate : g_derivate}
    }
}

impl<V,F,Df> Model for GeneralizedLinearModel<V,F,Df> where F : Fn (f64) -> f64 + Clone,
 Df : Fn (f64) -> f64 + Clone, V : Vector<Scalar=f64>
{
    type Input = V;

    fn predict(&self, input: &V) -> f64 {
        let f = &self.g;
        f(self.linear.predict(&input))
    }

    fn num_coefficents(&self) -> usize {
        self.linear.num_coefficents()
    }

    fn gradient(&self, coefficent: usize, input: &V) -> f64 {
        let f = &self.g_derivate;
        f(self.linear.predict(&input)) * self.linear.gradient(coefficent, input)
    }

    fn coefficent(&mut self, coefficent: usize) -> &mut f64 {
        self.linear.coefficent(coefficent)
    }
}<commit_msg>applied rustfmt<commit_after>use Model;
use linear_algebra::Vector;
use std::marker::PhantomData;

/// Models the target as a constant `c`
///
/// This model predicts a number. The cost function used during training decides
/// whether this number is a mean, median, or something else.
///
/// # Examples
///
/// Estimate mean
///
/// ```
/// use vikos::model::Constant;
/// use vikos::cost::LeastSquares;
/// use vikos::teacher::GradientDescentAl;
/// use vikos::learn_history;
///
/// let features = ();
/// let history = [1f64, 3.0, 4.0, 7.0, 8.0, 11.0, 29.0]; //mean is 9
///
/// let cost = LeastSquares{};
/// let mut model = Constant::new(0.0);
///
/// let teacher = GradientDescentAl{ l0 : 0.3, t : 4.0 };
/// learn_history(&teacher, &cost, &mut model, history.iter().cycle().map(|&y|((),y)).take(100));
/// println!("{}", model.c);
/// ```
#[derive(Debug, Default, RustcDecodable, RustcEncodable)]
pub struct Constant<Input> {
    /// Any prediction made by this model will have the value of `c`
    pub c: f64,
    _phantom: PhantomData<Input>,
}

impl<I> Constant<I> {
    /// Creates a new Constant from a `f64`
    pub fn new(c: f64) -> Constant<I> {
        Constant {
            c: c,
            _phantom: PhantomData::<I> {},
        }
    }
}

impl<I> Clone for Constant<I> {
    fn clone(&self) -> Self {
        Constant::new(self.c)
    }
}

impl<I> Model for Constant<I> {
    type Input = I;

    fn predict(&self, _: &I) -> f64 {
        self.c
    }

    fn num_coefficents(&self) -> usize {
        1
    }

    fn gradient(&self, coefficent: usize, _: &I) -> f64 {
        match coefficent {
            0 => 1.0,
            _ => panic!("coefficent index out of range"),
        }
    }

    fn coefficent(&mut self, coefficent: usize) -> &mut f64 {
        match coefficent {
            0 => &mut self.c,
            _ => panic!("coefficent index out of range"),
        }
    }
}

/// Models the target as `y = m * x + c`
#[derive(Debug, Clone, Default, RustcDecodable, RustcEncodable)]
pub struct Linear<V: Vector> {
    /// Slope
    pub m: V,
    /// Offset
    pub c: V::Scalar,
}

impl<V> Model for Linear<V>
    where V: Vector<Scalar = f64>
{
    type Input = V;

    fn predict(&self, input: &V) -> V::Scalar {
        self.m.dot(input) + self.c
    }

    fn num_coefficents(&self) -> usize {
        self.m.dimension() + 1
    }

    fn gradient(&self, coefficent: usize, input: &V) -> V::Scalar {

        use num::One;

        if coefficent == self.m.dimension() {
            V::Scalar::one() //c
        } else {
            input.at(coefficent)
        }
    }

    fn coefficent(&mut self, coefficent: usize) -> &mut V::Scalar {
        if coefficent == self.m.dimension() {
            &mut self.c
        } else {
            self.m.mut_at(coefficent)
        }
    }
}

/// Models target as `y = 1/(1+e^(m * x + c))`
#[derive(Debug, Clone, Default, RustcDecodable, RustcEncodable)]
pub struct Logistic<V: Vector>(Linear<V>);

impl<V> Model for Logistic<V>
    where V: Vector<Scalar = f64>
{
    type Input = V;

    fn predict(&self, input: &V) -> f64 {
        1.0 / (1.0 + self.0.predict(input).exp())
    }

    fn num_coefficents(&self) -> usize {
        self.0.num_coefficents()
    }

    fn gradient(&self, coefficent: usize, input: &V) -> f64 {
        let p = self.predict(input);
        -p * (1.0 - p) * self.0.gradient(coefficent, input)
    }

    fn coefficent(&mut self, coefficent: usize) -> &mut f64 {
        self.0.coefficent(coefficent)
    }
}

/// Models the target as `y = g(m*x + c)`
#[derive(Clone)]
pub struct GeneralizedLinearModel<V: Vector, G, Dg> {
    /// `Linear` term of the generalized linear `Model`
    pub linear: Linear<V>,
    /// Outer function applied to the result of `linear`
    pub g: G,
    /// Derivation of `g`
    pub g_derivate: Dg,
}

impl<V, G, Dg> GeneralizedLinearModel<V, G, Dg>
    where V: Vector
{
    /// Creates new model with the coefficents set to zero
    pub fn new(g: G, g_derivate: Dg) -> GeneralizedLinearModel<V, G, Dg>
        where V: Default
    {
        GeneralizedLinearModel {
            linear: Linear::default(),
            g: g,
            g_derivate: g_derivate,
        }
    }
}

impl<V, F, Df> Model for GeneralizedLinearModel<V, F, Df>
    where F: Fn(f64) -> f64 + Clone,
          Df: Fn(f64) -> f64 + Clone,
          V: Vector<Scalar = f64>
{
    type Input = V;

    fn predict(&self, input: &V) -> f64 {
        let f = &self.g;
        f(self.linear.predict(&input))
    }

    fn num_coefficents(&self) -> usize {
        self.linear.num_coefficents()
    }

    fn gradient(&self, coefficent: usize, input: &V) -> f64 {
        let f = &self.g_derivate;
        f(self.linear.predict(&input)) * self.linear.gradient(coefficent, input)
    }

    fn coefficent(&mut self, coefficent: usize) -> &mut f64 {
        self.linear.coefficent(coefficent)
    }
}
<|endoftext|>


<commit_before>use serde::ser::{Serialize, Serializer, SerializeStruct};

#[allow(dead_code)]
pub struct Instance {
    host_name: String,
    app: String,
    ip_addr: String,
    vip_address: String,
    secure_vip_address: String,
    status: Status,
    port: Option<u16>,
    secure_port: u16,
    homepage_url: String,
    status_page_url: String,
    health_check_url: String,
    data_center_info: DataCenterInfo,
    lease_info: Option<LeaseInfo>,
    metadata: Vec<String>
}

#[allow(dead_code)]
pub enum Status {
    Up,
    Down,
    Starting,
    OutOfService,
    Unknown
}

#[allow(dead_code)]
impl ToString for Status {

    fn to_string(&self) -> String {
        let result = match self {
            &Status::Up => "UP",
            &Status::Down => "DOWN",
            &Status::Starting => "STARTING",
            &Status::OutOfService => "OUT_OF_SERVICE",
            _ => "UNKNOWN"
        };
        result.to_string()
    }

}

#[allow(dead_code)]
pub enum DcName {
    MyOwn,
    Amaon
}

#[allow(dead_code)]
pub struct DataCenterInfo {
    name: DcName,
    metadata: AmazonMetaData
}

#[allow(dead_code)]
pub struct AmazonMetaData {
    ami_launch_index: String,
    local_hostname: String,
    availability_zone: String,
    instance_id: String,
    public_ip4: String,
    public_hostname: String,
    ami_manifest_path: String,
    local_ip4: String,
    hostname: String,
    ami_id: String,
    instance_type: String
}

impl Serialize for AmazonMetaData {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
        S: Serializer {

        let mut s = serializer.serialize_struct("AmazonMetaData", 11)?;
        s.serialize_field("ami-launch-index", &self.ami_launch_index)?;
        s.serialize_field("local-hostname", &self.local_hostname)?;
        s.serialize_field("availability-zone", &self.availability_zone)?;
        s.serialize_field("instance-id", &self.instance_id)?;
        s.serialize_field("public-ipv4", &self.public_ip4)?;
        s.serialize_field("public-hostname", &self.public_hostname)?;
        s.serialize_field("ami-manifest-path", &self.ami_manifest_path)?;
        s.serialize_field("local-ipv4", &self.local_ip4)?;
        s.serialize_field("hostname", &self.hostname)?;
        s.serialize_field("ami-id", &self.ami_id)?;
        s.serialize_field("instance-type", &self.instance_type)?;
        s.end()
    }
}

#[allow(dead_code)]
pub struct LeaseInfo {
    eviction_duration_in_secs: Option<u32>
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;

//    #[test]
//    fn test_instance() {
//        let instance = Instance {
//            host_name: "Foo".to_string(),
//            app: "Bar".to_string(),
//            ip_addr: "3.128.2.12".to_string(),
//            vip_address: "127.0.0.1".to_string(),
//            secure_vip_address: "127.0.0.2".to_string(),
//            status: Status::Up,
//            port: Some(80),
//            secure_port: Some(443),
//            homepage_url: "http://google.com".to_string(),
//            status_page_url: "http://nytimes.com".to_string(),
//            health_check_url: "http://washingtonpost.com".to_string(),
//            data_center_info: DataCenterInfo {
//                name: DcName::Amaon,
//                metadata: AmazonMetaData {
//                    ami_launch_index: "001".to_string(),
//                    local_hostname: "localhost".to_string(),
//                    availability_zone: "US_East1".to_string(),
//                    instance_id: "instance1".to_string(),
//                    public_ip4: "32.23.21.21".to_string(),
//                    public_hostname: "foo.com".to_string(),
//                    ami_manifest_path: "/dev/null".to_string(),
//                    local_ip4: "127.0.0.1".to_string(),
//                    hostname: "privatefoo.com".to_string(),
//                    ami_id: "ami002".to_string(),
//                    instance_type: "c4xlarge".to_string()
//                }
//            },
//            lease_info: LeaseInfo {
//                eviction_duration_in_secs: 122121
//            },
//            metadata: vec!["something".to_string()]
//        };
//    }

    #[test]
    fn test_serialize_amazon_meta_data() {
        let md = AmazonMetaData {
            ami_launch_index: "001a".to_string(),
            local_hostname: "localhost0".to_string(),
            availability_zone: "US_East1a".to_string(),
            instance_id: "instance1a".to_string(),
            public_ip4: "32.23.21.212".to_string(),
            public_hostname: "foo.coma".to_string(),
            ami_manifest_path: "/dev/nulla".to_string(),
            local_ip4: "127.0.0.12".to_string(),
            hostname: "privatefoo.coma".to_string(),
            ami_id: "ami0023".to_string(),
            instance_type: "c4xlarged".to_string()
        };
        let json = r#"{"ami-launch-index":"001a","local-hostname":"localhost0","availability-zone":"US_East1a","instance-id":"instance1a","public-ipv4":"32.23.21.212","public-hostname":"foo.coma","ami-manifest-path":"/dev/nulla","local-ipv4":"127.0.0.12","hostname":"privatefoo.coma","ami-id":"ami0023","instance-type":"c4xlarged"}"#;

        let result = serde_json::to_string(&md).unwrap();
        assert_eq!(json, result);
    }
}

<commit_msg>serialization for DataCenterInfo<commit_after>use serde::ser::{Serialize, Serializer, SerializeStruct};

#[allow(dead_code)]
pub struct Instance {
    host_name: String,
    app: String,
    ip_addr: String,
    vip_address: String,
    secure_vip_address: String,
    status: Status,
    port: Option<u16>,
    secure_port: u16,
    homepage_url: String,
    status_page_url: String,
    health_check_url: String,
    data_center_info: DataCenterInfo,
    lease_info: Option<LeaseInfo>,
    metadata: Vec<String>
}

#[allow(dead_code)]
pub enum Status {
    Up,
    Down,
    Starting,
    OutOfService,
    Unknown
}

impl Serialize for Status {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
        S: Serializer {
        let result = match self {
            &Status::Up => "UP",
            &Status::Down => "DOWN",
            &Status::Starting => "STARTING",
            &Status::OutOfService => "OUT_OF_SERVICE",
            _ => "UNKNOWN"
        };
        serializer.serialize_str(result)
    }
}

#[allow(dead_code)]
pub enum DcName {
    MyOwn,
    Amazon
}

impl Serialize for DcName {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
        S: Serializer {
        let result = match self {
            &DcName::MyOwn => "MyOwn",
            &DcName::Amazon => "Amazon"
        };

        serializer.serialize_str(result)
    }
}

#[allow(dead_code)]
pub struct AmazonMetaData {
    ami_launch_index: String,
    local_hostname: String,
    availability_zone: String,
    instance_id: String,
    public_ip4: String,
    public_hostname: String,
    ami_manifest_path: String,
    local_ip4: String,
    hostname: String,
    ami_id: String,
    instance_type: String
}

impl Serialize for AmazonMetaData {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
        S: Serializer {
        let mut s = serializer.serialize_struct("AmazonMetaData", 11)?;
        s.serialize_field("ami-launch-index", &self.ami_launch_index)?;
        s.serialize_field("local-hostname", &self.local_hostname)?;
        s.serialize_field("availability-zone", &self.availability_zone)?;
        s.serialize_field("instance-id", &self.instance_id)?;
        s.serialize_field("public-ipv4", &self.public_ip4)?;
        s.serialize_field("public-hostname", &self.public_hostname)?;
        s.serialize_field("ami-manifest-path", &self.ami_manifest_path)?;
        s.serialize_field("local-ipv4", &self.local_ip4)?;
        s.serialize_field("hostname", &self.hostname)?;
        s.serialize_field("ami-id", &self.ami_id)?;
        s.serialize_field("instance-type", &self.instance_type)?;
        s.end()
    }
}

#[allow(dead_code)]
pub struct DataCenterInfo {
    name: DcName,
    metadata: AmazonMetaData
}

impl Serialize for DataCenterInfo {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
        S: Serializer {
        let mut s = serializer.serialize_struct("DataCenterInfo", 2)?;
        s.serialize_field("name", &self.name)?;
        s.serialize_field("metadata", &self.metadata)?;
        s.end()
    }
}

#[allow(dead_code)]
pub struct LeaseInfo {
    eviction_duration_in_secs: Option<u32>
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;

    //    #[test]
    //    fn test_instance() {
    //        let instance = Instance {
    //            host_name: "Foo".to_string(),
    //            app: "Bar".to_string(),
    //            ip_addr: "3.128.2.12".to_string(),
    //            vip_address: "127.0.0.1".to_string(),
    //            secure_vip_address: "127.0.0.2".to_string(),
    //            status: Status::Up,
    //            port: Some(80),
    //            secure_port: Some(443),
    //            homepage_url: "http://google.com".to_string(),
    //            status_page_url: "http://nytimes.com".to_string(),
    //            health_check_url: "http://washingtonpost.com".to_string(),
    //            data_center_info: DataCenterInfo {
    //                name: DcName::Amaon,
    //                metadata: AmazonMetaData {
    //                    ami_launch_index: "001".to_string(),
    //                    local_hostname: "localhost".to_string(),
    //                    availability_zone: "US_East1".to_string(),
    //                    instance_id: "instance1".to_string(),
    //                    public_ip4: "32.23.21.21".to_string(),
    //                    public_hostname: "foo.com".to_string(),
    //                    ami_manifest_path: "/dev/null".to_string(),
    //                    local_ip4: "127.0.0.1".to_string(),
    //                    hostname: "privatefoo.com".to_string(),
    //                    ami_id: "ami002".to_string(),
    //                    instance_type: "c4xlarge".to_string()
    //                }
    //            },
    //            lease_info: LeaseInfo {
    //                eviction_duration_in_secs: 122121
    //            },
    //            metadata: vec!["something".to_string()]
    //        };
    //    }

    #[test]
    fn test_serialize_amazon_meta_data() {
        let md = AmazonMetaData {
            ami_launch_index: "001a".to_string(),
            local_hostname: "localhost0".to_string(),
            availability_zone: "US_East1a".to_string(),
            instance_id: "instance1a".to_string(),
            public_ip4: "32.23.21.212".to_string(),
            public_hostname: "foo.coma".to_string(),
            ami_manifest_path: "/dev/nulla".to_string(),
            local_ip4: "127.0.0.12".to_string(),
            hostname: "privatefoo.coma".to_string(),
            ami_id: "ami0023".to_string(),
            instance_type: "c4xlarged".to_string()
        };
        let json = sample_meta_data();

        let result = serde_json::to_string(&md).unwrap();
        assert_eq!(json, result);
    }

    #[test]
    fn test_serialize_data_center_info() {
        let dci = DataCenterInfo {
            name: DcName::Amazon,
            metadata: AmazonMetaData {
                ami_launch_index: "001a".to_string(),
                local_hostname: "localhost0".to_string(),
                availability_zone: "US_East1a".to_string(),
                instance_id: "instance1a".to_string(),
                public_ip4: "32.23.21.212".to_string(),
                public_hostname: "foo.coma".to_string(),
                ami_manifest_path: "/dev/nulla".to_string(),
                local_ip4: "127.0.0.12".to_string(),
                hostname: "privatefoo.coma".to_string(),
                ami_id: "ami0023".to_string(),
                instance_type: "c4xlarged".to_string()
            }
        };
        let json = sample_data_center();
        let result = serde_json::to_string(&dci).unwrap();
        assert_eq!(json, result);
    }

    fn sample_meta_data() -> String {
        r#"{ "ami-launch-index": "001a",
            "local-hostname": "localhost0",
            "availability-zone": "US_East1a",
            "instance-id": "instance1a",
            "public-ipv4": "32.23.21.212",
            "public-hostname": "foo.coma",
            "ami-manifest-path": "/dev/nulla",
            "local-ipv4": "127.0.0.12",
            "hostname": "privatefoo.coma",
            "ami-id": "ami0023",
            "instance-type": "c4xlarged" }"#
            .to_string()
            .replace(" ", "")
            .replace("\n", "")
    }

    fn sample_data_center() -> String {
        format!("{{\"name\":\"Amazon\",\"metadata\":{}}}", sample_meta_data())
    }
}

<|endoftext|>


<commit_before>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::fmt;
use std::io;
use std::str::FromStr;

use byteorder::{BigEndian, ReadBytesExt};
use hex::FromHex;

#[derive(Debug, PartialEq)]
pub struct OffsetAddr(u16);

impl FromHex for OffsetAddr {
    type Error = io::Error;
    fn from_hex(s: &str) -> Result<Self, Self::Error> {
        let error = || io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid FSUIPC offset address in '{}'", s));
        let buf: Vec<u8> = try!(FromHex::from_hex(s).map_err(|_| error()));
        if buf.len() > 2 { Err(error()) }
        else {
            (&buf[..]).read_u16::<BigEndian>()
                .map(|v| OffsetAddr(v))
                .map_err(|_| error())
        }
    }
}

impl fmt::Display for OffsetAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:x}", self.0)
    }
}

#[derive(Debug, PartialEq)]
pub enum OffsetLen { Ub, Sb, Uw, Sw, Ud, Sd }

impl fmt::Display for OffsetLen {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            OffsetLen::Ub => write!(f, "UB"),
            OffsetLen::Sb => write!(f, "SB"),
            OffsetLen::Uw => write!(f, "UW"),
            OffsetLen::Sw => write!(f, "SW"),
            OffsetLen::Ud => write!(f, "UD"),
            OffsetLen::Sd => write!(f, "SD"),
        }
    }
}

impl FromStr for OffsetLen {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<OffsetLen, io::Error> {
        match s {
            "UB" => Ok(OffsetLen::Ub),
            "SB" => Ok(OffsetLen::Sb),
            "UW" => Ok(OffsetLen::Uw),
            "SW" => Ok(OffsetLen::Sw),
            "UD" => Ok(OffsetLen::Ud),
            "SD" => Ok(OffsetLen::Sd),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset length in '{}'", s))),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Offset(OffsetAddr, OffsetLen);

impl fmt::Display for Offset {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}:{}", self.0, self.1)
    }
}

impl FromStr for Offset {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<Offset, io::Error> {
        let pair: Vec<&str> = s.split(":").collect();
        if pair.len() == 2 {
            let addr = try!(OffsetAddr::from_hex(pair[0]));
            let len = try!(OffsetLen::from_str(pair[1]));
            Ok(Offset(addr, len))
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset in '{}'", s)))
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Message {
    Begin { version: u16, client_id: String },
    WriteLvar { lvar: String, value: i64 },
    WriteOffset { offset: Offset, value: i64 },
    ObserveLvar { lvar: String }
}

impl Message {

    pub fn begin(version: u16, client_id: &str) -> Message {
        Message::Begin { version: version, client_id: client_id.to_string() }
    }

    pub fn write_lvar(lvar: &str, value: i64) -> Message {
        Message::WriteLvar { lvar: lvar.to_string(), value: value }
    }

    pub fn write_offset(offset: Offset, value: i64) -> Message {
        Message::WriteOffset { offset: offset, value: value }
    }

    pub fn obs_lvar(lvar: &str) -> Message {
        Message::ObserveLvar { lvar: lvar.to_string() }
    }

    pub fn encode<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            &Message::Begin { version, ref client_id } =>
                write!(w, "BEGIN {} {}\n", version, client_id),
            &Message::WriteLvar { ref lvar, value} =>
                write!(w, "WRITE_LVAR {} {}\n", lvar, value),
            &Message::WriteOffset { ref offset, value } =>
                write!(w, "WRITE_OFFSET {} {}\n", offset, value),
            &Message::ObserveLvar { ref lvar } =>
                write!(w, "OBS_LVAR {}\n", lvar),
        }
    }
}

impl FromStr for Message {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<Message, io::Error> {
        let deco = MessageParser::new(s);
        deco.parse()
    }
}

pub struct MessageParser<'a> {
    input: &'a str
}

impl<'a> MessageParser<'a> {
    pub fn new(input: &'a str) -> MessageParser {
        MessageParser { input: input }
    }

    pub fn parse(self) -> io::Result<Message> {
        let args: Vec<&str> = self.input.split_whitespace().collect();
        let cmd = args[0];
        let args = &args[1..];
        match &cmd.to_uppercase()[..] {
            "BEGIN" => self.parse_begin(&args),
            "WRITE_LVAR" => self.parse_write_lvar(&args),
            "WRITE_OFFSET" => self.parse_write_offset(&args),
            "OBS_LVAR" => self.parse_obs_lvar(&args),
            _ => Err(self.input_error()),
        }
    }

    fn parse_begin(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let ver = try!(args[0].parse().map_err(|_| self.input_error()));
        Ok(Message::begin(ver, args[1]))
    }

    fn parse_write_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let lvar = args[0];
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::write_lvar(&lvar, value))
    }

    fn parse_write_offset(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let offset = try!(args[0].parse());
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::write_offset(offset, value))
    }

    fn parse_obs_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 1));
        Ok(Message::obs_lvar(args[0]))
    }

    fn require_argc(&self, args: &[&str], expected: usize) -> io::Result<()> {
        if args.len() == expected { Ok(()) }
        else { Err(self.input_error()) }
    }

    fn input_error(&self) -> io::Error {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid oacsp message in '{}'", self.input))
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;

    use super::*;

    #[test]
    fn should_encode_begin_msg() {
        let mut buf = vec![];
        let msg = Message::begin(1, "arduino");
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"BEGIN 1 arduino\n")
    }

    #[test]
    fn should_decode_begin_msg() {
        let buf = "BEGIN 1 arduino";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::begin(1, "arduino"));
    }

    #[test]
    fn should_encode_write_lvar_msg() {
        let mut buf = vec![];
        let msg = Message::write_lvar("foobar", 42);
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"WRITE_LVAR foobar 42\n")
    }

    #[test]
    fn should_decode_write_lvar_msg() {
        let buf = "WRITE_LVAR foobar 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::write_lvar("foobar", 42));
    }

    #[test]
    fn should_encode_write_offset_msg() {
        let mut buf = vec![];
        let msg = Message::write_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw), 42);
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"WRITE_OFFSET 1234:UW 42\n")
    }

    #[test]
    fn should_decode_write_offset_msg() {
        let buf = "WRITE_OFFSET 1234:UW 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::write_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw), 42));
    }

    #[test]
    fn should_encode_obs_lvar_msg() {
        let mut buf = vec![];
        let msg = Message::obs_lvar("foobar");
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"OBS_LVAR foobar\n")
    }

    #[test]
    fn should_decode_obs_lvar_msg() {
        let buf = "OBS_LVAR foobar";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::obs_lvar("foobar"));
    }
}
<commit_msg>Move msg encoding to `Display` impl in `oacsp` mod<commit_after>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::fmt;
use std::io;
use std::str::FromStr;

use byteorder::{BigEndian, ReadBytesExt};
use hex::FromHex;

#[derive(Debug, PartialEq)]
pub struct OffsetAddr(u16);

impl FromHex for OffsetAddr {
    type Error = io::Error;
    fn from_hex(s: &str) -> Result<Self, Self::Error> {
        let error = || io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid FSUIPC offset address in '{}'", s));
        let buf: Vec<u8> = try!(FromHex::from_hex(s).map_err(|_| error()));
        if buf.len() > 2 { Err(error()) }
        else {
            (&buf[..]).read_u16::<BigEndian>()
                .map(|v| OffsetAddr(v))
                .map_err(|_| error())
        }
    }
}

impl fmt::Display for OffsetAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:x}", self.0)
    }
}

#[derive(Debug, PartialEq)]
pub enum OffsetLen { Ub, Sb, Uw, Sw, Ud, Sd }

impl fmt::Display for OffsetLen {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            OffsetLen::Ub => write!(f, "UB"),
            OffsetLen::Sb => write!(f, "SB"),
            OffsetLen::Uw => write!(f, "UW"),
            OffsetLen::Sw => write!(f, "SW"),
            OffsetLen::Ud => write!(f, "UD"),
            OffsetLen::Sd => write!(f, "SD"),
        }
    }
}

impl FromStr for OffsetLen {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<OffsetLen, io::Error> {
        match s {
            "UB" => Ok(OffsetLen::Ub),
            "SB" => Ok(OffsetLen::Sb),
            "UW" => Ok(OffsetLen::Uw),
            "SW" => Ok(OffsetLen::Sw),
            "UD" => Ok(OffsetLen::Ud),
            "SD" => Ok(OffsetLen::Sd),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset length in '{}'", s))),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Offset(OffsetAddr, OffsetLen);

impl fmt::Display for Offset {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}:{}", self.0, self.1)
    }
}

impl FromStr for Offset {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<Offset, io::Error> {
        let pair: Vec<&str> = s.split(":").collect();
        if pair.len() == 2 {
            let addr = try!(OffsetAddr::from_hex(pair[0]));
            let len = try!(OffsetLen::from_str(pair[1]));
            Ok(Offset(addr, len))
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset in '{}'", s)))
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Message {
    Begin { version: u16, client_id: String },
    WriteLvar { lvar: String, value: i64 },
    WriteOffset { offset: Offset, value: i64 },
    ObserveLvar { lvar: String }
}

impl Message {

    pub fn begin(version: u16, client_id: &str) -> Message {
        Message::Begin { version: version, client_id: client_id.to_string() }
    }

    pub fn write_lvar(lvar: &str, value: i64) -> Message {
        Message::WriteLvar { lvar: lvar.to_string(), value: value }
    }

    pub fn write_offset(offset: Offset, value: i64) -> Message {
        Message::WriteOffset { offset: offset, value: value }
    }

    pub fn obs_lvar(lvar: &str) -> Message {
        Message::ObserveLvar { lvar: lvar.to_string() }
    }
}

impl fmt::Display for Message {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Message::Begin { version, ref client_id } =>
                write!(f, "BEGIN {} {}", version, client_id),
            &Message::WriteLvar { ref lvar, value} =>
                write!(f, "WRITE_LVAR {} {}", lvar, value),
            &Message::WriteOffset { ref offset, value } =>
                write!(f, "WRITE_OFFSET {} {}", offset, value),
            &Message::ObserveLvar { ref lvar } =>
                write!(f, "OBS_LVAR {}", lvar),
        }
    }
}

impl FromStr for Message {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<Message, io::Error> {
        let deco = MessageParser::new(s);
        deco.parse()
    }
}

pub struct MessageParser<'a> {
    input: &'a str
}

impl<'a> MessageParser<'a> {
    pub fn new(input: &'a str) -> MessageParser {
        MessageParser { input: input }
    }

    pub fn parse(self) -> io::Result<Message> {
        let args: Vec<&str> = self.input.split_whitespace().collect();
        let cmd = args[0];
        let args = &args[1..];
        match &cmd.to_uppercase()[..] {
            "BEGIN" => self.parse_begin(&args),
            "WRITE_LVAR" => self.parse_write_lvar(&args),
            "WRITE_OFFSET" => self.parse_write_offset(&args),
            "OBS_LVAR" => self.parse_obs_lvar(&args),
            _ => Err(self.input_error()),
        }
    }

    fn parse_begin(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let ver = try!(args[0].parse().map_err(|_| self.input_error()));
        Ok(Message::begin(ver, args[1]))
    }

    fn parse_write_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let lvar = args[0];
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::write_lvar(&lvar, value))
    }

    fn parse_write_offset(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let offset = try!(args[0].parse());
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::write_offset(offset, value))
    }

    fn parse_obs_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 1));
        Ok(Message::obs_lvar(args[0]))
    }

    fn require_argc(&self, args: &[&str], expected: usize) -> io::Result<()> {
        if args.len() == expected { Ok(()) }
        else { Err(self.input_error()) }
    }

    fn input_error(&self) -> io::Error {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid oacsp message in '{}'", self.input))
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;

    use super::*;

    #[test]
    fn should_encode_begin_msg() {
        let msg = Message::begin(1, "arduino");
        let buf = format!("{}", msg);
        assert_eq!(buf, "BEGIN 1 arduino")
    }

    #[test]
    fn should_decode_begin_msg() {
        let buf = "BEGIN 1 arduino";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::begin(1, "arduino"));
    }

    #[test]
    fn should_encode_write_lvar_msg() {
        let msg = Message::write_lvar("foobar", 42);
        let buf = format!("{}", msg);
        assert_eq!(buf, "WRITE_LVAR foobar 42")
    }

    #[test]
    fn should_decode_write_lvar_msg() {
        let buf = "WRITE_LVAR foobar 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::write_lvar("foobar", 42));
    }

    #[test]
    fn should_encode_write_offset_msg() {
        let msg = Message::write_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw), 42);
        let buf = format!("{}", msg);
        assert_eq!(buf, "WRITE_OFFSET 1234:UW 42")
    }

    #[test]
    fn should_decode_write_offset_msg() {
        let buf = "WRITE_OFFSET 1234:UW 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::write_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw), 42));
    }

    #[test]
    fn should_encode_obs_lvar_msg() {
        let msg = Message::obs_lvar("foobar");
        let buf = format!("{}", msg);
        assert_eq!(buf, "OBS_LVAR foobar")
    }

    #[test]
    fn should_decode_obs_lvar_msg() {
        let buf = "OBS_LVAR foobar";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::obs_lvar("foobar"));
    }
}
<|endoftext|>