<commit_before>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use statistics::*;
use distribution::{Univariate, Continuous, Distribution};
use result::Result;
use error::StatsError;

/// Implements the [Cauchy](https://en.wikipedia.org/wiki/Cauchy_distribution)
/// distribution, also known as the Lorentz distribution.
///
/// # Examples
///
/// ```
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cauchy {
    location: f64,
    scale: f64,
}

impl Cauchy {
    /// Constructs a new cauchy distribution with the given
    /// location and scale.
    ///
    /// # Errors
    ///
    /// Returns an error if location is `NaN` or `rate <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let mut result = Cauchy::new(0.0, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = Cauchy::new(0.0, -1.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(location: f64, scale: f64) -> Result<Cauchy> {
        if location.is_nan() || scale <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            Ok(Cauchy {
                location: location,
                scale: scale,
            })
        }
    }

    /// Returns the location of the cauchy distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// assert_eq!(n.location(), 0.0);
    /// ```
    pub fn location(&self) -> f64 {
        self.location
    }

    /// Returns the scale of the cauchy distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// assert_eq!(n.scale(), 1.0);
    /// ```
    pub fn scale(&self) -> f64 {
        self.scale
    }
}

impl Sample<f64> for Cauchy {
    /// Generate a random sample from a cauchy
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Cauchy {
    /// Generate a random independent sample from a cauchy
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Cauchy {
    /// Generate a random sample from the cauchy distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Cauchy, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Cauchy.new(0.0, 1.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.location + self.scale * (f64::consts::PI * (r.next_f64() - 0.5)).tan()
    }
}

impl Univariate<f64, f64> for Cauchy {
    /// Calculates the cumulative distribution function for the
    /// cauchy distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (1 / π) * arctan((x - x_0) / γ) + 0.5
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn cdf(&self, x: f64) -> f64 {
        (1.0 / f64::consts::PI) * ((x - self.location) / self.scale).atan() + 0.5
    }
}

impl Min<f64> for Cauchy {
    /// Returns the minimum value in the domain of the cauchy
    /// distribution representable by a double precision float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// NEG_INF
    /// ```
    fn min(&self) -> f64 {
        f64::NEG_INFINITY
    }
}

impl Max<f64> for Cauchy {
    /// Returns the maximum value in the domain of the cauchy
    /// distribution representable by a double precision float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// INF
    /// ```
    fn max(&self) -> f64 {
        f64::INFINITY
    }
}

impl Entropy<f64> for Cauchy {
    /// Returns the entropy of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(γ) + ln(4π)
    /// ```
    ///
    /// where `γ` is the scale
    fn entropy(&self) -> f64 {
        (4.0 * f64::consts::PI * self.scale).ln()
    }
}

impl Median<f64> for Cauchy {
    /// Returns the median of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// x_0
    /// ```
    ///
    /// where `x_0` is the location
    fn median(&self) -> f64 {
        self.location
    }
}

impl Mode<f64> for Cauchy {
    /// Returns the mode of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// x_0
    /// ```
    ///
    /// where `x_0` is the location
    fn mode(&self) -> f64 {
        self.location
    }
}

impl Continuous<f64, f64> for Exponential {
    /// Calculates the probability density function for the cauchy
    /// distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 1 / (πγ * (1 + ((x - x_0) / γ)^2))
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn pdf(&self, x: f64) -> f64 {
        1.0 /
        (f64::consts::PI * self.scale *
         (1.0 + ((x - self.location) / self.scale) * ((x - self.location) / self.scale)))
    }

    /// Calculates the log probability density function for the cauchy
    /// distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(1 / (πγ * (1 + ((x - x_0) / γ)^2)))
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn ln_pdf(&self, x: f64) -> f64 {
        -(f64::consts::PI * self.scale *
          (1.0 + ((x - self.location) / self.scale) * ((x - self.location) / self.scale)))
            .ln()
    }
}<commit_msg>wip: begin testing for cauchy<commit_after>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use statistics::*;
use distribution::{Univariate, Continuous, Distribution};
use result::Result;
use error::StatsError;

/// Implements the [Cauchy](https://en.wikipedia.org/wiki/Cauchy_distribution)
/// distribution, also known as the Lorentz distribution.
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Cauchy, Continuous};
/// use statrs::statistics::Mode;
///
/// let n = Cauchy::new(0.0, 1.0).unwrap();
/// assert_eq!(n.mode(), 0.0);
/// assert_eq!(n.pdf(1.0), 0.1591549430918953357689);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cauchy {
    location: f64,
    scale: f64,
}

impl Cauchy {
    /// Constructs a new cauchy distribution with the given
    /// location and scale.
    ///
    /// # Errors
    ///
    /// Returns an error if location or scale are `NaN` or `scale <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let mut result = Cauchy::new(0.0, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = Cauchy::new(0.0, -1.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(location: f64, scale: f64) -> Result<Cauchy> {
        if location.is_nan() || scale.is_nan() || scale <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            Ok(Cauchy {
                location: location,
                scale: scale,
            })
        }
    }

    /// Returns the location of the cauchy distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// assert_eq!(n.location(), 0.0);
    /// ```
    pub fn location(&self) -> f64 {
        self.location
    }

    /// Returns the scale of the cauchy distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// assert_eq!(n.scale(), 1.0);
    /// ```
    pub fn scale(&self) -> f64 {
        self.scale
    }
}

impl Sample<f64> for Cauchy {
    /// Generate a random sample from a cauchy
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Cauchy {
    /// Generate a random independent sample from a cauchy
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Cauchy {
    /// Generate a random sample from the cauchy distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Cauchy, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.location + self.scale * (f64::consts::PI * (r.next_f64() - 0.5)).tan()
    }
}

impl Univariate<f64, f64> for Cauchy {
    /// Calculates the cumulative distribution function for the
    /// cauchy distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (1 / π) * arctan((x - x_0) / γ) + 0.5
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn cdf(&self, x: f64) -> f64 {
        (1.0 / f64::consts::PI) * ((x - self.location) / self.scale).atan() + 0.5
    }
}

impl Min<f64> for Cauchy {
    /// Returns the minimum value in the domain of the cauchy
    /// distribution representable by a double precision float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// NEG_INF
    /// ```
    fn min(&self) -> f64 {
        f64::NEG_INFINITY
    }
}

impl Max<f64> for Cauchy {
    /// Returns the maximum value in the domain of the cauchy
    /// distribution representable by a double precision float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// INF
    /// ```
    fn max(&self) -> f64 {
        f64::INFINITY
    }
}

impl Entropy<f64> for Cauchy {
    /// Returns the entropy of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(γ) + ln(4π)
    /// ```
    ///
    /// where `γ` is the scale
    fn entropy(&self) -> f64 {
        (4.0 * f64::consts::PI * self.scale).ln()
    }
}

impl Median<f64> for Cauchy {
    /// Returns the median of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// x_0
    /// ```
    ///
    /// where `x_0` is the location
    fn median(&self) -> f64 {
        self.location
    }
}

impl Mode<f64> for Cauchy {
    /// Returns the mode of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// x_0
    /// ```
    ///
    /// where `x_0` is the location
    fn mode(&self) -> f64 {
        self.location
    }
}

impl Continuous<f64, f64> for Cauchy {
    /// Calculates the probability density function for the cauchy
    /// distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 1 / (πγ * (1 + ((x - x_0) / γ)^2))
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn pdf(&self, x: f64) -> f64 {
        1.0 /
        (f64::consts::PI * self.scale *
         (1.0 + ((x - self.location) / self.scale) * ((x - self.location) / self.scale)))
    }

    /// Calculates the log probability density function for the cauchy
    /// distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(1 / (πγ * (1 + ((x - x_0) / γ)^2)))
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn ln_pdf(&self, x: f64) -> f64 {
        -(f64::consts::PI * self.scale *
          (1.0 + ((x - self.location) / self.scale) * ((x - self.location) / self.scale)))
            .ln()
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::f64;
    use statistics::*;
    use distribution::{Univariate, Continuous, Cauchy};

    fn try_create(location: f64, scale: f64) -> Cauchy {
        let n = Cauchy::new(location, scale);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(location: f64, scale: f64) {
        let n = try_create(location, scale);
        assert_eq!(location, n.location());
        assert_eq!(scale, n.scale());
    }

    fn bad_create_case(location: f64, scale: f64) {
        let n = Cauchy::new(location, scale);
        assert!(n.is_err());
    }

    fn test_case<F>(location: f64, scale: f64, expected: f64, eval: F)
        where F: Fn(Cauchy) -> f64
    {
        let n = try_create(location, scale);
        let x = eval(n);
        assert_eq!(expected, x);
    }

    #[test]
    fn test_create() {
        create_case(0.0, 0.1);
        create_case(0.0, 1.0);
        create_case(0.0, 10.0);
        create_case(10.0, 11.0);
        create_case(-5.0, 100.0);
        create_case(0.0, f64::INFINITY);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(f64::NAN, 1.0);
        bad_create_case(1.0, f64::NAN);
        bad_create_case(f64::NAN, f64::NAN);
        bad_create_case(1.0, 0.0);
    }

    #[test]
    fn test_entropy() {
        test_case(0.0, 2.0, 3.224171427529236102395, |x| x.entropy());
        test_case(0.1, 4.0, 3.917318608089181411812, |x| x.entropy());
        test_case(1.0, 10.0, 4.833609339963336476996, |x| x.entropy());
        test_case(10.0, 11.0, 4.92891951976766133704, |x| x.entropy());
    }

    #[test]
    fn test_mode() {
        test_case(0.0, 2.0, 0.0, |x| x.mode());
        test_case(0.1, 4.0, 0.1, |x| x.mode());
        test_case(1.0, 10.0, 1.0, |x| x.mode());
        test_case(10.0, 11.0, 10.0, |x| x.mode());
        test_case(0.0, f64::INFINITY, 0.0, |x| x.mode());
    }

    #[test]
    fn test_median() {
        test_case(0.0, 2.0, 0.0, |x| x.median());
        test_case(0.1, 4.0, 0.1, |x| x.median());
        test_case(1.0, 10.0, 1.0, |x| x.median());
        test_case(10.0, 11.0, 10.0, |x| x.median());
        test_case(0.0, f64::INFINITY, 0.0, |x| x.median());
    }

    #[test]
    fn test_min_max() {
        test_case(0.0, 1.0, f64::NEG_INFINITY, |x| x.min());
        test_case(0.0, 1.0, f64::INFINITY, |x| x.max());
    }
}<|endoftext|>


<commit_before>//! This module contains all the OpenGEX structures as specified. The module tries to stay as close
//! to the OpenGEX structures as possible.
//!
//! Some of the documentation might be subjected to copyright by Eric Lengyel. For more detailed
//! documentation, please go to http://opengex.org.

use std::collections::HashMap;
use std::rc::Rc;

/// The Material structure contains information about a material. Material structures are
/// referenced by geometry nodes through MaterialRef structures belonging to GeometryNode
/// structures.
pub struct Material {
    /// Whether the material is two-sided.
    pub two_sided: bool,
    /// An optional name.
    pub name: Option<Name>,
    /// Any number of colors.
    pub color: HashMap<String, Color>,
    /// Any number of parameters.
    pub param: ParamMap,
    /// Any number of textures.
    pub texture: HashMap<String, Texture>,
}

/// A Color structure must contain an RGB or RGBA color value.
pub enum Color {
    /// An RGB color value.
    Rgb(f32, f32, f32),
    /// An RGBA color value.
    Rgba(f32, f32, f32, f32)
}

/// This is a map of different Param structures, for convenience.
pub type ParamMap = HashMap<String, f32>;

/// The Name structure holds the name of a node, morph target, material, or animation clip.
pub type Name = String;

/// The Texture structure holds information about a single texture map, and how it is accessed with
/// texture coordinates.
pub struct Texture {
    /// The index of the texture coordinate set associated with the texture.
    pub texcoord: u32,
    /// A substructure holding the file name of the texture.
    pub file_name: String,
    /// Any number of transformations that are applied to the texture coordinates of a mesh when
    /// they are used to fetch from the texture map.
    pub transformations: Vec<Transformation>,
    /// Any number of animation tracks that are applied to the texture coordinate transformations.
    pub animation: Vec<Animation>
}

/// Helper enum to contain all different kinds of Transformations.
pub enum Transformation {
    /// A Transform structure.
    Transform(Transform),
    /// A Translation structure.
    Translation(Translation),
    /// A Rotation structure.
    Rotation(Rotation),
    /// A Scale structure.
    Scale(Scale)
}

/// The Transform structure holds one or more 4 x 4 transformation matrices. In the cases that a
/// Transform structure is contained inside any type of node structure, a Texture structure, or a
/// Skin structure, it must contain a single matrix. In the case that a Transform structure is
/// contained inside a Skeleton structure, is must contain an array of matrices with one entry for
/// each bone referenced by the skeleton.
///
/// When contained inside a node structure, a Transform structure can be the target of a track
/// stored inside an Animation structure.
pub struct Transform([f32; 16]);

/// The Translation structure holds a translation transformation in one of several possible
/// variants.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Translation structure can be the target of a track
/// stored inside an Animation structure.
pub enum Translation {
    /// The translation occurs along only the X axis.
    X(f32),
    /// The translation occurs along only the Y axis.
    Y(f32),
    /// The translation occurs along only the Z axis.
    Z(f32),
    /// The translation occurs along all three coordinate axes.
    Xyz(f32, f32, f32)
}

/// The Rotation structure represents a rotation along one of several axes.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Rotation structure can be the target of a track
/// stored in an Animation structure.
pub enum Rotation {
    /// The rotation occurs about the X axis.
    X(f32),
    /// The rotation occurs about the Y axis.
    Y(f32),
    /// The rotation occurs about the Z axis.
    Z(f32),
    /// The rotation occurs about an arbitrary axis. The first entry of this structure is the angle
    /// of rotation. The remaining three entries are respectively the X, Y and Z components of the
    /// axis of rotation.
    Axis(f32, f32, f32, f32),
    /// The rotation is given by a quaternion. Please refer to the official OpenGEX documentation
    /// for more information.
    Quaternion(f32, f32, f32, f32)
}

/// The Scale structure represents a scale transformation in one of several possible variants.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Scale structure can be the target of a strack stored
/// inside an Animation structure.
pub enum Scale {
    /// The scaling occurs along only the X axis.
    X(f32),
    /// The scaling occurs along only the Y axis.
    Y(f32),
    /// The scaling occurs along only the Z axis.
    Z(f32),
    /// The scaling occurs along all three coordinate axes.
    Xyz(f32, f32, f32)
}

/// The Animation structure contains animation data for a single node in a scene. Each animation
/// structure is directly contained inside a node structure or Texture structure. Each animation
/// structure contains the data needed to modify its sibling Transformation structures or sibling
/// MorphWeight structures over time.
///
/// More detailed information can be found in the official OpenGEX specification.
pub struct Animation {
    /// Specifies the animation clip index.
    pub clip: u32,
    /// Specifies when the animation begins. If the property is not specifies, the begin time for
    /// the animation is determined by the earliest time values present in the Track structures
    /// belonging to this Animation.
    pub begin: Option<f32>,
    /// Specifies when the animation ends. Like with the begin property, if the property is not
    /// specified, the end time for the animation is determined by the latest time values present
    /// in the Track structures belonging to this Animation.
    pub end: Option<f32>,
    /// One or more tracks that each hold animation keys for a single target.
    pub tracks: Vec<Track>,
}

/// The Track structure contains animation key data for a single Transformation or MorphWeight
/// structure.
pub struct Track {
    /// The target transformation or MorphWeight this track applies to.
    pub target: TrackTarget,
    /// The time curve associated with this track.
    pub time: Time,
    /// The value curve associated with this track.
    pub value: Value
}

/// Enum wrapping over all possible animation track targets.
pub enum TrackTarget {
    /// A Transformation structure. See enum to see possibilities.
    Transformation(Rc<Transformation>),
    /// A MorphWeight structure.
    MorphWeight(Rc<MorphWeight>)
}

/// The Time structure contains key time data in an animation track.
///
/// There are two different kinds of this structure; one for every curve kind.
///
/// The variants in this enum contain vectors. One vector item represents on key time.
pub enum Time {
    /// The times are interpolated linearly.
    Linear(Vec<f32>),
    /// The times are interpolated on a one-dimensional Bézier curve.
    ///
    /// The times in each tuple in the vector are the "value", "-control" and "+control" values of
    /// the Bézier curve respectively.
    Bézier(Vec<(f32, f32, f32)>)
}

/// The Value structure contains key value data in an animation track.
///
/// There are two different kinds of this structure; one for every curve kind.
///
/// The variants in this enum contain vectors. One vector item represents on key value.
pub enum Value {
    /// The values are not interpolated, but remain constant until the next key time.
    Constant(Vec<f32>),
    /// The values are interpolated linearly.
    Linear(Vec<f32>),
    /// The values are interpolated on a one-dimensional Bézier curve.
    ///
    /// The values in each tuple in the vector are the "value", "-control" and "+control" values of
    /// the Bézier curve respectively.
    Bézier(Vec<(f32, f32, f32)>),
    /// The values are interpolated on a tension-continuity-bias (TCB) spline.
    ///
    /// The values in each tuple in the vector are the "value", "tension", "bias" and "continuity"
    /// values of the TCB spline respecitvely. The data contained in these last three values is
    /// always scalar.
    Tcb(Vec<(f32, f32, f32, f32)>)
}

/// A MorphWeight structure holds a single morph weight for a GeometryNode structure, that
/// references a GeometryObject strucure containing vertex data for multiple morph targets.
///
/// A MorphWeight structure can be the target of a track stored inside an Animation structure.
pub struct MorphWeight {
    /// Specifies the morph target index to which this morph weight applies. If the GeometryObject
    /// structure contains no vertex data corresponding to this target index, then this structure
    /// should be ignored. Each MorphWeight structure belonging to any particular GeometryNode
    /// structure must have a unique target index among all morph weights belonging to that
    /// GeometryNode.
    pub target_index: u32,
    /// The weight this MorphWeight structure represents.
    pub weight: f32,
}
<commit_msg>Implemented LightObject, and switched from Rc to Arc.<commit_after>//! This module contains all the OpenGEX structures as specified. The module tries to stay as close
//! to the OpenGEX structures as possible.
//!
//! Some of the documentation might be subjected to copyright by Eric Lengyel. For more detailed
//! documentation, please go to http://opengex.org.

use std::collections::HashMap;
use std::sync::Arc;

/// The Material structure contains information about a material. Material structures are
/// referenced by geometry nodes through MaterialRef structures belonging to GeometryNode
/// structures.
pub struct Material {
    /// Whether the material is two-sided.
    pub two_sided: bool,
    /// An optional name.
    pub name: Option<Name>,
    /// Any number of colors.
    pub color: HashMap<String, Color>,
    /// Any number of parameters.
    pub param: ParamMap,
    /// Any number of textures.
    pub texture: HashMap<String, Texture>,
}

/// A Color structure must contain an RGB or RGBA color value.
pub enum Color {
    /// An RGB color value.
    Rgb(f32, f32, f32),
    /// An RGBA color value.
    Rgba(f32, f32, f32, f32)
}

/// The Param structure contains just a float. While the OpenGEX specification defines a Param as a
/// key-value pair, this is better implemented through a HashMap. See ParamMap.
pub type Param = f32;

/// This is a map of different Param structures, for convenience.
pub type ParamMap = HashMap<String, Param>;
/// The Name structure holds the name of a node, morph target, material, or animation clip.
pub type Name = String;

/// The Texture structure holds information about a single texture map, and how it is accessed with
/// texture coordinates.
pub struct Texture {
    /// The index of the texture coordinate set associated with the texture.
    pub texcoord: u32,
    /// A substructure holding the file name of the texture.
    pub file_name: String,
    /// Any number of transformations that are applied to the texture coordinates of a mesh when
    /// they are used to fetch from the texture map.
    pub transformations: Vec<Transformation>,
    /// Any number of animation tracks that are applied to the texture coordinate transformations.
    pub animation: Vec<Animation>
}

/// Helper enum to contain all different kinds of Transformations.
pub enum Transformation {
    /// A Transform structure.
    Transform(Transform),
    /// A Translation structure.
    Translation(Translation),
    /// A Rotation structure.
    Rotation(Rotation),
    /// A Scale structure.
    Scale(Scale)
}

/// The Transform structure holds one or more 4 x 4 transformation matrices. In the cases that a
/// Transform structure is contained inside any type of node structure, a Texture structure, or a
/// Skin structure, it must contain a single matrix. In the case that a Transform structure is
/// contained inside a Skeleton structure, is must contain an array of matrices with one entry for
/// each bone referenced by the skeleton.
///
/// When contained inside a node structure, a Transform structure can be the target of a track
/// stored inside an Animation structure.
pub struct Transform([f32; 16]);

/// The Translation structure holds a translation transformation in one of several possible
/// variants.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Translation structure can be the target of a track
/// stored inside an Animation structure.
pub enum Translation {
    /// The translation occurs along only the X axis.
    X(f32),
    /// The translation occurs along only the Y axis.
    Y(f32),
    /// The translation occurs along only the Z axis.
    Z(f32),
    /// The translation occurs along all three coordinate axes.
    Xyz(f32, f32, f32)
}

/// The Rotation structure represents a rotation along one of several axes.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Rotation structure can be the target of a track
/// stored in an Animation structure.
pub enum Rotation {
    /// The rotation occurs about the X axis.
    X(f32),
    /// The rotation occurs about the Y axis.
    Y(f32),
    /// The rotation occurs about the Z axis.
    Z(f32),
    /// The rotation occurs about an arbitrary axis. The first entry of this structure is the angle
    /// of rotation. The remaining three entries are respectively the X, Y and Z components of the
    /// axis of rotation.
    Axis(f32, f32, f32, f32),
    /// The rotation is given by a quaternion. Please refer to the official OpenGEX documentation
    /// for more information.
    Quaternion(f32, f32, f32, f32)
}

/// The Scale structure represents a scale transformation in one of several possible variants.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Scale structure can be the target of a strack stored
/// inside an Animation structure.
pub enum Scale {
    /// The scaling occurs along only the X axis.
    X(f32),
    /// The scaling occurs along only the Y axis.
    Y(f32),
    /// The scaling occurs along only the Z axis.
    Z(f32),
    /// The scaling occurs along all three coordinate axes.
    Xyz(f32, f32, f32)
}

/// The Animation structure contains animation data for a single node in a scene. Each animation
/// structure is directly contained inside a node structure or Texture structure. Each animation
/// structure contains the data needed to modify its sibling Transformation structures or sibling
/// MorphWeight structures over time.
///
/// More detailed information can be found in the official OpenGEX specification.
pub struct Animation {
    /// Specifies the animation clip index.
    pub clip: u32,
    /// Specifies when the animation begins. If the property is not specifies, the begin time for
    /// the animation is determined by the earliest time values present in the Track structures
    /// belonging to this Animation.
    pub begin: Option<f32>,
    /// Specifies when the animation ends. Like with the begin property, if the property is not
    /// specified, the end time for the animation is determined by the latest time values present
    /// in the Track structures belonging to this Animation.
    pub end: Option<f32>,
    /// One or more tracks that each hold animation keys for a single target.
    pub tracks: Vec<Track>,
}

/// The Track structure contains animation key data for a single Transformation or MorphWeight
/// structure.
pub struct Track {
    /// The target transformation or MorphWeight this track applies to.
    pub target: TrackTarget,
    /// The time curve associated with this track.
    pub time: Time,
    /// The value curve associated with this track.
    pub value: Value
}

/// Enum wrapping over all possible animation track targets.
pub enum TrackTarget {
    /// A Transformation structure. See enum to see possibilities.
    Transformation(Arc<Transformation>),
    /// A MorphWeight structure.
    MorphWeight(Arc<MorphWeight>)
}

/// The Time structure contains key time data in an animation track.
///
/// There are two different kinds of this structure; one for every curve kind.
///
/// The variants in this enum contain vectors. One vector item represents on key time.
pub enum Time {
    /// The times are interpolated linearly.
    Linear(Vec<f32>),
    /// The times are interpolated on a one-dimensional Bézier curve.
    ///
    /// The times in each tuple in the vector are the "value", "-control" and "+control" values of
    /// the Bézier curve respectively.
    Bézier(Vec<(f32, f32, f32)>)
}

/// The Value structure contains key value data in an animation track.
///
/// There are two different kinds of this structure; one for every curve kind.
///
/// The variants in this enum contain vectors. One vector item represents on key value.
pub enum Value {
    /// The values are not interpolated, but remain constant until the next key time.
    Constant(Vec<f32>),
    /// The values are interpolated linearly.
    Linear(Vec<f32>),
    /// The values are interpolated on a one-dimensional Bézier curve.
    ///
    /// The values in each tuple in the vector are the "value", "-control" and "+control" values of
    /// the Bézier curve respectively.
    Bézier(Vec<(f32, f32, f32)>),
    /// The values are interpolated on a tension-continuity-bias (TCB) spline.
    ///
    /// The values in each tuple in the vector are the "value", "tension", "bias" and "continuity"
    /// values of the TCB spline respecitvely. The data contained in these last three values are
    /// always scalar.
    Tcb(Vec<(f32, f32, f32, f32)>)
}

/// A MorphWeight structure holds a single morph weight for a GeometryNode structure, that
/// references a GeometryObject strucure containing vertex data for multiple morph targets.
///
/// A MorphWeight structure can be the target of a track stored inside an Animation structure.
pub struct MorphWeight {
    /// Specifies the morph target index to which this morph weight applies. If the GeometryObject
    /// structure contains no vertex data corresponding to this target index, then this structure
    /// should be ignored. Each MorphWeight structure belonging to any particular GeometryNode
    /// structure must have a unique target index among all morph weights belonging to that
    /// GeometryNode.
    pub target_index: u32,
    /// The weight this MorphWeight structure represents.
    pub weight: f32,
}

/// The LightObject struture contains data for a light object. Multiple LightNode structures may
/// reference a single LightObject. This allows a scene to contain multiple instances of the same
/// light, with different transformations.
pub struct LightObject {
    /// The type of light emitted by this LightObject.
    pub light_type: LightType,
    /// Whether this LightObject casts shadows. This can be overiden by the LightNode referencing
    /// this LightObject.
    pub cast_shadow: bool,
    /// The colors associated with this LightObject.
    ///
    /// The OpenGEX specification only references one type of color: "light". This is the main
    /// color of light emitted by the light souArce. This defaults to an RGB value of
    /// (1.0, 1.0, 1.0).
    ///
    /// There can be any other number of colors in this HashMap, for application-specific kinds.
    pub colors: HashMap<String, Color>,
    /// The parameters associated with this LightObject.
    ///
    /// The OpenGEX specification only references one type of parameter: "intensity". This is the
    /// intensity of the light emitted by the light souArce. This defaults to 0.
    ///
    /// There can be any other number of parameters in this HashMap, for application-specific
    /// kinds.
    pub params: ParamMap,
    /// The textures associated with this LightObject.
    ///
    /// The OpenGEX specification only references one type of texture: "projection". This is an
    /// optional texture projection of this LightObject. The texture map should be oriented so that
    /// the right direction is aligned to the object-space positive x-axis, and the up direction is
    /// aligned to the object-space positive y-axis.
    ///
    /// There can be any other number of textures in this HashMap, for application-specific kinds.
    pub textures: HashMap<String, Texture>,
    /// Any number of attenuation functions to be applied to the LightObject. The values produced
    /// by all of them are multiplied together to determine the intensity of the light reaching
    /// any particular point in space.
    pub attenuations: Atten
}

/// This is an helper-enum representing all different types of lights that a LightObject can emit.
pub enum LightType {
    /// The light souArce is to be treated as if it were infinitely far away so its rays are
    /// parallel. In object space, the rays point in the direction of the negative z-axis.
    Infinite,
    /// The lght souArce is a point light that radiates in all directions.
    Point,
    /// The light source is a spot light that radiates from a single points byt in a limited range
    /// of directions In object space, the primary direction is the negative z-axis.
    Spot
}

/// The Atten structure specifies an attenuation function for a light object.
pub struct Atten {
    /// The kind of attenuation.
    pub kind: AttenuationKind,
    /// The type of curve defining the attenuation.
    pub curve: AttenuationCurve,
    /// Any parameters associated with this Atten structure.
    ///
    /// For the meaning of the parameters, please refer to the official OpenGEX documentation.
    /// There can exist application-defined parameters.
    pub params: ParamMap
}

/// A helper enum representing different kinds of attenuation functions.
pub enum AttenuationKind {
    /// The input to the attenuation function is the radial distance from the LightObject the
    /// parent Atten structure is associated with.
    Distance,
    /// The input to the attenuation function is the angle formed between the negative z-axis and
    /// the direction to the point being illuminated in object space.
    ///
    /// The result of this function should be raised to the power value of a potential "power"
    /// paramter present in the parent Atten structure.
    Angle,
    /// The input ot the attenuation function is the cosine of the angle formed between the
    /// negative z-axis and the direction to the point being illuminated in objet space.
    ///
    /// The result of this function should be raised to the power value of a potential "power"
    /// paramter present in the parent Atten structure.
    CosAngle
}

/// A helper enum representing different kinds of curves for an attenuation function.
///
/// For exact formulas, please refer to the offical OpenGEX documentation.
pub enum AttenuationCurve {
    /// The attenuation is a linear function.
    Linear,
    /// The attenuation is given by a cubic-smooth-step function.
    Cubic,
    /// The attenuation is given by the inverse function.
    Inverse,
    /// The attenuation is given by the inverse square function.
    InverseSquare
}
<|endoftext|>


<commit_before>///! Provide helpers for making ioctl system calls
///!
///! # Overview of IOCTLs
///!
///! The `ioctl` system call is a widely support system
///! call on *nix systems providing access to functions
///! and data that do not fit nicely into the standard
///! read and write operations on a file itself.  It is
///! common to see ioctls used for the following purposes:
///!
///! * Provide read/write access to out-of-band data related
///!   to a device such as configuration (for instance, setting
///!   serial port options)
///! * Provide a mechanism for performing full-duplex data
///!   transfers (for instance, xfer on SPI devices).
///! * Provide access to control functions on a device (for example,
///!   on Linux you can send commands like pause, resume, and eject
///!   to the CDROM device.
///! * Do whatever else the device driver creator thought made most sense.
///!
///! Ioctls are synchronous system calls and are similar to read and
///! write calls in that regard.
///!
///! The prototype for the ioctl system call in libc is as follows:
///!
///! ```c
///! int ioctl(int fd, unsigned long request, ...);
///! ```
///!
///! Typically, an ioctl takes 3 parameters as arguments:
///! 1. An open file descriptor, `fd`.
///! 2. An device-dependennt request code or operation.  This request
///!    code is referred to as `op` in this module.
///! 3. Either a pointer to a location in memory or an integer.  This
///!    number of pointer may either be used by the kernel or written
///!    to by the kernel depending on how the operation is documented
///!    to work.
///!
///! The `op` request code is essentially an arbitrary integer having
///! a device-driver specific meaning.  Over time, it proved difficult
///! for various driver implementors to use this field sanely, so a
///! convention with macros was introduced to the Linux Kernel that
///! is used by most newer drivers.  See
///! https://github.com/torvalds/linux/blob/master/Documentation/ioctl/ioctl-number.txt
///! for additional details.  The macros exposed by the kernel for
///! consumers are implemented in this module and may be used to
///! instead of calls like `_IOC`, `_IO`, `_IOR`, and `_IOW`.
///!
///! # Interface Overview
///!
///! This ioctl module seeks to tame the ioctl beast by providing
///! a set of safer (although not safe) functions
///! implementing the most common ioctl access patterns.
///!
///! The most common access patterns for ioctls are as follows:
///! 1. `read`: A pointer is provided to the kernel which is populated
///!    with a value containing the "result" of the operation.  The
///!    result may be an integer or structure.  The kernel may also
///!    read values from the provided pointer (usually a structure).
///! 2. `write`: A pointer is provided to the kernel containing values
///!    that the kernel will read in order to perform the operation.
///! 3. `execute`: The operation is passed to the kernel but no
///!    additional pointer is passed.  The operation is enough
///!    and it either succeeds or results in an error.
///!
///! Where appropriate, versions of these interface function are provided
///! taking either refernces or pointers.  The pointer versions are
///! necessary for cases (notably slices) where a reference cannot
///! be generically cast to a pointer.

use libc::funcs::bsd44::ioctl as libc_ioctl;
use std::mem;
use fcntl::Fd;
use {Error, Result, errno};

pub type ioctl_op_t = u32;

// low-level ioctl functions and definitions matching the
// macros provided in ioctl.h from the kernel
const IOC_NRBITS: u32 = 8;
const IOC_TYPEBITS: u32 = 8;
const IOC_SIZEBITS: u32 = 14;
// const IOC_DIRBITS: u32 = 2;

const IOC_NRSHIFT: u32 = 0;
const IOC_TYPESHIFT: u32 = IOC_NRSHIFT + IOC_NRBITS;
const IOC_SIZESHIFT: u32 = IOC_TYPESHIFT + IOC_TYPEBITS;
const IOC_DIRSHIFT: u32 = IOC_SIZESHIFT + IOC_SIZEBITS;

/// Flags indicating the direction of the ioctl operation
/// for ioctls using modern operation conventions
bitflags! {
    flags IoctlDirFlags: u8 {
        /// Indicates that the ioctl data pointer is not used
        const IOC_NONE  = 0x00,
        /// Indicates that the ioctl data pointer contains data that
        /// will be consumed by the operating system
        const IOC_WRITE = 0x01,
        /// Indicates tha the ioctl data pointer contains data that
        /// will be populated by the operating system to be consumed
        /// by userspace
        const IOC_READ  = 0x02,
    }
}

/// Build an ioctl op with the provide parameters.  This is a helper
/// function for IOCTLs in the Linux kernel using the newer conventions
/// for IOCTLs operations.  Many ioctls do not use this newer convention
/// and the constants for those should just be used as-is.
///
/// This provides the same functionality as the Linux `_IOC` macro.
pub fn op(dir: IoctlDirFlags, ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
    // actual number will always fit in 32 bits, but ioctl() expects
    // an unsigned long for the op
    let size_to_use: u32 = if size < (1 << IOC_SIZEBITS) { size as u32 } else { 0 };
    (((dir.bits as u32) << IOC_DIRSHIFT) |
     ((ioctl_type as u32) << IOC_TYPESHIFT) |
     ((nr as u32) << IOC_NRSHIFT) |
     ((size_to_use) << IOC_SIZESHIFT)) as ioctl_op_t
}

/// Build an op indicating that the data pointer is not used.
/// That is, the command itself is sufficient.
///
/// This provides the same functionality the Linux `_IO` macro.
pub fn op_none(ioctl_type: u8, nr: u8) -> ioctl_op_t {
    op(IOC_NONE, ioctl_type, nr, 0)
}

/// Build an op indicating that the data pointer will be populated
/// with data from the kernel
///
/// This provides the same functionality as the Linux `_IOR` macro.
pub fn op_read(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
    op(IOC_READ, ioctl_type, nr, size)
}

/// Build an op indicating that the data pointer contains data
/// to be consumed by the kernel (and not written to).
///
/// This provides the same functionality as the Linux `_IOW` macro.
pub fn op_write(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
    op(IOC_WRITE, ioctl_type, nr, size)
}

/// Build an op indicating that the data pointer both contains
/// data to be consumed by the kernel and contains fields that
/// will be populated by the kernel.
///
/// This provides the same functionality as the Linux `_IOWR` macro.
pub fn op_read_write(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
    op(IOC_WRITE | IOC_READ, ioctl_type, nr, size)
}

fn convert_ioctl_res(res: i32) -> Result<i32> {
    if res < 0 {
        return Err(Error::Sys(errno::Errno::last()))
    }
    Ok(res) // res may length or similar useful to caller
}

/// Ioctl call that is expected to return a result
/// but which does not take any additional arguments on the input side
///
/// This function will allocate allocate space for and returned an owned
/// reference to the result.
pub unsafe fn read<T>(fd: Fd, op: ioctl_op_t) -> Result<T> {
    // allocate memory for the result (should get a value from kernel)
    let mut dst: T = mem::zeroed();
    let dst_ptr: *mut T = &mut dst;
    try!(read_into_ptr(fd, op, dst_ptr));
    Ok(dst)
}

/// Ioctl where the result from the kernel will be written to the
/// provided reference
///
/// The refernced data may also contain information that will be consumed
/// by the kernel.
pub unsafe fn read_into<T>(fd: Fd, op: ioctl_op_t, data: &mut T) -> Result<i32> {
    read_into_ptr(fd, op, data as *mut T)
}

/// Ioctl where the result from the kernel will be written to the
/// provided pointer
///
/// The refernced data may also contain information that will be consumed
/// by the kernel.
pub unsafe fn read_into_ptr<T>(fd: Fd, op: ioctl_op_t, data_ptr: *mut T) -> Result<i32> {
    convert_ioctl_res(libc_ioctl(fd, op as i32, data_ptr))
}

/// Ioctl call that sends a value to the kernel but
/// does not return anything (pure side effect).
pub unsafe fn write<T>(fd: Fd, op: ioctl_op_t, data: &T) -> Result<i32> {
    write_ptr(fd, op, data as *const T)
}

/// Ioctl call that sends a value to the kernel but
/// does not return anything (pure side effect).
pub unsafe fn write_ptr<T>(fd: Fd, op: ioctl_op_t, data: *const T) -> Result<i32> {
    convert_ioctl_res(libc_ioctl(fd, op as i32, data as *const T))
}

/// Ioctl call for which no data pointer is provided to the kernel.
/// That is, the kernel has sufficient information about what to
/// do based on the op alone.
pub fn execute(fd: Fd, op: ioctl_op_t) -> Result<i32> {
    convert_ioctl_res(unsafe { libc_ioctl(fd, op as i32) })
}
<commit_msg>ioctl: modify type signatures to match common ioctl usage and libc impls<commit_after>///! Provide helpers for making ioctl system calls
///!
///! # Overview of IOCTLs
///!
///! The `ioctl` system call is a widely support system
///! call on *nix systems providing access to functions
///! and data that do not fit nicely into the standard
///! read and write operations on a file itself.  It is
///! common to see ioctls used for the following purposes:
///!
///! * Provide read/write access to out-of-band data related
///!   to a device such as configuration (for instance, setting
///!   serial port options)
///! * Provide a mechanism for performing full-duplex data
///!   transfers (for instance, xfer on SPI devices).
///! * Provide access to control functions on a device (for example,
///!   on Linux you can send commands like pause, resume, and eject
///!   to the CDROM device.
///! * Do whatever else the device driver creator thought made most sense.
///!
///! Ioctls are synchronous system calls and are similar to read and
///! write calls in that regard.
///!
///! The prototype for the ioctl system call in libc is as follows:
///!
///! ```c
///! int ioctl(int fd, unsigned long request, ...);
///! ```
///!
///! Typically, an ioctl takes 3 parameters as arguments:
///! 1. An open file descriptor, `fd`.
///! 2. An device-dependennt request code or operation.  This request
///!    code is referred to as `op` in this module.
///! 3. Either a pointer to a location in memory or an integer.  This
///!    number of pointer may either be used by the kernel or written
///!    to by the kernel depending on how the operation is documented
///!    to work.
///!
///! The `op` request code is essentially an arbitrary integer having
///! a device-driver specific meaning.  Over time, it proved difficult
///! for various driver implementors to use this field sanely, so a
///! convention with macros was introduced to the Linux Kernel that
///! is used by most newer drivers.  See
///! https://github.com/torvalds/linux/blob/master/Documentation/ioctl/ioctl-number.txt
///! for additional details.  The macros exposed by the kernel for
///! consumers are implemented in this module and may be used to
///! instead of calls like `_IOC`, `_IO`, `_IOR`, and `_IOW`.
///!
///! # Interface Overview
///!
///! This ioctl module seeks to tame the ioctl beast by providing
///! a set of safer (although not safe) functions
///! implementing the most common ioctl access patterns.
///!
///! The most common access patterns for ioctls are as follows:
///! 1. `read`: A pointer is provided to the kernel which is populated
///!    with a value containing the "result" of the operation.  The
///!    result may be an integer or structure.  The kernel may also
///!    read values from the provided pointer (usually a structure).
///! 2. `write`: A pointer is provided to the kernel containing values
///!    that the kernel will read in order to perform the operation.
///! 3. `execute`: The operation is passed to the kernel but no
///!    additional pointer is passed.  The operation is enough
///!    and it either succeeds or results in an error.
///!
///! Where appropriate, versions of these interface function are provided
///! taking either refernces or pointers.  The pointer versions are
///! necessary for cases (notably slices) where a reference cannot
///! be generically cast to a pointer.

use libc::{c_int, c_ulong};
use libc::funcs::bsd44::ioctl as libc_ioctl;
use std::mem;
use fcntl::Fd;
use {Error, Result, errno};

pub type ioctl_op_t = c_ulong;

// the libc definiton of the 'op' type is platform dependent
#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
type os_ioctl_op_t = c_ulong;

#[cfg(any(target_os = "linux", target_os = "android"))]
type os_ioctl_op_t = c_int;

// low-level ioctl functions and definitions matching the
// macros provided in ioctl.h from the kernel
const IOC_NRBITS: u32 = 8;
const IOC_TYPEBITS: u32 = 8;
const IOC_SIZEBITS: u32 = 14;
// const IOC_DIRBITS: u32 = 2;

const IOC_NRSHIFT: u32 = 0;
const IOC_TYPESHIFT: u32 = IOC_NRSHIFT + IOC_NRBITS;
const IOC_SIZESHIFT: u32 = IOC_TYPESHIFT + IOC_TYPEBITS;
const IOC_DIRSHIFT: u32 = IOC_SIZESHIFT + IOC_SIZEBITS;

/// Flags indicating the direction of the ioctl operation
/// for ioctls using modern operation conventions
bitflags! {
    flags IoctlDirFlags: u8 {
        /// Indicates that the ioctl data pointer is not used
        const IOC_NONE  = 0x00,
        /// Indicates that the ioctl data pointer contains data that
        /// will be consumed by the operating system
        const IOC_WRITE = 0x01,
        /// Indicates tha the ioctl data pointer contains data that
        /// will be populated by the operating system to be consumed
        /// by userspace
        const IOC_READ  = 0x02,
    }
}

/// Build an ioctl op with the provide parameters.  This is a helper
/// function for IOCTLs in the Linux kernel using the newer conventions
/// for IOCTLs operations.  Many ioctls do not use this newer convention
/// and the constants for those should just be used as-is.
///
/// This provides the same functionality as the Linux `_IOC` macro.
pub fn op(dir: IoctlDirFlags, ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
    // actual number will always fit in 32 bits, but ioctl() expects
    // an unsigned long for the op
    let size_to_use: u32 = if size < (1 << IOC_SIZEBITS) { size as u32 } else { 0 };
    (((dir.bits as u32) << IOC_DIRSHIFT) |
     ((ioctl_type as u32) << IOC_TYPESHIFT) |
     ((nr as u32) << IOC_NRSHIFT) |
     ((size_to_use) << IOC_SIZESHIFT)) as ioctl_op_t
}

/// Build an op indicating that the data pointer is not used.
/// That is, the command itself is sufficient.
///
/// This provides the same functionality the Linux `_IO` macro.
pub fn op_none(ioctl_type: u8, nr: u8) -> ioctl_op_t {
    op(IOC_NONE, ioctl_type, nr, 0)
}

/// Build an op indicating that the data pointer will be populated
/// with data from the kernel
///
/// This provides the same functionality as the Linux `_IOR` macro.
pub fn op_read(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
    op(IOC_READ, ioctl_type, nr, size)
}

/// Build an op indicating that the data pointer contains data
/// to be consumed by the kernel (and not written to).
///
/// This provides the same functionality as the Linux `_IOW` macro.
pub fn op_write(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
    op(IOC_WRITE, ioctl_type, nr, size)
}

/// Build an op indicating that the data pointer both contains
/// data to be consumed by the kernel and contains fields that
/// will be populated by the kernel.
///
/// This provides the same functionality as the Linux `_IOWR` macro.
pub fn op_read_write(ioctl_type: u8, nr: u8, size: usize) -> ioctl_op_t {
    op(IOC_WRITE | IOC_READ, ioctl_type, nr, size)
}

fn convert_ioctl_res(res: c_int) -> Result<c_int> {
    if res < 0 {
        return Err(Error::Sys(errno::Errno::last()))
    }
    Ok(res) // res may length or similar useful to caller
}

/// Ioctl call that is expected to return a result
/// but which does not take any additional arguments on the input side
///
/// This function will allocate allocate space for and returned an owned
/// reference to the result.
pub unsafe fn read<T>(fd: Fd, op: ioctl_op_t) -> Result<T> {
    // allocate memory for the result (should get a value from kernel)
    let mut dst: T = mem::zeroed();
    let dst_ptr: *mut T = &mut dst;
    try!(read_into_ptr(fd, op, dst_ptr));
    Ok(dst)
}

/// Ioctl where the result from the kernel will be written to the
/// provided reference
///
/// The refernced data may also contain information that will be consumed
/// by the kernel.
pub unsafe fn read_into<T>(fd: Fd, op: ioctl_op_t, data: &mut T) -> Result<c_int> {
    read_into_ptr(fd, op, data as *mut T)
}

/// Ioctl where the result from the kernel will be written to the
/// provided pointer
///
/// The refernced data may also contain information that will be consumed
/// by the kernel.
pub unsafe fn read_into_ptr<T>(fd: Fd, op: ioctl_op_t, data_ptr: *mut T) -> Result<c_int> {
    convert_ioctl_res(libc_ioctl(fd, op as os_ioctl_op_t, data_ptr))
}

/// Ioctl call that sends a value to the kernel but
/// does not return anything (pure side effect).
pub unsafe fn write<T>(fd: Fd, op: ioctl_op_t, data: &T) -> Result<c_int> {
    write_ptr(fd, op, data as *const T)
}

/// Ioctl call that sends a value to the kernel but
/// does not return anything (pure side effect).
pub unsafe fn write_ptr<T>(fd: Fd, op: ioctl_op_t, data: *const T) -> Result<c_int> {
    convert_ioctl_res(libc_ioctl(fd, op as os_ioctl_op_t, data as *const T))
}

/// Ioctl call for which no data pointer is provided to the kernel.
/// That is, the kernel has sufficient information about what to
/// do based on the op alone.
pub fn execute(fd: Fd, op: ioctl_op_t) -> Result<c_int> {
    convert_ioctl_res(unsafe { libc_ioctl(fd, op as os_ioctl_op_t) })
}
<|endoftext|>


<commit_before>extern crate herder;
extern crate hyper;
extern crate url;

use herder::Client;
use herder::Mastodon;
use herder::mastodon::{NodeInstance, ApiHandler};
use hyper::header::Bearer;
use std::str::FromStr;
use url::Url;

const BASE_URL: &str = "http://localhost:3000";
const MY_TOKEN: &str = "MY_TOKEN";

#[test]
fn mastodon_node_created() {
    let Mastodon(domain) = Mastodon::new(BASE_URL).unwrap();
    assert_eq!(domain, Url::parse(BASE_URL).unwrap());
}

#[test]
fn create_client_with_mastodon_domain() {
    let mastodon = Mastodon::new(BASE_URL).unwrap();
    let Client { url_base, .. } = mastodon.client(MY_TOKEN).unwrap();
    assert_eq!(url_base, Url::parse(BASE_URL).unwrap());
}

#[test]
fn create_client_with_bearer_token() {
    let mastodon = Mastodon::new(BASE_URL).unwrap();
    let Client { token, .. } = mastodon.client(MY_TOKEN).unwrap();
    assert_eq!(token, Bearer::from_str(MY_TOKEN).unwrap());
}

// Testing of ApiHandler trait on Client
#[test]
fn client_builds_api_endpoint_urls() {
    let mastodon = Mastodon::new(BASE_URL).unwrap();
    let client = mastodon.client(MY_TOKEN).unwrap();
    let api_endpoint = client.endpoint_url_string("/api/v1/");
    assert_eq!(api_endpoint, format!("{}/api/v1/", BASE_URL));
}

#[test]
fn client_builds_api_request() {
    unimplemented!()
}
<commit_msg>tests for how the client makes api requests<commit_after>extern crate herder;
extern crate hyper;
extern crate url;

use herder::{Client, Mastodon};
use herder::api::v1::methods::{
    AccountID,
    APIEndpoint,
    APIEndpointRequest,
    RelationshipsQuery,
    SearchAccountsQuery,
    UserFormData
};
use herder::mastodon::{NodeInstance, ApiHandler};
use hyper::header::Bearer;
use hyper::Method::{Get, Patch, Post};
use std::str::FromStr;
use url::Url;

const BASE_URL: &str = "http://localhost:3000";
const MY_TOKEN: &str = "MY_TOKEN";

#[test]
fn mastodon_node_created() {
    let Mastodon(domain) = Mastodon::new(BASE_URL).unwrap();
    assert_eq!(domain, Url::parse(BASE_URL).unwrap());
}

#[test]
fn create_client_with_mastodon_domain() {
    let mastodon = Mastodon::new(BASE_URL).unwrap();
    let Client { url_base, .. } = mastodon.client(MY_TOKEN).unwrap();
    assert_eq!(url_base, Url::parse(BASE_URL).unwrap());
}

#[test]
fn create_client_with_bearer_token() {
    let mastodon = Mastodon::new(BASE_URL).unwrap();
    let Client { token, .. } = mastodon.client(MY_TOKEN).unwrap();
    assert_eq!(token, Bearer::from_str(MY_TOKEN).unwrap());
}

// Testing of ApiHandler trait on Client
#[test]
fn client_builds_api_endpoint_url() {
    let mastodon = Mastodon::new(BASE_URL).unwrap();
    let client = mastodon.client(MY_TOKEN).unwrap();
    let api_endpoint = client.endpoint_url("/api/v1/").unwrap();
    assert_eq!(api_endpoint, Url::parse(&format!("{}/api/v1/", BASE_URL)).unwrap());
}

// Testing API Method Requests
// pub enum APIEndpoint {
//     // AccountsMethod: Fetch Account
//     FetchAccount(AccountID),
//     GetCurrentUser,
//     UpdateCurrentUser(UserFormData),
//     GetAccountFollowers(AccountID),
//     GetFollowing(AccountID),
//     GetAccountStatuses(AccountID),
//     FollowAccount(AccountID),
//     UnfollowAccount(AccountID),
//     BlockAccount(AccountID),
//     UnblockAccount(AccountID),
//     MuteAccount(AccountID),
//     UnmuteAccount(AccountID),
//     GetAccountRelationships(RelationshipsQuery),
//     SearchAccounts(SearchAccountsQuery)
// }

#[test]
fn api_request_fetch_account() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::FetchAccount(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Get);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345")
}

#[test]
fn api_request_get_current_user() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::GetCurrentUser;
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Get);
    assert_eq!(request.uri().path(), "/api/v1/accounts/verify_credentials")
}

#[test]
fn api_request_update_current_user() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::UpdateCurrentUser(UserFormData::new(None, None, None, None));
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Patch);
    assert_eq!(request.uri().path(), "/api/v1/accounts/update_credentials")
}

#[test]
fn api_request_get_account_followers() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::GetAccountFollowers(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Get);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/followers")
}

#[test]
fn api_request_get_account_following() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::GetFollowing(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Get);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/following")
}

#[test]
fn api_request_get_account_statuses() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::GetAccountStatuses(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Get);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/statuses")
}

#[test]
fn api_request_following_an_account() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::FollowAccount(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Post);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/follow")
}

#[test]
fn api_request_unfollowing_an_account() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::UnfollowAccount(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Post);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/unfollow")
}

#[test]
fn api_request_block_an_account() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::BlockAccount(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Post);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/block")
}

#[test]
fn api_request_unblock_an_account() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::UnblockAccount(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Post);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/unblock")
}

#[test]
fn api_request_mute_an_account() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::MuteAccount(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Post);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/mute")
}

#[test]
fn api_request_unmute_an_account() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let endpoint = APIEndpoint::UnmuteAccount(AccountID { id: 12345 });
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Post);
    assert_eq!(request.uri().path(), "/api/v1/accounts/12345/unmute")
}

#[test]
fn api_request_single_account_relationship() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let query = RelationshipsQuery::SingleAccount(AccountID { id: 12345 });
    let endpoint = APIEndpoint::GetAccountRelationships(query);
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Get);
    assert_eq!(request.uri().path(), "/api/v1/accounts/relationships")
}

#[test]
fn api_request_many_accounts_relationship() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let accounts = vec![AccountID { id: 12345 }, AccountID { id: 67890 }];
    let query = RelationshipsQuery::MultipleAccounts(accounts);
    let endpoint = APIEndpoint::GetAccountRelationships(query);
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Get);
    assert_eq!(request.uri().path(), "/api/v1/accounts/relationships")
}

#[test]
fn api_request_search_accounts() {
    let client = Mastodon::new(BASE_URL).unwrap().client(MY_TOKEN).unwrap();
    let query = SearchAccountsQuery { q: String::from("search text"), limit: None };
    let endpoint = APIEndpoint::SearchAccounts(query);
    let request = client.build_request(endpoint).unwrap();
    assert_eq!(*request.method(), Get);
    assert_eq!(request.uri().path(), "/api/v1/accounts/search")
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate mime;
extern crate unix_socket;

use std::ops::DerefMut;
use hyper::Client;
use hyper::client;
use self::hyper::header::{ ContentType, UserAgent, qitem };
use hyper::method::Method;
use self::mime::{ Attr, Mime, Value };
use self::mime::TopLevel::Application;
use self::mime::SubLevel::Json;
use std::io::{ self, Read, Result, Write };
use unix_socket::UnixStream;

#[doc(hidden)]
pub struct Body<'a> {
 read: &'a mut Box<&'a mut Read>,
 size: u64
}

impl<'a> Body<'a> {
  /// Create a new body instance
  pub fn new(read: &'a mut Box<&'a mut Read>, size: u64) -> Body<'a> {
    Body { read: read, size: size }
  }
}

pub trait Transport {
  fn request(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<String>;
  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>>;
}

impl Transport for UnixStream {
  fn request(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<String> {
    let method_str = match method {
      Method::Put    => "PUT",
      Method::Post   => "POST",
      Method::Delete => "DELETE",
               _     => "GET"
    };
    let req = format!("{} {} HTTP/1.0\r\n\r\n", method_str, endpoint);
    try!(self.write_all(req.as_bytes()));
    let mut result = String::new();
    self.read_to_string(&mut result).map(|_| result)
  }

  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>> {
    Err(io::Error::new(io::ErrorKind::InvalidInput, "Not yet implemented"))
  }
}

impl Transport for (Client, String) {
  fn request(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<String> {
    let mut res = match self.stream(method, endpoint, body) {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    let mut body = String::new();

    res.read_to_string(&mut body).map(|_| body)
  }

  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>> {
    let uri = format!("{}{}", self.1, endpoint);
    let mut req = match method {
      Method::Put    => self.0.put(&uri[..]),
      Method::Post   => self.0.post(&uri[..]),
      Method::Delete => self.0.delete(&uri[..]),
                   _ => self.0.get(&uri[..])
    };
    let embodied = match body {
      Some(Body { read: r, size: l }) => {
        let reader: &mut Read = *r.deref_mut();
        let content_type: Mime = Mime(Application, Json, vec![(Attr::Charset, Value::Utf8)]);
        req.header(ContentType(content_type)).body(client::Body::SizedBody(reader, l))
      },
      _ => req
    };
    let mut res = match embodied.send() {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    Ok(Box::new(res))
  }
}
<commit_msg>impl unix socket in a similar fashion<commit_after>extern crate hyper;
extern crate mime;
extern crate unix_socket;

use std::ops::DerefMut;
use hyper::Client;
use hyper::client;
use self::hyper::header::{ ContentType, UserAgent, qitem };
use hyper::method::Method;
use self::mime::{ Attr, Mime, Value };
use self::mime::TopLevel::Application;
use self::mime::SubLevel::Json;
use std::io::{ self, Read, Result, Write };
use unix_socket::UnixStream;

#[doc(hidden)]
pub struct Body<'a> {
 read: &'a mut Box<&'a mut Read>,
 size: u64
}

impl<'a> Body<'a> {
  /// Create a new body instance
  pub fn new(read: &'a mut Box<&'a mut Read>, size: u64) -> Body<'a> {
    Body { read: read, size: size }
  }
}

pub trait Transport {
  fn request(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<String>;
  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>>;
}

impl Transport for UnixStream {
  fn request(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<String> {
    let mut res = match self.stream(method, endpoint, body) {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    let mut body = String::new();
    res.read_to_string(&mut body).map(|_| body)
  }

  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>> {
    let method_str = match method {
      Method::Put    => "PUT",
      Method::Post   => "POST",
      Method::Delete => "DELETE",
               _     => "GET"
    };
    let req = format!("{} {} HTTP/1.0\r\n\r\n", method_str, endpoint);
    try!(self.write_all(req.as_bytes()));
    let clone = try!(self.try_clone());
    Ok(Box::new(clone))
  }
}

impl Transport for (Client, String) {
  fn request(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<String> {
    let mut res = match self.stream(method, endpoint, body) {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    let mut body = String::new();
    res.read_to_string(&mut body).map(|_| body)
  }

  fn stream(&mut self, method: Method, endpoint: &str, body: Option<Body>) -> Result<Box<Read>> {
    let uri = format!("{}{}", self.1, endpoint);
    let mut req = match method {
      Method::Put    => self.0.put(&uri[..]),
      Method::Post   => self.0.post(&uri[..]),
      Method::Delete => self.0.delete(&uri[..]),
                   _ => self.0.get(&uri[..])
    };
    let embodied = match body {
      Some(Body { read: r, size: l }) => {
        let reader: &mut Read = *r.deref_mut();
        let content_type: Mime = Mime(Application, Json, vec![(Attr::Charset, Value::Utf8)]);
        req.header(ContentType(content_type)).body(client::Body::SizedBody(reader, l))
      },
      _ => req
    };
    let mut res = match embodied.send() {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    Ok(Box::new(res))
  }
}
<|endoftext|>


<commit_before>use wrapper::pugi_delete_node;

use tree::NodeBase;

pub enum CNode {}

#[derive(Debug)]
pub struct Node {
    ptr: *mut CNode,
}

impl NodeBase for Node {
    fn get_ptr(&self) -> *mut c_void {
        self.ptr as *mut c_void
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        unsafe { pugi_delete_node(self.ptr) }
    }
}

impl Node {
    pub fn from_ptr(ptr: *mut CNode) -> Result<Self, ()> {
        if ptr.is_null() {
            Err(())
        } else {
            Ok(Node { ptr: ptr })
        }
    }
}
<commit_msg>Implementing Hash and Eq for Node struct<commit_after>use libc::c_void;

use std::cmp::Eq;

use std::hash::{Hash, Hasher};

use tree::NodeBase;

use wrapper::{pugi_delete_node, pugi_node_equal};

pub enum CNode {}

#[derive(Debug)]
pub struct Node {
    ptr: *mut CNode,
}

impl NodeBase for Node {
    fn get_ptr(&self) -> *mut c_void {
        self.ptr as *mut c_void
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        unsafe { pugi_delete_node(self.ptr) }
    }
}

impl Eq for Node {}

impl PartialEq for Node {
    fn eq(&self, other: &Node) -> bool {
        unsafe { pugi_node_equal(self.ptr, other.ptr) == 1 }
    }
}

impl Hash for Node {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.ptr.hash(state)
    }
}

impl Node {
    pub fn from_ptr(ptr: *mut CNode) -> Result<Self, ()> {
        if ptr.is_null() {
            Err(())
        } else {
            Ok(Node { ptr: ptr })
        }
    }
}
<|endoftext|>


<commit_before>use input::Event::{ self, Update };
use input::UpdateArgs;
use ai_behavior::{
    Action,
    State,
    Sequence,
    Success,
    Wait,
    WaitForever,
    WhenAll,
    While,
};

use test_events::TestActions::{ Inc, Dec };

/// Some test actions.
#[derive(Clone, Debug)]
pub enum TestActions {
    /// Increment accumulator.
    Inc,
    /// Decrement accumulator.
    Dec,
}

// A test state machine that can increment and decrement.
fn exec(mut acc: u32, dt: f64, state: &mut State<TestActions, ()>, all_time: bool) -> u32 {
    let e: Event = Update(UpdateArgs { dt: dt });
    state.event(&e, &mut |args| {
        match *args.action {
            Inc => acc += 1,
            Dec => acc -= 1,
        }
        (Success, if all_time { 0.0 } else { args.dt })
    });
    acc
}

// Each action that terminates immediately
// consumes a time of 0.0 seconds.
// This makes it possible to execute one action
// after another without delay or waiting for next update.
#[test]
fn print_2() {
    let a: u32 = 0;
    let seq = Sequence(vec![Action(Inc), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 0.0, &mut state, false);
    assert_eq!(a, 2);
}

// If you wait the exact amount before to execute an action,
// it will execute. This behavior makes it easy to predict
// when an action will run.
#[test]
fn wait_sec() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state, false);
    assert_eq!(a, 1);
}

// When we execute half the time and then the other half,
// then the action should be executed.
#[test]
fn wait_half_sec() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 1);
}

// A sequence of one event is like a bare event.
#[test]
fn sequence_of_one_event() {
    let a: u32 = 0;
    let seq = Sequence(vec![Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state, false);
    assert_eq!(a, 1);
}

// A sequence of wait events is the same as one wait event.
#[test]
fn wait_two_waits() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(0.5), Wait(0.5), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state, false);
    assert_eq!(a, 1);
}

// Increase counter ten times.
#[test]
fn loop_ten_times() {
    let a: u32 = 0;
    let rep = While(Box::new(Wait(50.0)), vec![Wait(0.5), Action(Inc), Wait(0.5)]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state, false);
    assert_eq!(a, 10);
}

// Increase counter once using all available time
#[test]
fn all_time() {
    let a: u32 = 0;
    let rep = While(Box::new(WaitForever), vec![Action(Inc)]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 1);
}

// Increase then decrease counter using all available time
#[test]
fn all_time_twice() {
    let a: u32 = 0;
    let rep = While(Box::new(WaitForever), vec![Action(Inc), Action(Dec)]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 1);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 0);
}

// Increase then decrease counter using all available time inside a sequence
#[test]
fn all_time_sequence() {
    let a: u32 = 0;
    let rep = While(Box::new(WaitForever), vec![Sequence(vec![Action(Inc), Action(Dec)])]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 1);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 0);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 1);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 0);
}

#[test]
fn when_all_wait() {
    let a: u32 = 0;
    let all = Sequence(vec![
            // Wait in parallel.
            WhenAll(vec![Wait(0.5), Wait(1.0)]),
            Action(Inc)
        ]);
    let mut state = State::new(all);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 1);
}
<commit_msg>instant actions need some time to run<commit_after>use input::Event::{ self, Update };
use input::UpdateArgs;
use ai_behavior::{
    Action,
    State,
    Sequence,
    Success,
    Wait,
    WaitForever,
    WhenAll,
    While,
};

use test_events::TestActions::{ Inc, Dec };

/// Some test actions.
#[derive(Clone, Debug)]
pub enum TestActions {
    /// Increment accumulator.
    Inc,
    /// Decrement accumulator.
    Dec,
}

// A test state machine that can increment and decrement.
fn exec(mut acc: u32, dt: f64, state: &mut State<TestActions, ()>, all_time: bool) -> u32 {
    let e: Event = Update(UpdateArgs { dt: dt });
    state.event(&e, &mut |args| {
        match *args.action {
            Inc => acc += 1,
            Dec => acc -= 1,
        }
        (Success, if all_time { 0.0 } else { args.dt })
    });
    acc
}

// Each action that terminates immediately
// consumes a time of 0.0 seconds.
// This makes it possible to execute one action
// after another without delay or waiting for next update.
// so long as there is time remaining.
#[test]
fn print_2() {
    let a: u32 = 0;
    let seq = Sequence(vec![Action(Inc), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 0.1, &mut state, false);
    assert_eq!(a, 2);
}

// If you wait the exact amount before to execute an action,
// it will not execute. There must be time remaining
// for the action to run. This behavior makes it easy to predict
// when an action will run.
#[test]
fn wait_sec() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state, false);
    assert_eq!(a, 0);
    let a = exec(a, 1.0, &mut state, false);
    assert_eq!(a, 1);
}

// When we execute half the time and then the other half,
// then give some time then the action should be executed.
#[test]
fn wait_half_sec() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 1);
}

// A sequence of one event is like a bare event.
#[test]
fn sequence_of_one_event() {
    let a: u32 = 0;
    let seq = Sequence(vec![Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state, false);
    assert_eq!(a, 1);
}

// A sequence of wait events is the same as one wait event.
#[test]
fn wait_two_waits() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(0.5), Wait(0.5), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state, false);
    assert_eq!(a, 0);
    let a = exec(a, 1.0, &mut state, false);
    assert_eq!(a, 1);
}

// Increase counter ten times.
#[test]
fn loop_ten_times() {
    let a: u32 = 0;
    let rep = While(Box::new(Wait(50.0)), vec![Wait(0.5), Action(Inc), Wait(0.5)]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state, false);
    assert_eq!(a, 10);
}

// Increase counter once using all available time
#[test]
fn all_time() {
    let a: u32 = 0;
    let rep = While(Box::new(WaitForever), vec![Action(Inc)]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 1);
}

// Increase then decrease counter using all available time
#[test]
fn all_time_twice() {
    let a: u32 = 0;
    let rep = While(Box::new(WaitForever), vec![Action(Inc), Action(Dec)]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 1);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 0);
}

// Increase then decrease counter using all available time inside a sequence
#[test]
fn all_time_sequence() {
    let a: u32 = 0;
    let rep = While(Box::new(WaitForever), vec![Sequence(vec![Action(Inc), Action(Dec)])]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 1);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 0);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 1);
    let a = exec(a, 10.0, &mut state, true);
    assert_eq!(a, 0);
}

// two waits in parallel is the same as one wait
// of the longest wait.
#[test]
fn when_all_wait() {
    let a: u32 = 0;
    let all = Sequence(vec![
            // Wait in parallel.
            WhenAll(vec![Wait(0.5), Wait(1.0)]),
            Action(Inc)
        ]);
    let mut state = State::new(all);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state, false);
    assert_eq!(a, 1);
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;

pub fn is_transfer_encoding(val: &str) -> bool {
    if val.len() != "transfer-encoding".len() {
        return false;
    }
    for (idx, ch) in val.bytes().enumerate() {
        if b"transfer-encoding"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

pub fn is_content_length(val: &str) -> bool {
    if val.len() != "content-length".len() {
        return false;
    }
    for (idx, ch) in val.bytes().enumerate() {
        if b"content-length"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

pub fn is_connection(val: &str) -> bool {
    if val.len() != "connection".len() {
        return false;
    }
    for (idx, ch) in val.bytes().enumerate() {
        if b"connection"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

pub fn is_expect(val: &str) -> bool {
    if val.len() != "expect".len() {
        return false;
    }
    for (idx, ch) in val.bytes().enumerate() {
        if b"expect"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

// header value is byte sequence
// we need case insensitive comparison and strip out of the whitespace
pub fn is_close(val: &[u8]) -> bool {
    if val.len() < "close".len() {
        return false;
    }
    let mut iter = val.iter();
    for (idx, &ch) in iter.by_ref().enumerate() {
        match ch {
            b'\r' | b'\n' | b' ' | b'\t' => continue,
            b'c' | b'C' => {
                if idx + "close".len() > val.len() {
                    return false;
                }
                break;
            }
            _ => return false,
        }
    }
    for (idx, ch) in iter.by_ref().take(4).enumerate() {
        if b"lose"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

// header value is byte sequence
// we need case insensitive comparison and strip out of the whitespace
pub fn is_chunked(val: &[u8]) -> bool {
    if val.len() < "chunked".len() {
        return false;
    }
    let mut iter = val.iter();
    for (idx, &ch) in iter.by_ref().enumerate() {
        match ch {
            b'\r' | b'\n' | b' ' | b'\t' => continue,
            b'c' | b'C' => {
                if idx + "chunked".len() > val.len() {
                    return false;
                }
                break;
            }
            _ => return false,
        }
    }
    for (idx, ch) in iter.by_ref().take(6).enumerate() {
        if b"hunked"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

// header value is byte sequence
// we need case insensitive comparison and strip out of the whitespace
pub fn is_continue(val: &[u8]) -> bool {
    if val.len() < "100-continue".len() {
        return false;
    }
    let mut iter = val.iter();
    for (idx, &ch) in iter.by_ref().enumerate() {
        match ch {
            b'\r' | b'\n' | b' ' | b'\t' => continue,
            b'1' => {
                if idx + "100-continue".len() > val.len() {
                    return false;
                }
                break;
            }
            _ => return false,
        }
    }
    for (idx, ch) in iter.by_ref().take(11).enumerate() {
        if b"00-continue"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

#[cfg(test)]
mod test {
    use super::{is_content_length, is_transfer_encoding, is_connection};
    use super::{is_expect};
    use super::{is_chunked, is_close, is_continue};

    #[test]
    fn test_content_len() {
        assert!(is_content_length("Content-Length"));
        assert!(is_content_length("content-length"));
        assert!(is_content_length("CONTENT-length"));
        assert!(is_content_length("CONTENT-LENGTH"));
    }

    #[test]
    fn test_transfer_encoding() {
        assert!(is_transfer_encoding("Transfer-Encoding"));
        assert!(is_transfer_encoding("transfer-ENCODING"));
        assert!(is_transfer_encoding("TRANSFER-Encoding"));
        assert!(is_transfer_encoding("TRANSFER-ENCODING"));
    }

    #[test]
    fn test_connection() {
        assert!(is_connection("Connection"));
        assert!(is_connection("CONNECTION"));
        assert!(is_connection("ConneCTION"));
        assert!(is_connection("connection"));
    }

    #[test]
    fn test_chunked() {
        assert!(is_chunked(b"chunked"));
        assert!(is_chunked(b"Chunked"));
        assert!(is_chunked(b"chuNKED"));
        assert!(is_chunked(b"CHUNKED"));
        assert!(is_chunked(b"   CHUNKED"));
        assert!(is_chunked(b"   CHUNKED  "));
        assert!(is_chunked(b"chunked  "));
        assert!(is_chunked(b"   CHUNKED"));
        assert!(!is_chunked(b"   CHUNKED 1 "));
    }

    #[test]
    fn test_close() {
        assert!(is_close(b"close"));
        assert!(is_close(b"Close"));
        assert!(is_close(b"clOSE"));
        assert!(is_close(b"CLOSE"));
        assert!(is_close(b" CLOSE"));
        assert!(is_close(b"   close   "));
        assert!(!is_close(b"Close  1 "));
        assert!(!is_close(b" xclose   "));
    }

    #[test]
    fn test_continue() {
        assert!(is_continue(b"100-continue"));
        assert!(is_continue(b"100-Continue"));
        assert!(is_continue(b"100-conTINUE"));
        assert!(is_continue(b"100-CONTINUE"));
        assert!(is_continue(b"  100-CONTINUE"));
        assert!(is_continue(b"   100-continue   "));
        assert!(!is_continue(b"100-continue y  "));
        assert!(!is_continue(b"100-coztinue   "));
    }
}

<commit_msg>Fix tests for headers<commit_after>use std::ascii::AsciiExt;

pub fn is_transfer_encoding(val: &str) -> bool {
    if val.len() != "transfer-encoding".len() {
        return false;
    }
    for (idx, ch) in val.bytes().enumerate() {
        if b"transfer-encoding"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

pub fn is_content_length(val: &str) -> bool {
    if val.len() != "content-length".len() {
        return false;
    }
    for (idx, ch) in val.bytes().enumerate() {
        if b"content-length"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

pub fn is_connection(val: &str) -> bool {
    if val.len() != "connection".len() {
        return false;
    }
    for (idx, ch) in val.bytes().enumerate() {
        if b"connection"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

pub fn is_expect(val: &str) -> bool {
    if val.len() != "expect".len() {
        return false;
    }
    for (idx, ch) in val.bytes().enumerate() {
        if b"expect"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    return true;
}

// header value is byte sequence
// we need case insensitive comparison and strip out of the whitespace
pub fn is_close(val: &[u8]) -> bool {
    if val.len() < "close".len() {
        return false;
    }
    let mut iter = val.iter();
    for (idx, &ch) in iter.by_ref().enumerate() {
        match ch {
            b'\r' | b'\n' | b' ' | b'\t' => continue,
            b'c' | b'C' => {
                if idx + "close".len() > val.len() {
                    return false;
                }
                break;
            }
            _ => return false,
        }
    }
    for (idx, ch) in iter.by_ref().take(4).enumerate() {
        if b"lose"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    for &ch in iter {
        if !matches!(ch, b'\r' | b'\n' | b' ' | b'\t') {
            return false;
        }
    }
    return true;
}

// header value is byte sequence
// we need case insensitive comparison and strip out of the whitespace
pub fn is_chunked(val: &[u8]) -> bool {
    if val.len() < "chunked".len() {
        return false;
    }
    let mut iter = val.iter();
    for (idx, &ch) in iter.by_ref().enumerate() {
        match ch {
            b'\r' | b'\n' | b' ' | b'\t' => continue,
            b'c' | b'C' => {
                if idx + "chunked".len() > val.len() {
                    return false;
                }
                break;
            }
            _ => return false,
        }
    }
    for (idx, ch) in iter.by_ref().take(6).enumerate() {
        if b"hunked"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    for &ch in iter {
        if !matches!(ch, b'\r' | b'\n' | b' ' | b'\t') {
            return false;
        }
    }
    return true;
}

// header value is byte sequence
// we need case insensitive comparison and strip out of the whitespace
pub fn is_continue(val: &[u8]) -> bool {
    if val.len() < "100-continue".len() {
        return false;
    }
    let mut iter = val.iter();
    for (idx, &ch) in iter.by_ref().enumerate() {
        match ch {
            b'\r' | b'\n' | b' ' | b'\t' => continue,
            b'1' => {
                if idx + "100-continue".len() > val.len() {
                    return false;
                }
                break;
            }
            _ => return false,
        }
    }
    for (idx, ch) in iter.by_ref().take(11).enumerate() {
        if b"00-continue"[idx] != ch.to_ascii_lowercase() {
            return false;
        }
    }
    for &ch in iter {
        if !matches!(ch, b'\r' | b'\n' | b' ' | b'\t') {
            return false;
        }
    }
    return true;
}

#[cfg(test)]
mod test {
    use super::{is_content_length, is_transfer_encoding, is_connection};
    use super::{is_expect};
    use super::{is_chunked, is_close, is_continue};

    #[test]
    fn test_content_len() {
        assert!(is_content_length("Content-Length"));
        assert!(is_content_length("content-length"));
        assert!(is_content_length("CONTENT-length"));
        assert!(is_content_length("CONTENT-LENGTH"));
    }

    #[test]
    fn test_transfer_encoding() {
        assert!(is_transfer_encoding("Transfer-Encoding"));
        assert!(is_transfer_encoding("transfer-ENCODING"));
        assert!(is_transfer_encoding("TRANSFER-Encoding"));
        assert!(is_transfer_encoding("TRANSFER-ENCODING"));
    }

    #[test]
    fn test_connection() {
        assert!(is_connection("Connection"));
        assert!(is_connection("CONNECTION"));
        assert!(is_connection("ConneCTION"));
        assert!(is_connection("connection"));
    }

    #[test]
    fn test_expect() {
        assert!(is_expect("Expect"));
        assert!(is_expect("EXPECT"));
        assert!(is_expect("expect"));
        assert!(is_expect("ExpECT"));
    }

    #[test]
    fn test_chunked() {
        assert!(is_chunked(b"chunked"));
        assert!(is_chunked(b"Chunked"));
        assert!(is_chunked(b"chuNKED"));
        assert!(is_chunked(b"CHUNKED"));
        assert!(is_chunked(b"   CHUNKED"));
        assert!(is_chunked(b"   CHUNKED  "));
        assert!(is_chunked(b"chunked  "));
        assert!(is_chunked(b"   CHUNKED"));
        assert!(!is_chunked(b"   CHUNKED 1 "));
    }

    #[test]
    fn test_close() {
        assert!(is_close(b"close"));
        assert!(is_close(b"Close"));
        assert!(is_close(b"clOSE"));
        assert!(is_close(b"CLOSE"));
        assert!(is_close(b" CLOSE"));
        assert!(is_close(b"   close   "));
        assert!(!is_close(b"Close  1 "));
        assert!(!is_close(b" xclose   "));
    }

    #[test]
    fn test_continue() {
        assert!(is_continue(b"100-continue"));
        assert!(is_continue(b"100-Continue"));
        assert!(is_continue(b"100-conTINUE"));
        assert!(is_continue(b"100-CONTINUE"));
        assert!(is_continue(b"  100-CONTINUE"));
        assert!(is_continue(b"   100-continue   "));
        assert!(!is_continue(b"100-continue y  "));
        assert!(!is_continue(b"100-coztinue   "));
    }
}

<|endoftext|>