<commit_before>//! Items in the scene heirarchy.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::sync::mpsc;

use mint;

use audio;
use camera::Camera;
use hub::{Hub, Message, Operation, SubLight, SubNode};
use light;
use mesh::Mesh;
use node::NodePointer;
use scene::SyncGuard;
use skeleton::{Bone, Skeleton};
use sprite::Sprite;
use text::Text;

//Note: no local state should be here, only remote links
/// `Base` represents a concrete entity that can be added to the scene.
///
/// One cannot construct `Base` directly. Wrapper types such as [`Camera`],
/// [`Mesh`], and [`Group`] are provided instead.
///
/// Any type that implements [`Object`] may be converted to its concrete
/// `Base` type with the method [`Object::upcast`]. This is useful for
/// storing generic objects in containers.
///
/// [`Camera`]: ../camera/struct.Camera.html
/// [`Mesh`]: ../mesh/struct.Mesh.html
/// [`Group`]: ../object/struct.Group.html
/// [`Object`]: ../object/trait.Object.html
/// [`Object::upcast`]: ../object/trait.Object.html#method.upcast
#[derive(Clone)]
pub struct Base {
    pub(crate) node: NodePointer,
    pub(crate) tx: mpsc::Sender<Message>,
}

/// Marks data structures that are able to added to the scene graph.
pub trait Object: AsRef<Base> {
    /// The internal data for the object.
    ///
    /// Three-rs objects normally expose a write-only interface, making it possible to change
    /// an object's internal values but not possible to read those values.
    /// [`SyncGuard::resolve_data`] allows for that data to be read in a controlled way, with.
    /// the data for the specific object type determined by the `Data` trait member.
    ///
    /// Each object type has its own internal data, and not all object types can provide access
    /// to meaningful data. Types that cannot provide user-facing data will specify `()`
    /// for `Data`.
    type Data;

    /// Retrieves the internal data for the object.
    ///
    /// Prefer to use [`SyncGuard::resolve_data`] over calling this directly.
    fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data;

    /// Converts into the base type.
    fn upcast(&self) -> Base {
        self.as_ref().clone()
    }

    /// Invisible objects are not rendered by cameras.
    fn set_visible(
        &self,
        visible: bool,
    ) {
        self.as_ref().send(Operation::SetVisible(visible));
    }

    /// Sets the name of the object.
    fn set_name<S: Into<String>>(
        &self,
        name: S,
    ) {
        self.as_ref().send(Operation::SetName(name.into()));
    }

    /// Set both position, orientation and scale.
    fn set_transform<P, Q>(
        &self,
        pos: P,
        rot: Q,
        scale: f32,
    ) where
        Self: Sized,
        P: Into<mint::Point3<f32>>,
        Q: Into<mint::Quaternion<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(Some(pos.into()), Some(rot.into()), Some(scale)));
    }

    /// Set position.
    fn set_position<P>(
        &self,
        pos: P,
    ) where
        Self: Sized,
        P: Into<mint::Point3<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(Some(pos.into()), None, None));
    }

    /// Set orientation.
    fn set_orientation<Q>(
        &self,
        rot: Q,
    ) where
        Self: Sized,
        Q: Into<mint::Quaternion<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(None, Some(rot.into()), None));
    }

    /// Set scale.
    fn set_scale(
        &self,
        scale: f32,
    ) {
        self.as_ref().send(Operation::SetTransform(None, None, Some(scale)));
    }

    /// Set weights.
    //Note: needed for animations
    fn set_weights(
        &self,
        weights: Vec<f32>,
    ) {
        self.as_ref().send(Operation::SetWeights(weights));
    }

    /// Rotates object in the specific direction of `target`.
    fn look_at<E, T>(
        &self,
        eye: E,
        target: T,
        up: Option<mint::Vector3<f32>>,
    ) where
        Self: Sized,
        E: Into<mint::Point3<f32>>,
        T: Into<mint::Point3<f32>>,
    {
        use cgmath::{InnerSpace, Point3, Quaternion, Rotation, Vector3};
        let p: [mint::Point3<f32>; 2] = [eye.into(), target.into()];
        let dir = (Point3::from(p[0]) - Point3::from(p[1])).normalize();
        let z = Vector3::unit_z();
        let up = match up {
            Some(v) => Vector3::from(v).normalize(),
            None if dir.dot(z).abs() < 0.99 => z,
            None => Vector3::unit_y(),
        };
        let q = Quaternion::look_at(dir, up).invert();
        self.set_transform(p[0], q, 1.0);
    }
}

impl PartialEq for Base {
    fn eq(
        &self,
        other: &Base,
    ) -> bool {
        self.node == other.node
    }
}

impl Eq for Base {}

impl Hash for Base {
    fn hash<H: Hasher>(
        &self,
        state: &mut H,
    ) {
        self.node.hash(state);
    }
}

impl fmt::Debug for Base {
    fn fmt(
        &self,
        f: &mut fmt::Formatter,
    ) -> fmt::Result {
        self.node.fmt(f)
    }
}

impl Base {
    pub(crate) fn send(
        &self,
        operation: Operation,
    ) {
        let _ = self.tx.send((self.node.downgrade(), operation));
    }
}

// Required for `Base` to implement `trait Object`.
impl AsRef<Base> for Base {
    fn as_ref(&self) -> &Base {
        self
    }
}

impl Object for Base {
    type Data = ObjectType;

    fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data {
        let node = &sync_guard.hub[self];
        match &node.sub_node {
            // TODO: Handle resolving cameras better (`Empty` is only used for cameras).
            SubNode::Camera(..) => ObjectType::Camera(Camera {
                object: self.clone(),
            }),

            SubNode::Group { .. } => ObjectType::Group(Group {
                object: self.clone(),
            }),

            SubNode::Audio(..) => ObjectType::AudioSource(audio::Source {
                object: self.clone(),
            }),

            SubNode::UiText(..) => ObjectType::Text(Text {
                object: self.clone(),
            }),

            // TODO: Differentiate between `Mesh` and `DynamicMesh`.
            SubNode::Visual(..) => ObjectType::Mesh(Mesh {
                object: self.clone(),
            }),

            SubNode::Bone { .. } => ObjectType::Bone(Bone {
                object: self.clone(),
            }),

            SubNode::Skeleton(..) => ObjectType::Skeleton(Skeleton {
                object: self.clone(),
            }),

            SubNode::Light(light) => match light.sub_light {
                SubLight::Ambient => ObjectType::AmbientLight(light::Ambient {
                    object: self.clone(),
                }),

                SubLight::Directional => ObjectType::DirectionalLight(light::Directional {
                    object: self.clone(),
                }),

                SubLight::Point => ObjectType::PointLight(light::Point {
                    object: self.clone(),
                }),

                SubLight::Hemisphere { .. } => ObjectType::HemisphereLight(light::Hemisphere {
                    object: self.clone(),
                }),
            },
        }
    }
}

/// The possible concrete types that a [`Base`] can be resolved to.
///
/// When using [`SyncGuard::resolve_data`] with a [`Base`], it will resolve to the concrete
/// object type that the base represents.
#[derive(Debug, Clone)]
pub enum ObjectType {
    /// An audio source.
    AudioSource(audio::Source),

    /// An ambient light.
    AmbientLight(light::Ambient),

    /// A directional light.
    DirectionalLight(light::Directional),

    /// A hemisphere light.
    HemisphereLight(light::Hemisphere),

    /// A point light.
    PointLight(light::Point),

    /// A mesh.
    Mesh(Mesh),

    /// A group.
    Group(Group),

    /// A skeleton.
    Skeleton(Skeleton),

    /// A bone in a skeleton.
    Bone(Bone),

    /// A 2D sprite.
    Sprite(Sprite),

    /// A UI text object.
    Text(Text),

    /// A camera.
    Camera(Camera),
}

/// Marks an object type that can be downcast from a [`Base`].
pub trait DowncastObject: Sized {
    /// Attempts to extract the concrete type of the object from an [`ObjectType`].
    ///
    /// Prefer to use [`SyncGuard::downcast`] over calling this directly.
    fn downcast(object: ObjectType) -> Option<Self>;
}

/// Groups are used to combine several other objects or groups to work with them
/// as with a single entity.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Group {
    object: Base,
}

impl AsRef<Base> for Group {
    fn as_ref(&self) -> &Base { &self.object }
}

impl Object for Group {
    type Data = Vec<Base>;

    fn resolve_data(&self, sync_guard: &SyncGuard) -> Vec<Base> {
        let mut children = Vec::new();
        let node = &sync_guard.hub[self];

        let mut child = match node.sub_node {
            SubNode::Group { ref first_child } => first_child.clone(),
            _ => panic!("`Group` had a bad sub node type: {:?}", node.sub_node),
        };

        while let Some(child_pointer) = child {
            child = sync_guard.hub.nodes[&child_pointer].next_sibling.clone();

            children.push(Base {
                node: child_pointer,
                tx: sync_guard.hub.message_tx.clone(),
            });
        }

        children
    }
}

derive_DowncastObject!(Group => ObjectType::Group);

impl Group {
    pub(crate) fn new(hub: &mut Hub) -> Self {
        let sub = SubNode::Group { first_child: None };
        Group {
            object: hub.spawn(sub),
        }
    }

    /// Add new [`Object`](trait.Object.html) to the group.
    pub fn add<T: Object>(
        &self,
        child: &T,
    ) {
        let node = child.as_ref().node.clone();
        self.as_ref().send(Operation::AddChild(node));
    }

    /// Removes a child [`Object`](trait.Object.html) from the group.
    pub fn remove<T: Object>(
        &self,
        child: &T,
    ) {
        let node = child.as_ref().node.clone();
        self.as_ref().send(Operation::RemoveChild(node));
    }
}
<commit_msg>Document new items in object.rs<commit_after>//! Items in the scene heirarchy.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::sync::mpsc;

use mint;

use audio;
use camera::Camera;
use hub::{Hub, Message, Operation, SubLight, SubNode};
use light;
use mesh::Mesh;
use node::NodePointer;
use scene::SyncGuard;
use skeleton::{Bone, Skeleton};
use sprite::Sprite;
use text::Text;

//Note: no local state should be here, only remote links
/// `Base` represents a concrete entity that can be added to the scene.
///
/// One cannot construct `Base` directly. Wrapper types such as [`Camera`],
/// [`Mesh`], and [`Group`] are provided instead.
///
/// Any type that implements [`Object`] may be converted to its concrete
/// `Base` type with the method [`Object::upcast`]. This is useful for
/// storing generic objects in containers.
///
/// [`Camera`]: ../camera/struct.Camera.html
/// [`Mesh`]: ../mesh/struct.Mesh.html
/// [`Group`]: ../object/struct.Group.html
/// [`Object`]: ../object/trait.Object.html
/// [`Object::upcast`]: ../object/trait.Object.html#method.upcast
#[derive(Clone)]
pub struct Base {
    pub(crate) node: NodePointer,
    pub(crate) tx: mpsc::Sender<Message>,
}

/// Marks data structures that are able to added to the scene graph.
pub trait Object: AsRef<Base> {
    /// The internal data for the object.
    ///
    /// Three-rs objects normally expose a write-only interface, making it possible to change
    /// an object's internal values but not possible to read those values.
    /// [`SyncGuard::resolve_data`] allows for that data to be read in a controlled way, with.
    /// the data for the specific object type determined by the `Data` trait member.
    ///
    /// Each object type has its own internal data, and not all object types can provide access
    /// to meaningful data. Types that cannot provide user-facing data will specify `()`
    /// for `Data`.
    ///
    /// [`SyncGuard::resolve_data`]: ./scene/struct.SyncGuard.html#method.resolve_data
    type Data;

    /// Retrieves the internal data for the object.
    ///
    /// Prefer to use [`SyncGuard::resolve_data`] over calling this directly.
    ///
    /// [`SyncGuard::resolve_data`]: ./scene/struct.SyncGuard.html#method.resolve_data
    fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data;

    /// Converts into the base type.
    fn upcast(&self) -> Base {
        self.as_ref().clone()
    }

    /// Invisible objects are not rendered by cameras.
    fn set_visible(
        &self,
        visible: bool,
    ) {
        self.as_ref().send(Operation::SetVisible(visible));
    }

    /// Sets the name of the object.
    fn set_name<S: Into<String>>(
        &self,
        name: S,
    ) {
        self.as_ref().send(Operation::SetName(name.into()));
    }

    /// Set both position, orientation and scale.
    fn set_transform<P, Q>(
        &self,
        pos: P,
        rot: Q,
        scale: f32,
    ) where
        Self: Sized,
        P: Into<mint::Point3<f32>>,
        Q: Into<mint::Quaternion<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(Some(pos.into()), Some(rot.into()), Some(scale)));
    }

    /// Set position.
    fn set_position<P>(
        &self,
        pos: P,
    ) where
        Self: Sized,
        P: Into<mint::Point3<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(Some(pos.into()), None, None));
    }

    /// Set orientation.
    fn set_orientation<Q>(
        &self,
        rot: Q,
    ) where
        Self: Sized,
        Q: Into<mint::Quaternion<f32>>,
    {
        self.as_ref().send(Operation::SetTransform(None, Some(rot.into()), None));
    }

    /// Set scale.
    fn set_scale(
        &self,
        scale: f32,
    ) {
        self.as_ref().send(Operation::SetTransform(None, None, Some(scale)));
    }

    /// Set weights.
    //Note: needed for animations
    fn set_weights(
        &self,
        weights: Vec<f32>,
    ) {
        self.as_ref().send(Operation::SetWeights(weights));
    }

    /// Rotates object in the specific direction of `target`.
    fn look_at<E, T>(
        &self,
        eye: E,
        target: T,
        up: Option<mint::Vector3<f32>>,
    ) where
        Self: Sized,
        E: Into<mint::Point3<f32>>,
        T: Into<mint::Point3<f32>>,
    {
        use cgmath::{InnerSpace, Point3, Quaternion, Rotation, Vector3};
        let p: [mint::Point3<f32>; 2] = [eye.into(), target.into()];
        let dir = (Point3::from(p[0]) - Point3::from(p[1])).normalize();
        let z = Vector3::unit_z();
        let up = match up {
            Some(v) => Vector3::from(v).normalize(),
            None if dir.dot(z).abs() < 0.99 => z,
            None => Vector3::unit_y(),
        };
        let q = Quaternion::look_at(dir, up).invert();
        self.set_transform(p[0], q, 1.0);
    }
}

impl PartialEq for Base {
    fn eq(
        &self,
        other: &Base,
    ) -> bool {
        self.node == other.node
    }
}

impl Eq for Base {}

impl Hash for Base {
    fn hash<H: Hasher>(
        &self,
        state: &mut H,
    ) {
        self.node.hash(state);
    }
}

impl fmt::Debug for Base {
    fn fmt(
        &self,
        f: &mut fmt::Formatter,
    ) -> fmt::Result {
        self.node.fmt(f)
    }
}

impl Base {
    pub(crate) fn send(
        &self,
        operation: Operation,
    ) {
        let _ = self.tx.send((self.node.downgrade(), operation));
    }
}

// Required for `Base` to implement `trait Object`.
impl AsRef<Base> for Base {
    fn as_ref(&self) -> &Base {
        self
    }
}

impl Object for Base {
    type Data = ObjectType;

    fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data {
        let node = &sync_guard.hub[self];
        match &node.sub_node {
            // TODO: Handle resolving cameras better (`Empty` is only used for cameras).
            SubNode::Camera(..) => ObjectType::Camera(Camera {
                object: self.clone(),
            }),

            SubNode::Group { .. } => ObjectType::Group(Group {
                object: self.clone(),
            }),

            SubNode::Audio(..) => ObjectType::AudioSource(audio::Source {
                object: self.clone(),
            }),

            SubNode::UiText(..) => ObjectType::Text(Text {
                object: self.clone(),
            }),

            // TODO: Differentiate between `Mesh` and `DynamicMesh`.
            SubNode::Visual(..) => ObjectType::Mesh(Mesh {
                object: self.clone(),
            }),

            SubNode::Bone { .. } => ObjectType::Bone(Bone {
                object: self.clone(),
            }),

            SubNode::Skeleton(..) => ObjectType::Skeleton(Skeleton {
                object: self.clone(),
            }),

            SubNode::Light(light) => match light.sub_light {
                SubLight::Ambient => ObjectType::AmbientLight(light::Ambient {
                    object: self.clone(),
                }),

                SubLight::Directional => ObjectType::DirectionalLight(light::Directional {
                    object: self.clone(),
                }),

                SubLight::Point => ObjectType::PointLight(light::Point {
                    object: self.clone(),
                }),

                SubLight::Hemisphere { .. } => ObjectType::HemisphereLight(light::Hemisphere {
                    object: self.clone(),
                }),
            },
        }
    }
}

/// The possible concrete types that a [`Base`] can be resolved to.
///
/// When using [`SyncGuard::resolve_data`] with a [`Base`], it returns an `ObjectType`
/// containing the concrete object for the [`Base`].
///
/// [`Base`]: ./struct.Base.html
/// [`SyncGuard::resolve_data`]: ../scene/struct.SyncGuard.html#method.resolve_data
#[derive(Debug, Clone)]
pub enum ObjectType {
    /// An audio source.
    AudioSource(audio::Source),

    /// An ambient light.
    AmbientLight(light::Ambient),

    /// A directional light.
    DirectionalLight(light::Directional),

    /// A hemisphere light.
    HemisphereLight(light::Hemisphere),

    /// A point light.
    PointLight(light::Point),

    /// A mesh.
    Mesh(Mesh),

    /// A group.
    Group(Group),

    /// A skeleton.
    Skeleton(Skeleton),

    /// A bone in a skeleton.
    Bone(Bone),

    /// A 2D sprite.
    Sprite(Sprite),

    /// A UI text object.
    Text(Text),

    /// A camera.
    Camera(Camera),
}

/// Marks an object type that can be downcast from a [`Base`].
///
/// See [`SyncGuard::downcast`] for information on how this trait is used.
///
/// [`Base`]: ./struct.Base.html
/// [`SyncGuard::downcast`]: ../scene/struct.SyncGuard.html#method.downcast
pub trait DowncastObject: Sized {
    /// Attempts to extract the concrete type of the object from an [`ObjectType`].
    ///
    /// Prefer to use [`SyncGuard::downcast`] over calling this directly.
    ///
    /// [`ObjectType`]: ./enum.ObjectType.html
    /// [`SyncGuard::downcast`]: ../scene/struct.SyncGuard.html#method.downcast
    fn downcast(object: ObjectType) -> Option<Self>;
}

/// Groups are used to combine several other objects or groups to work with them
/// as with a single entity.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Group {
    object: Base,
}

impl AsRef<Base> for Group {
    fn as_ref(&self) -> &Base { &self.object }
}

impl Object for Group {
    type Data = Vec<Base>;

    fn resolve_data(&self, sync_guard: &SyncGuard) -> Vec<Base> {
        let mut children = Vec::new();
        let node = &sync_guard.hub[self];

        let mut child = match node.sub_node {
            SubNode::Group { ref first_child } => first_child.clone(),
            _ => panic!("`Group` had a bad sub node type: {:?}", node.sub_node),
        };

        while let Some(child_pointer) = child {
            child = sync_guard.hub.nodes[&child_pointer].next_sibling.clone();

            children.push(Base {
                node: child_pointer,
                tx: sync_guard.hub.message_tx.clone(),
            });
        }

        children
    }
}

derive_DowncastObject!(Group => ObjectType::Group);

impl Group {
    pub(crate) fn new(hub: &mut Hub) -> Self {
        let sub = SubNode::Group { first_child: None };
        Group {
            object: hub.spawn(sub),
        }
    }

    /// Add new [`Object`](trait.Object.html) to the group.
    pub fn add<T: Object>(
        &self,
        child: &T,
    ) {
        let node = child.as_ref().node.clone();
        self.as_ref().send(Operation::AddChild(node));
    }

    /// Removes a child [`Object`](trait.Object.html) from the group.
    pub fn remove<T: Object>(
        &self,
        child: &T,
    ) {
        let node = child.as_ref().node.clone();
        self.as_ref().send(Operation::RemoveChild(node));
    }
}
<|endoftext|>


<commit_before>use serde_json::from_reader;
use std::path::Path;
use std::fs::File;

use linear::{M44, Quat, V3};
use model::ObjModel;
use resource::{Load, LoadError, LoadResult, Res, ResCache};
use scale::Scale;
use transform::{Transform, Transformable};

type ObjObject = Object<ObjModel>;

#[derive(Clone)]
pub struct Object<M> {
  pub model: Res<M>,
  pub position: V3<f32>,
  pub orientation: Quat<f32>,
  pub scale: Scale
}

impl<M> Object<M> {
  pub fn new(model: Res<M>, position: V3<f32>, orientation: Quat<f32>, scale: Scale) -> Self {
    Object {
      model: model,
      position: position,
      orientation: orientation,
      scale: scale
    }
  }
}

impl<Vertex> Transformable for Object<Vertex> {
  fn transform(&self) -> Transform {
    (M44::from_translation(-self.position) * M44::from(self.scale) * M44::from(self.orientation)).into()
  }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ObjectManifest {
  model: String,
  #[serde(default = "def_position")]
  position: [f32; 3],
  #[serde(default = "def_orientation")]
  orientation: [f32; 4],
  #[serde(default = "def_scale")]
  scale: [f32; 3]
}

impl Load for ObjObject {
  type Args = ();

  const TY_STR: &'static str = "objects";

  fn load<P>(path: P, cache: &mut ResCache, _: Self::Args) -> Result<LoadResult<Self>, LoadError> where P: AsRef<Path> {
    let path = path.as_ref();

    // read the manifest
    let manifest: ObjectManifest = {
      let file = File::open(path).map_err(|_| LoadError::FileNotFound(path.to_path_buf()))?;
      from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))?
    };

    let model = cache.get(&manifest.model, ()).ok_or(LoadError::ConversionFailed(format!("unable to find model {} for object at {:?}", manifest.model, path)))?;

    Ok((Object {
      model: model,
      position: manifest.position.into(),
      orientation: manifest.orientation.into(),
      scale: manifest.scale.into()
    }).into())
  }
}

fn def_position() -> [f32; 3] { [0., 0., 0.] }
fn def_orientation() -> [f32; 4] { [1., 0., 0., 0.] }
fn def_scale() -> [f32; 3] { [1., 1., 1.] }
<commit_msg>ObjObject visible.<commit_after>use serde_json::from_reader;
use std::path::Path;
use std::fs::File;

use linear::{M44, Quat, V3};
use model::ObjModel;
use resource::{Load, LoadError, LoadResult, Res, ResCache};
use scale::Scale;
use transform::{Transform, Transformable};

pub type ObjObject = Object<ObjModel>;

#[derive(Clone)]
pub struct Object<M> {
  pub model: Res<M>,
  pub position: V3<f32>,
  pub orientation: Quat<f32>,
  pub scale: Scale
}

impl<M> Object<M> {
  pub fn new(model: Res<M>, position: V3<f32>, orientation: Quat<f32>, scale: Scale) -> Self {
    Object {
      model: model,
      position: position,
      orientation: orientation,
      scale: scale
    }
  }
}

impl<Vertex> Transformable for Object<Vertex> {
  fn transform(&self) -> Transform {
    (M44::from_translation(-self.position) * M44::from(self.scale) * M44::from(self.orientation)).into()
  }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ObjectManifest {
  model: String,
  #[serde(default = "def_position")]
  position: [f32; 3],
  #[serde(default = "def_orientation")]
  orientation: [f32; 4],
  #[serde(default = "def_scale")]
  scale: [f32; 3]
}

impl Load for ObjObject {
  type Args = ();

  const TY_STR: &'static str = "objects";

  fn load<P>(path: P, cache: &mut ResCache, _: Self::Args) -> Result<LoadResult<Self>, LoadError> where P: AsRef<Path> {
    let path = path.as_ref();

    // read the manifest
    let manifest: ObjectManifest = {
      let file = File::open(path).map_err(|_| LoadError::FileNotFound(path.to_path_buf()))?;
      from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))?
    };

    let model = cache.get(&manifest.model, ()).ok_or(LoadError::ConversionFailed(format!("unable to find model {} for object at {:?}", manifest.model, path)))?;

    Ok((Object {
      model: model,
      position: manifest.position.into(),
      orientation: manifest.orientation.into(),
      scale: manifest.scale.into()
    }).into())
  }
}

fn def_position() -> [f32; 3] { [0., 0., 0.] }
fn def_orientation() -> [f32; 4] { [1., 0., 0., 0.] }
fn def_scale() -> [f32; 3] { [1., 1., 1.] }
<|endoftext|>


<commit_before>fn kmain() {
    let vid_buffer: *char = 0xb8000 as (*char);
    vid_buff[0] = 'R';
    vid_buffer[1] = 0x07;
}
<commit_msg>Update kernel.rs<commit_after>fn kmain() {
    let vid_buffer: *mut char = 0xb8000 as (*mut char);
    unsafe {
        vid_buff[0] = 'R';
        //vid_buffer[1] = 0x07;
    }
}
<|endoftext|>


<commit_before>use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{def, Expr, ExprKind, PrimTy, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::sym;

use crate::utils::is_type_diagnostic_item;
use crate::utils::span_lint_and_sugg;
use crate::utils::sugg::Sugg;

declare_clippy_lint! {
    /// **What it does:**
    /// Checks for function invocations of the form `primitive::from_str_radix(s, 10)`
    ///
    /// **Why is this bad?**
    /// This specific common use case can be rewritten as `s.parse::<primitive>()`
    /// (and in most cases, the turbofish can be removed), which reduces code length
    /// and complexity.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// let input: &str = get_input();
    /// let num = u16::from_str_radix(input, 10)?;
    /// ```
    /// Use instead:
    /// ```ignore
    /// let input: &str = get_input();
    /// let num: u16 = input.parse()?;
    /// ```
    pub FROM_STR_RADIX_10,
    style,
    "from_str_radix with radix 10"
}

declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);

impl LateLintPass<'tcx> for FromStrRadix10 {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
        if_chain! {
            if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
            if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind;

            // check if the first part of the path is some integer primitive
            if let TyKind::Path(ty_qpath) = &ty.kind;
            let ty_res = cx.qpath_res(ty_qpath, ty.hir_id);
            if let def::Res::PrimTy(prim_ty) = ty_res;
            if matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_));

            // check if the second part of the path indeed calls the associated
            // function `from_str_radix`
            if pathseg.ident.name.as_str() == "from_str_radix";

            // check if the second argument is a primitive `10`
            if arguments.len() == 2;
            if let ExprKind::Lit(lit) = &arguments[1].kind;
            if let rustc_ast::ast::LitKind::Int(10, _) = lit.node;

            then {
                let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind {
                    let ty = cx.typeck_results().expr_ty(expr);
                    if is_ty_stringish(cx, ty) {
                        expr
                    } else {
                        &arguments[0]
                    }
                } else {
                    &arguments[0]
                };

                let sugg = Sugg::hir_with_applicability(
                    cx,
                    expr,
                    "<string>",
                    &mut Applicability::MachineApplicable
                ).maybe_par();

                span_lint_and_sugg(
                    cx,
                    FROM_STR_RADIX_10,
                    exp.span,
                    "this call to `from_str_radix` can be replaced with a call to `str::parse`",
                    "try",
                    format!("{}.parse::<{}>()", sugg, prim_ty.name_str()),
                    Applicability::MaybeIncorrect
                );
            }
        }
    }
}

/// Checks if a Ty is `String` or `&str`
fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
    is_type_diagnostic_item(cx, ty, sym::string_type) || is_type_diagnostic_item(cx, ty, sym::str)
}
<commit_msg>Fixed the known problems section<commit_after>use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{def, Expr, ExprKind, PrimTy, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::sym;

use crate::utils::is_type_diagnostic_item;
use crate::utils::span_lint_and_sugg;
use crate::utils::sugg::Sugg;

declare_clippy_lint! {
    /// **What it does:**
    /// Checks for function invocations of the form `primitive::from_str_radix(s, 10)`
    ///
    /// **Why is this bad?**
    /// This specific common use case can be rewritten as `s.parse::<primitive>()`
    /// (and in most cases, the turbofish can be removed), which reduces code length
    /// and complexity.
    ///
    /// **Known problems:**
    /// This lint may suggest using (&<expression>).parse() instead of <expression>.parse() directly
    /// in some cases, which is correct but adds unnecessary complexity to the code.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// let input: &str = get_input();
    /// let num = u16::from_str_radix(input, 10)?;
    /// ```
    /// Use instead:
    /// ```ignore
    /// let input: &str = get_input();
    /// let num: u16 = input.parse()?;
    /// ```
    pub FROM_STR_RADIX_10,
    style,
    "from_str_radix with radix 10"
}

declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);

impl LateLintPass<'tcx> for FromStrRadix10 {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
        if_chain! {
            if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
            if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind;

            // check if the first part of the path is some integer primitive
            if let TyKind::Path(ty_qpath) = &ty.kind;
            let ty_res = cx.qpath_res(ty_qpath, ty.hir_id);
            if let def::Res::PrimTy(prim_ty) = ty_res;
            if matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_));

            // check if the second part of the path indeed calls the associated
            // function `from_str_radix`
            if pathseg.ident.name.as_str() == "from_str_radix";

            // check if the second argument is a primitive `10`
            if arguments.len() == 2;
            if let ExprKind::Lit(lit) = &arguments[1].kind;
            if let rustc_ast::ast::LitKind::Int(10, _) = lit.node;

            then {
                let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind {
                    let ty = cx.typeck_results().expr_ty(expr);
                    if is_ty_stringish(cx, ty) {
                        expr
                    } else {
                        &arguments[0]
                    }
                } else {
                    &arguments[0]
                };

                let sugg = Sugg::hir_with_applicability(
                    cx,
                    expr,
                    "<string>",
                    &mut Applicability::MachineApplicable
                ).maybe_par();

                span_lint_and_sugg(
                    cx,
                    FROM_STR_RADIX_10,
                    exp.span,
                    "this call to `from_str_radix` can be replaced with a call to `str::parse`",
                    "try",
                    format!("{}.parse::<{}>()", sugg, prim_ty.name_str()),
                    Applicability::MaybeIncorrect
                );
            }
        }
    }
}

/// Checks if a Ty is `String` or `&str`
fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
    is_type_diagnostic_item(cx, ty, sym::string_type) || is_type_diagnostic_item(cx, ty, sym::str)
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::default::Default;
use std::error;
use std::fmt;
use std::io;

use byteorder::{BigEndian, ByteOrder, LittleEndian};
use encoding::label::encoding_from_whatwg_label;
use encoding::types::DecoderTrap::Strict;
use encoding::types::EncodingRef;

use crate::plurals::{Ast, Resolver};
use crate::{Catalog, Message};
use crate::metadata::parse_metadata;

#[allow(non_upper_case_globals)]
static utf8_encoding: EncodingRef = &encoding::codec::utf_8::UTF8Encoding;

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
    /// Incorrect syntax encountered while parsing the meta information
    MalformedMetadata,
    /// Meta information string was not the first string in the catalog
    MisplacedMetadata,
    /// Invalid Plural-Forms metadata
    PluralParsing,
    /// An unknown encoding was specified in the metadata
    UnknownEncoding,
}
use crate::Error::*;

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
            MalformedMetadata => "metadata syntax error",
            MisplacedMetadata => "misplaced metadata",
            UnknownEncoding => "unknown encoding specified",
            PluralParsing => "invalid plural expression",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(_: Cow<'static, str>) -> Error {
        DecodingError
    }
}

/// ParseOptions allows setting options for parsing MO catalogs.
///
/// # Examples
/// ```ignore
/// use std::fs::File;
/// use encoding::all::ISO_8859_1;
///
/// let file = File::open("french.mo").unwrap();
/// let catalog = ParseOptions::new().force_encoding(ISO_8859_1).parse(file).unwrap();
/// ```
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
    force_plural: Option<fn(u64) -> usize>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        Default::default()
    }

    /// Tries to parse the catalog from the given reader using the specified options.
    pub fn parse<R: io::Read>(self, reader: R) -> Result<Catalog, Error> {
        parse_catalog(reader, self)
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(mut self, encoding: EncodingRef) -> Self {
        self.force_encoding = Some(encoding);
        self
    }

    /// Forces a use of the given plural formula
    /// for deciding the proper plural form for a message.
    /// If this option is not enabled,
    /// the parser uses the default formula
    /// (`n != 1`).
    pub fn force_plural(mut self, plural: fn(u64) -> usize) -> Self {
        self.force_plural = Some(plural);
        self
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

pub fn parse_catalog<'a, R: io::Read>(mut file: R, opts: ParseOptions) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = file.read_to_end(&mut contents)?;
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = get_read_u32_fn(&contents[0..4]).ok_or(BadMagic)?;

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    if let Some(f) = opts.force_plural {
        catalog.resolver = Resolver::Function(f);
    }
    let mut encoding = opts.force_encoding.unwrap_or(utf8_encoding);

    for i in 0..num_strings {
        // Parse the original string
        if n < off_otable + 8 {
            return Err(Eof);
        }
        let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
        let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
        // +1 compensates for the ending NUL byte which is not included in length
        if n < off + len + 1 {
            return Err(Eof);
        }
        let mut original = &contents[off..off + len + 1];
        // check for context
        let context = match original.iter().position(|x| *x == 4) {
            Some(idx) => {
                let ctx = &original[..idx];
                original = &original[idx + 1..];
                Some(encoding.decode(ctx, Strict)?)
            }
            None => None,
        };
        // extract msg_id singular, ignoring the plural
        let id = match original
            .iter()
            .position(|x| *x == 0)
            .map(|i| &original[..i])
        {
            Some(b) => encoding.decode(b, Strict)?,
            None => return Err(Eof),
        };
        if id == "" && i != 0 {
            return Err(MisplacedMetadata);
        }

        // Parse the translation strings
        if n < off_ttable + 8 {
            return Err(Eof);
        }
        let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
        let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
        // +1 compensates for the ending NUL byte which is not included in length
        if n < off + len + 1 {
            return Err(Eof);
        }
        let translated = contents[off..off + len]
            .split(|x| *x == 0)
            .map(|b| encoding.decode(b, Strict))
            .collect::<Result<Vec<_>, _>>()?;
        if id == "" {
            let map = parse_metadata(&*translated[0])?;
            if let (Some(c), None) = (map.charset(), opts.force_encoding) {
                encoding = encoding_from_whatwg_label(c).ok_or(UnknownEncoding)?;
            }
            if opts.force_plural.is_none() {
                if let Some(p) = map.plural_forms().1 {
                    catalog.resolver = Ast::parse(p).map(Resolver::Expr)?;
                }
            }
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    Ok(catalog)
}

/// The default plural resolver.
///
/// It will be used if not `Plural-Forms` header is found in the .mo file, and if
/// `ParseOptions::force_plural` was not called.
///
/// It is valid for English and similar languages: plural will be used for any quantity
/// different of 1.
pub fn default_resolver(n: u64) -> usize {
    if n == 1 {
        0
    } else {
        1
    }
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(
            catalog.strings["this is context\x04Text"],
            Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"])
        );
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(
            catalog.strings["Image"],
            Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"])
        );
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader, ParseOptions::new()).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<commit_msg>Fix outdated documentation<commit_after>use std::borrow::Cow;
use std::default::Default;
use std::error;
use std::fmt;
use std::io;

use byteorder::{BigEndian, ByteOrder, LittleEndian};
use encoding::label::encoding_from_whatwg_label;
use encoding::types::DecoderTrap::Strict;
use encoding::types::EncodingRef;

use crate::plurals::{Ast, Resolver};
use crate::{Catalog, Message};
use crate::metadata::parse_metadata;

#[allow(non_upper_case_globals)]
static utf8_encoding: EncodingRef = &encoding::codec::utf_8::UTF8Encoding;

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
    /// Incorrect syntax encountered while parsing the meta information
    MalformedMetadata,
    /// Meta information string was not the first string in the catalog
    MisplacedMetadata,
    /// Invalid Plural-Forms metadata
    PluralParsing,
    /// An unknown encoding was specified in the metadata
    UnknownEncoding,
}
use crate::Error::*;

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
            MalformedMetadata => "metadata syntax error",
            MisplacedMetadata => "misplaced metadata",
            UnknownEncoding => "unknown encoding specified",
            PluralParsing => "invalid plural expression",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(_: Cow<'static, str>) -> Error {
        DecodingError
    }
}

/// ParseOptions allows setting options for parsing MO catalogs.
///
/// # Examples
/// ```ignore
/// use std::fs::File;
/// use encoding::all::ISO_8859_1;
///
/// let file = File::open("french.mo").unwrap();
/// let catalog = ParseOptions::new().force_encoding(ISO_8859_1).parse(file).unwrap();
/// ```
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
    force_plural: Option<fn(u64) -> usize>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        Default::default()
    }

    /// Tries to parse the catalog from the given reader using the specified options.
    pub fn parse<R: io::Read>(self, reader: R) -> Result<Catalog, Error> {
        parse_catalog(reader, self)
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(mut self, encoding: EncodingRef) -> Self {
        self.force_encoding = Some(encoding);
        self
    }

    /// Forces a use of the given plural formula
    /// for deciding the proper plural form for a message.
    /// If this option is not enabled,
    /// the parser tries to use the plural formula specified in the metadata
    /// or `n != 1` if metadata is non-existent.
    pub fn force_plural(mut self, plural: fn(u64) -> usize) -> Self {
        self.force_plural = Some(plural);
        self
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

pub fn parse_catalog<'a, R: io::Read>(mut file: R, opts: ParseOptions) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = file.read_to_end(&mut contents)?;
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = get_read_u32_fn(&contents[0..4]).ok_or(BadMagic)?;

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    if let Some(f) = opts.force_plural {
        catalog.resolver = Resolver::Function(f);
    }
    let mut encoding = opts.force_encoding.unwrap_or(utf8_encoding);

    for i in 0..num_strings {
        // Parse the original string
        if n < off_otable + 8 {
            return Err(Eof);
        }
        let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
        let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
        // +1 compensates for the ending NUL byte which is not included in length
        if n < off + len + 1 {
            return Err(Eof);
        }
        let mut original = &contents[off..off + len + 1];
        // check for context
        let context = match original.iter().position(|x| *x == 4) {
            Some(idx) => {
                let ctx = &original[..idx];
                original = &original[idx + 1..];
                Some(encoding.decode(ctx, Strict)?)
            }
            None => None,
        };
        // extract msg_id singular, ignoring the plural
        let id = match original
            .iter()
            .position(|x| *x == 0)
            .map(|i| &original[..i])
        {
            Some(b) => encoding.decode(b, Strict)?,
            None => return Err(Eof),
        };
        if id == "" && i != 0 {
            return Err(MisplacedMetadata);
        }

        // Parse the translation strings
        if n < off_ttable + 8 {
            return Err(Eof);
        }
        let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
        let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
        // +1 compensates for the ending NUL byte which is not included in length
        if n < off + len + 1 {
            return Err(Eof);
        }
        let translated = contents[off..off + len]
            .split(|x| *x == 0)
            .map(|b| encoding.decode(b, Strict))
            .collect::<Result<Vec<_>, _>>()?;
        if id == "" {
            let map = parse_metadata(&*translated[0])?;
            if let (Some(c), None) = (map.charset(), opts.force_encoding) {
                encoding = encoding_from_whatwg_label(c).ok_or(UnknownEncoding)?;
            }
            if opts.force_plural.is_none() {
                if let Some(p) = map.plural_forms().1 {
                    catalog.resolver = Ast::parse(p).map(Resolver::Expr)?;
                }
            }
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    Ok(catalog)
}

/// The default plural resolver.
///
/// It will be used if not `Plural-Forms` header is found in the .mo file, and if
/// `ParseOptions::force_plural` was not called.
///
/// It is valid for English and similar languages: plural will be used for any quantity
/// different of 1.
pub fn default_resolver(n: u64) -> usize {
    if n == 1 {
        0
    } else {
        1
    }
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(
            catalog.strings["this is context\x04Text"],
            Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"])
        );
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(
            catalog.strings["Image"],
            Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"])
        );
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader, ParseOptions::new()).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<|endoftext|>


<commit_before>use chrono::DateTime;
use chrono::prelude::{Local, Utc};
use errors::*;
use nom::{alphanumeric, ErrorKind, IResult};
use output::Output;
use std::str;

#[derive(Debug, PartialEq, Eq)]
struct Program {
    name: MacroOp,
    steps: Vec<Step>,
}

#[derive(Debug, PartialEq, Eq)]
struct Step {
    op: MacroOp,
    args: Vec<String>
}

#[derive(Debug, PartialEq, Eq)]
enum MacroOp {
    Add,
    Divide,
    Multiply,
    Name(String),
    Roll,
    Say,
    Subtract,
    Whisper,
}

#[derive(Debug, PartialEq, Eq)]
enum RollOp {
    Advantage,
    Comment,
    Disadvantage,
    NdD,
}

#[derive(Debug, PartialEq, Eq)]
enum SayOp {
    Message,
    To,
}

named!(arguments <&[u8], String>, alt!(
    string |
    quoted |
    single_quoted
));

/// Matches a command
named!(command <&[u8], MacroOp>, alt!(
    map!(ws!(tag!("!roll")),     |_| MacroOp::Roll)      |
    map!(ws!(tag!("!r")),        |_| MacroOp::Roll)      |
    map!(ws!(tag!("!say")),      |_| MacroOp::Say)       |
    map!(ws!(tag!("!s")),        |_| MacroOp::Say)       |
    map!(ws!(tag!("!whisper")),  |_| MacroOp::Whisper)   |
    map!(ws!(tag!("!w")),        |_| MacroOp::Whisper)
));

/// Matches a macro name
named!(name <&[u8], MacroOp>, ws!(do_parse!(
    tag!("#") >>
    name: map_res!(is_not!(" \t\r\n"), |r: &[u8]| String::from_utf8(r.to_vec())) >>
    (MacroOp::Name(name))
)));

/// Matches any type of operation
named!(op <&[u8], MacroOp>, alt!(
    name |
    command |
    ws!(primitive)
));

/// Matches primitive operations
named!(primitive <&[u8], MacroOp>, alt!(
    map!(tag!("*"), |_| MacroOp::Multiply)  |
    map!(tag!("+"), |_| MacroOp::Add)       |
    map!(tag!("-"), |_| MacroOp::Subtract)  |
    map!(tag!("/"), |_| MacroOp::Divide)
));

/// Parse the complete macro
named!(parse <&[u8], Program>, do_parse!(
    prog_name: name >>
    op_type: op >>
    args: ws!(many0!(arguments)) >>
    (Program {
        name: prog_name,
        steps: vec![Step {
            op: op_type,
            args,
        }],
    })
));

/// Matches arguments in quotes ("")
named!(quoted <&[u8], String>, do_parse!(
    word: ws!(delimited!(tag!("\""),take_until!("\""), tag!("\""))) >>
    (String::from_utf8(word.to_vec()).unwrap())
));

/// Matches arguments in quotes ('')
named!(single_quoted <&[u8], String>, do_parse!(
    word: ws!(delimited!(tag!("'"),take_until!("'"), tag!("'"))) >>
    (String::from_utf8(word.to_vec()).unwrap())
));

/// Match alphanumeric values to strings
named!(string <&[u8], String>, do_parse!(
    word: ws!(alphanumeric) >>
    (String::from_utf8(word.to_vec()).unwrap())
));

#[test]
fn test_parser() {
    let program = Program {
        name: MacroOp::Name(String::from("macro-name")),
        steps: vec![Step {
            op: MacroOp::Roll,
            args: vec![ "1d20".to_string() ],
        }],
    };
    let (_, result) = parse(b"#macro-name !roll 1d20").unwrap();
    assert_eq!(result, program);

    let program = Program {
        name: MacroOp::Name(String::from("macro-name-2")),
        steps: vec![Step {
            op: MacroOp::Say,
            args: vec![ "Hello, world!".to_string() ],
        }],
    };
    let (_, result) = parse(b"#macro-name-2 !say \"Hello, world!\"").unwrap();
    assert_eq!(result, program);
}

#[test]
fn test_name_parser() {
    let (_, result) = name(b"#macro_name").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("macro_name")));

    let (_, result) = name(b"#macro-name").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("macro-name")));

    let (_, result) = name(b"#123macro-name").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("123macro-name")));

    let (_, result) = name(b"#Z123macro-name").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("Z123macro-name")));

    let (_, result) = name(b"#macro-name cannot have spaces").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("macro-name")));

    let bad_result = name(b"macro_name");
    match bad_result {
        IResult::Error(e) => assert_eq!(e, ErrorKind::Tag),
        _ => assert_eq!(1, 0),
    }
}

#[test]
fn test_command_parser_roll() {
    let (_, result) = command(b"!roll 1d20").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!r 1d20").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!roll advantage").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!roll adv").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!roll disadvantage").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!roll dis").unwrap();
    assert_eq!(result, MacroOp::Roll);
}

#[test]
fn test_op_parser() {
    let (_, result) = op(b"    #test-macro   ").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("test-macro")));
    let (_, result) = command(b"    !roll 1d20 ").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"   !say \"Hello!\" ").unwrap();
    assert_eq!(result, MacroOp::Say);
    let (_, result) = command(b"   !whisper").unwrap();
    assert_eq!(result, MacroOp::Whisper);
}

#[test]
fn test_arguments_parser() {
    let (_, result) = arguments(b"\"hello\"").unwrap();
    assert_eq!(result, String::from("hello"));
    let (_, result) = arguments(b"   Hello  ").unwrap();
    assert_eq!(result, String::from("Hello"));
    let (_, result) = arguments(b"'   Single String Args'").unwrap();
    assert_eq!(result, String::from("Single String Args"));
}

#[test]
fn test_quoted_parser() {
    let (_, result) = quoted(b"\"hello\"").unwrap();
    assert_eq!(result, String::from("hello"));
    let (_, result) = quoted(b"\"   Hello  \"").unwrap();
    assert_eq!(result, String::from("Hello  "));
}

#[test]
fn test_single_quoted_parser() {
    let (_, result) = single_quoted(b"'test 123'").unwrap();
    assert_eq!(result, String::from("test 123"));
    let (_, result) = single_quoted(b"'   Single String Args'").unwrap();
    assert_eq!(result, String::from("Single String Args"));
}
<commit_msg>parse semi-complex macros<commit_after>use chrono::DateTime;
use chrono::prelude::{Local, Utc};
use errors::*;
use nom::{alphanumeric, ErrorKind, IResult};
use output::Output;
use std::str;

#[derive(Debug, PartialEq, Eq)]
struct Program {
    name: MacroOp,
    steps: Vec<Step>,
}

#[derive(Debug, PartialEq, Eq)]
struct Step {
    op: MacroOp,
    args: Vec<String>
}

#[derive(Debug, PartialEq, Eq)]
enum MacroOp {
    Add,
    Divide,
    Multiply,
    Name(String),
    Roll,
    Say,
    Subtract,
    Whisper,
}

#[derive(Debug, PartialEq, Eq)]
enum RollOp {
    Advantage,
    Comment,
    Disadvantage,
    NdD,
}

#[derive(Debug, PartialEq, Eq)]
enum SayOp {
    Message,
    To,
}

named!(arguments <&[u8], String>, alt!(
    string |
    quoted |
    single_quoted
));

/// Matches a command
named!(command <&[u8], MacroOp>, alt!(
    map!(ws!(tag!("!roll")),     |_| MacroOp::Roll)      |
    map!(ws!(tag!("!r")),        |_| MacroOp::Roll)      |
    map!(ws!(tag!("!say")),      |_| MacroOp::Say)       |
    map!(ws!(tag!("!s")),        |_| MacroOp::Say)       |
    map!(ws!(tag!("!whisper")),  |_| MacroOp::Whisper)   |
    map!(ws!(tag!("!w")),        |_| MacroOp::Whisper)
));

/// Matches a macro name
named!(name <&[u8], MacroOp>, ws!(do_parse!(
    tag!("#") >>
    name: map_res!(is_not!(" \t\r\n"), |r: &[u8]| String::from_utf8(r.to_vec())) >>
    (MacroOp::Name(name))
)));

/// Matches any type of operation
named!(op <&[u8], MacroOp>, alt!(
    name |
    command |
    ws!(primitive)
));

/// Matches primitive operations
named!(primitive <&[u8], MacroOp>, alt!(
    map!(tag!("*"), |_| MacroOp::Multiply)  |
    map!(tag!("+"), |_| MacroOp::Add)       |
    map!(tag!("-"), |_| MacroOp::Subtract)  |
    map!(tag!("/"), |_| MacroOp::Divide)
));

/// Parse the complete macro
named!(parse <&[u8], Program>, do_parse!(
    prog_name: name >>
    steps: many0!(parse_step) >>
    (Program {
        name: prog_name,
        steps: steps,
    })
));

/// Parse a step of the program
named!(parse_step <&[u8], Step>, do_parse!(
    op_type: op >>
    args: ws!(many0!(arguments)) >>
    (Step {
        op: op_type,
        args,
    })
));

/// Matches arguments in quotes ("")
named!(quoted <&[u8], String>, do_parse!(
    word: ws!(delimited!(tag!("\""),take_until!("\""), tag!("\""))) >>
    (String::from_utf8(word.to_vec()).unwrap())
));

/// Matches arguments in quotes ('')
named!(single_quoted <&[u8], String>, do_parse!(
    word: ws!(delimited!(tag!("'"),take_until!("'"), tag!("'"))) >>
    (String::from_utf8(word.to_vec()).unwrap())
));

/// Match alphanumeric values to strings
named!(string <&[u8], String>, do_parse!(
    word: ws!(alphanumeric) >>
    (String::from_utf8(word.to_vec()).unwrap())
));

#[test]
fn test_simple_parser() {
    let program = Program {
        name: MacroOp::Name(String::from("macro-name")),
        steps: vec![Step {
            op: MacroOp::Roll,
            args: vec![ "1d20".to_string() ],
        }],
    };
    let (_, result) = parse(b"#macro-name !roll 1d20").unwrap();
    assert_eq!(result, program);

    let program = Program {
        name: MacroOp::Name(String::from("macro-name-2")),
        steps: vec![Step {
            op: MacroOp::Say,
            args: vec![ "Hello, world!".to_string() ],
        }],
    };
    let (_, result) = parse(b"#macro-name-2 !say \"Hello, world!\"").unwrap();
    assert_eq!(result, program);
}

#[test]
fn test_complex_parser() {
    let program = Program {
        name: MacroOp::Name(String::from("macro-name")),
        steps: vec![
            Step {
                op: MacroOp::Roll,
                args: vec![ "1d20".to_string() ],
            },
            Step {
                op: MacroOp::Say,
                args: vec![ "Smite!".to_string() ],
            },
        ],
    };
    let (_, result) = parse(b"#macro-name !roll 1d20 !say \"Smite!\"").unwrap();
    assert_eq!(result, program);

    let program = Program {
        name: MacroOp::Name(String::from("macro-name-2")),
        steps: vec![
            Step {
                op: MacroOp::Roll,
                args: vec![ "3d8".to_string() ],
            },
            Step {
                op: MacroOp::Say,
                args: vec![ "Smite!".to_string() ],
            },
            Step {
                op: MacroOp::Roll,
                args: vec![ "1d20".to_string() ],
            },
        ],
    };
    let (_, result) = parse(b"#macro-name-2 !roll 3d8 !say \"Smite!\" !roll 1d20").unwrap();
    assert_eq!(result, program);
}

#[test]
fn test_name_parser() {
    let (_, result) = name(b"#macro_name").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("macro_name")));

    let (_, result) = name(b"#macro-name").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("macro-name")));

    let (_, result) = name(b"#123macro-name").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("123macro-name")));

    let (_, result) = name(b"#Z123macro-name").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("Z123macro-name")));

    let (_, result) = name(b"#macro-name cannot have spaces").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("macro-name")));

    let bad_result = name(b"macro_name");
    match bad_result {
        IResult::Error(e) => assert_eq!(e, ErrorKind::Tag),
        _ => assert_eq!(1, 0),
    }
}

#[test]
fn test_command_parser_roll() {
    let (_, result) = command(b"!roll 1d20").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!r 1d20").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!roll advantage").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!roll adv").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!roll disadvantage").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"!roll dis").unwrap();
    assert_eq!(result, MacroOp::Roll);
}

#[test]
fn test_op_parser() {
    let (_, result) = op(b"    #test-macro   ").unwrap();
    assert_eq!(result, MacroOp::Name(String::from("test-macro")));
    let (_, result) = command(b"    !roll 1d20 ").unwrap();
    assert_eq!(result, MacroOp::Roll);
    let (_, result) = command(b"   !say \"Hello!\" ").unwrap();
    assert_eq!(result, MacroOp::Say);
    let (_, result) = command(b"   !whisper").unwrap();
    assert_eq!(result, MacroOp::Whisper);
}

#[test]
fn test_arguments_parser() {
    let (_, result) = arguments(b"\"hello\"").unwrap();
    assert_eq!(result, String::from("hello"));
    let (_, result) = arguments(b"   Hello  ").unwrap();
    assert_eq!(result, String::from("Hello"));
    let (_, result) = arguments(b"'   Single String Args'").unwrap();
    assert_eq!(result, String::from("Single String Args"));
}

#[test]
fn test_quoted_parser() {
    let (_, result) = quoted(b"\"hello\"").unwrap();
    assert_eq!(result, String::from("hello"));
    let (_, result) = quoted(b"\"   Hello  \"").unwrap();
    assert_eq!(result, String::from("Hello  "));
}

#[test]
fn test_single_quoted_parser() {
    let (_, result) = single_quoted(b"'test 123'").unwrap();
    assert_eq!(result, String::from("test 123"));
    let (_, result) = single_quoted(b"'   Single String Args'").unwrap();
    assert_eq!(result, String::from("Single String Args"));
}
<|endoftext|>


<commit_before>use libc;

use ffi;
use error::{YamlError, YamlErrorContext, YamlMark};
use event::YamlEvent;
use document::{YamlDocument};
use codecs;

use std::mem;
use std::io::{IoError, EndOfFile};
use std::slice;

pub struct YamlEventStream<P> {
    parser: Box<P>,
}

impl<P:YamlParser> Iterator for YamlEventStream<P> {
    type Item = Result<YamlEvent, YamlError>;

    fn next(&mut self) -> Option<Result<YamlEvent, YamlError>> {
        unsafe {
            match self.parser.parse_event() {
                Some(YamlEvent::YamlNoEvent) => None,
                Some(evt) => Some(Ok(evt)),
                None => Some(Err(self.parser.get_error()))
            }
        }
    }
}

pub struct YamlDocumentStream<P> {
    parser: Box<P>,
}

impl<P:YamlParser> Iterator for YamlDocumentStream<P> {
    type Item = Result<Box<YamlDocument>, YamlError>;

    fn next(&mut self) -> Option<Result<Box<YamlDocument>, YamlError>> {
        unsafe {
            match YamlDocument::parser_load(&mut self.parser.base_parser_ref().parser_mem) {
                Some(doc) => if doc.is_empty() {
                    None
                } else {
                    Some(Ok(doc))
                },
                None => Some(Err(self.parser.get_error()))
            }
        }
    }
}

pub struct InternalEvent {
    event_mem: ffi::yaml_event_t
}

impl Drop for InternalEvent {
    fn drop(&mut self) {
        unsafe {
            self.event_mem.delete()
        }
    }
}

pub trait YamlParser: Sized {
    unsafe fn base_parser_ref<'r>(&'r mut self) -> &'r mut YamlBaseParser;
    unsafe fn get_error(&mut self) -> YamlError;

    unsafe fn parse_event(&mut self) -> Option<YamlEvent> {
        let mut event = InternalEvent {
            event_mem: mem::uninitialized()
        };

        if !self.base_parser_ref().parse(&mut event.event_mem) {
            None
        } else {
            Some(YamlEvent::load(&event.event_mem))
        }
    }

    fn parse(self: Box<Self>) -> YamlEventStream<Self> {
        YamlEventStream {
            parser: self,
        }
    }

    fn load(self: Box<Self>) -> YamlDocumentStream<Self> {
        YamlDocumentStream {
            parser: self,
        }
    }
}

extern fn handle_reader_cb(data: *mut YamlIoParser, buffer: *mut u8, size: libc::size_t, size_read: *mut libc::size_t) -> libc::c_int {
    unsafe {
        let mut buf = slice::from_raw_mut_buf(&buffer, size as usize);
        let parser = &mut *data;
        match parser.reader.read(buf) {
            Ok(size) => {
                *size_read = size as libc::size_t;
                return 1;
            },
            Err(err) => {
                match err.kind {
                    EndOfFile => {
                        *size_read = 0;
                        return 1;
                    },
                    _ => {
                        parser.io_error = Some(err);
                        return 0;
                    }
                }
            }
        }
    }
}

pub struct YamlBaseParser {
    parser_mem: ffi::yaml_parser_t,
}

impl YamlBaseParser {
    unsafe fn new() -> YamlBaseParser {
        YamlBaseParser {
            parser_mem: mem::uninitialized()
        }
    }

    unsafe fn initialize(&mut self) -> bool {
        ffi::yaml_parser_initialize(&mut self.parser_mem) != 0
    }

    unsafe fn set_input_string(&mut self, input: *const u8, size: usize) {
        ffi::yaml_parser_set_input_string(&mut self.parser_mem, input, size as libc::size_t);
    }

    unsafe fn parse(&mut self, event: &mut ffi::yaml_event_t) -> bool {
        ffi::yaml_parser_parse(&mut self.parser_mem, event) != 0
    }

    unsafe fn build_error(&self) -> YamlError {
        let context = YamlErrorContext {
            byte_offset: self.parser_mem.problem_offset as usize,
            problem_mark: YamlMark::conv(&self.parser_mem.problem_mark),
            context: codecs::decode_c_str(self.parser_mem.context as *const ffi::yaml_char_t),
            context_mark: YamlMark::conv(&self.parser_mem.context_mark),
        };

        YamlError {
            kind: self.parser_mem.error,
            problem: codecs::decode_c_str(self.parser_mem.problem as *const ffi::yaml_char_t),
            io_error: None,
            context: Some(context)
        }
    }
}

impl Drop for YamlBaseParser {
    fn drop(&mut self) {
        unsafe {
            ffi::yaml_parser_delete(&mut self.parser_mem);
        }
    }
}

pub struct YamlByteParser<'r> {
    base_parser: YamlBaseParser
}

impl<'r> YamlParser for YamlByteParser<'r> {
    unsafe fn base_parser_ref<'a>(&'a mut self) -> &'a mut YamlBaseParser {
        &mut self.base_parser
    }

    unsafe fn get_error(&mut self) -> YamlError {
        self.base_parser.build_error()
    }
}

impl<'r> YamlByteParser<'r> {
    pub fn init(bytes: &'r [u8], encoding: ffi::YamlEncoding) -> Box<YamlByteParser<'r>> {
        unsafe {
            let mut parser = box YamlByteParser {
                base_parser: YamlBaseParser::new()
            };

            if !parser.base_parser.initialize() {
                panic!("failed to initialize yaml_parser_t");
            }

            ffi::yaml_parser_set_encoding(&mut parser.base_parser.parser_mem, encoding);
            parser.base_parser.set_input_string(bytes.as_ptr(), bytes.len());

            parser
        }
    }
}

pub struct YamlIoParser<'r> {
    base_parser: YamlBaseParser,
    reader: &'r mut (Reader+'r),
    io_error: Option<IoError>,
}

impl<'r> YamlParser for YamlIoParser<'r> {
    unsafe fn base_parser_ref<'a>(&'a mut self) -> &'a mut YamlBaseParser {
        &mut self.base_parser
    }

    unsafe fn get_error(&mut self) -> YamlError {
        let mut error = self.base_parser.build_error();
        mem::swap(&mut (error.io_error), &mut (self.io_error));
        return error;
    }
}

impl<'r> YamlIoParser<'r> {
    pub fn init<'a>(reader: &'a mut Reader, encoding: ffi::YamlEncoding) -> Box<YamlIoParser<'a>> {
        unsafe {
            let mut parser = box YamlIoParser {
                base_parser: YamlBaseParser::new(),
                reader: reader,
                io_error: None
            };

            if !parser.base_parser.initialize() {
                panic!("failed to initialize yaml_parser_t");
            }

            ffi::yaml_parser_set_encoding(&mut parser.base_parser.parser_mem, encoding);

            ffi::yaml_parser_set_input(&mut parser.base_parser.parser_mem, handle_reader_cb, mem::transmute(&mut *parser));

            parser
        }
    }
}

#[cfg(test)]
mod test {
    use event::{YamlEvent, YamlSequenceParam, YamlScalarParam};
    use event::YamlEvent::*;
    use document::{YamlDocument, YamlNode};
    use parser;
    use parser::YamlParser;
    use error::YamlError;
    use ffi::YamlErrorType;
    use ffi::YamlEncoding::*;
    use ffi::YamlScalarStyle::*;
    use ffi::YamlSequenceStyle::*;
    use std::io;

    #[test]
    fn test_byte_parser() {
        let data = "[1, 2, 3]";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let expected = Ok(vec![
            YamlStreamStartEvent(YamlUtf8Encoding),
            YamlDocumentStartEvent(None, vec![], true),
            YamlSequenceStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "3".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlSequenceEndEvent,
            YamlDocumentEndEvent(true),
            YamlStreamEndEvent
        ]);

        let stream: Result<Vec<YamlEvent>, YamlError> = parser.parse().collect();

        assert_eq!(expected, stream);
    }

    #[test]
    fn test_io_parser() {
        let data = "[1, 2, 3]";
        let mut reader = io::BufReader::new(data.as_bytes());
        let parser = parser::YamlIoParser::init(&mut reader, YamlUtf8Encoding);
        let expected = Ok(vec![
            YamlStreamStartEvent(YamlUtf8Encoding),
            YamlDocumentStartEvent(None, vec![], true),
            YamlSequenceStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "3".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlSequenceEndEvent,
            YamlDocumentEndEvent(true),
            YamlStreamEndEvent
        ]);

        let stream: Result<Vec<YamlEvent>, YamlError> = parser.parse().collect();

        assert_eq!(expected, stream);
    }

    #[test]
    fn test_byte_parser_mapping() {
        let data = "{\"a\": 1, \"b\":2}";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let expected = Ok(vec![
            YamlStreamStartEvent(YamlUtf8Encoding),
            YamlDocumentStartEvent(None, vec![], true),
            YamlMappingStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "a".to_string(), plain_implicit: false, quoted_implicit: true, style: YamlDoubleQuotedScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "b".to_string(), plain_implicit: false, quoted_implicit: true, style: YamlDoubleQuotedScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlMappingEndEvent,
            YamlDocumentEndEvent(true),
            YamlStreamEndEvent
        ]);

        let stream: Result<Vec<YamlEvent>, YamlError> = parser.parse().collect();

        assert_eq!(expected, stream);
    }

    #[test]
    fn test_parser_error() {
        let data = "\"ab";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let mut stream = parser.parse();

        let stream_start = stream.next();
        assert_eq!(Some(Ok(YamlStreamStartEvent(YamlUtf8Encoding))), stream_start);

        let stream_err = stream.next();
        match stream_err {
            Some(Err(err)) => assert_eq!(YamlErrorType::YAML_SCANNER_ERROR, err.kind),
            evt => panic!("unexpected result: {}", evt),
        }
    }

    #[test]
    fn test_document() {
        let data = "[1, 2, 3]";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let docs_res:Result<Vec<Box<YamlDocument>>, YamlError> = parser.load().collect();

        match docs_res {
            Err(e) => panic!("unexpected result: {}", e),
            Ok(docs) => match docs.as_slice().first().and_then(|doc| doc.root()) {
                Some(YamlNode::YamlSequenceNode(seq)) => {
                    let values:Vec<String> = seq.values().map(|node| {
                        match node {
                            YamlNode::YamlScalarNode(scalar) => scalar.get_value(),
                            _ => panic!("unexpected scalar")
                        }
                    }).collect();
                    assert_eq!(vec!["1".to_string(), "2".to_string(), "3".to_string()], values)
                },
                _ => panic!("unexpected result")
            }
        }
    }

    #[test]
    fn test_mapping_document() {
        let data = "{\"a\": 1, \"b\": 2}";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let docs_res:Result<Vec<Box<YamlDocument>>, YamlError> = parser.load().collect();

        match docs_res {
            Err(e) => panic!("unexpected result: {}", e),
            Ok(docs) => match docs.as_slice().first().and_then(|doc| doc.root()) {
                Some(YamlNode::YamlMappingNode(seq)) => {
                    let values:Vec<(String, String)> = seq.pairs().map(|(key, value)| {
                        (
                            match key {
                                YamlNode::YamlScalarNode(scalar) => scalar.get_value(),
                                _ => panic!("unexpected scalar")
                            },
                            match value {
                                YamlNode::YamlScalarNode(scalar) => scalar.get_value(),
                                _ => panic!("unexpected scalar")
                            }
                        )
                    }).collect();
                    assert_eq!(vec![("a".to_string(), "1".to_string()), ("b".to_string(), "2".to_string())], values)
                },
                _ => panic!("unexpected result")
            }
        }
    }
}
<commit_msg>Language changes: fmt::Show changed from {} to {:?}<commit_after>use libc;

use ffi;
use error::{YamlError, YamlErrorContext, YamlMark};
use event::YamlEvent;
use document::{YamlDocument};
use codecs;

use std::mem;
use std::io::{IoError, EndOfFile};
use std::slice;

pub struct YamlEventStream<P> {
    parser: Box<P>,
}

impl<P:YamlParser> Iterator for YamlEventStream<P> {
    type Item = Result<YamlEvent, YamlError>;

    fn next(&mut self) -> Option<Result<YamlEvent, YamlError>> {
        unsafe {
            match self.parser.parse_event() {
                Some(YamlEvent::YamlNoEvent) => None,
                Some(evt) => Some(Ok(evt)),
                None => Some(Err(self.parser.get_error()))
            }
        }
    }
}

pub struct YamlDocumentStream<P> {
    parser: Box<P>,
}

impl<P:YamlParser> Iterator for YamlDocumentStream<P> {
    type Item = Result<Box<YamlDocument>, YamlError>;

    fn next(&mut self) -> Option<Result<Box<YamlDocument>, YamlError>> {
        unsafe {
            match YamlDocument::parser_load(&mut self.parser.base_parser_ref().parser_mem) {
                Some(doc) => if doc.is_empty() {
                    None
                } else {
                    Some(Ok(doc))
                },
                None => Some(Err(self.parser.get_error()))
            }
        }
    }
}

pub struct InternalEvent {
    event_mem: ffi::yaml_event_t
}

impl Drop for InternalEvent {
    fn drop(&mut self) {
        unsafe {
            self.event_mem.delete()
        }
    }
}

pub trait YamlParser: Sized {
    unsafe fn base_parser_ref<'r>(&'r mut self) -> &'r mut YamlBaseParser;
    unsafe fn get_error(&mut self) -> YamlError;

    unsafe fn parse_event(&mut self) -> Option<YamlEvent> {
        let mut event = InternalEvent {
            event_mem: mem::uninitialized()
        };

        if !self.base_parser_ref().parse(&mut event.event_mem) {
            None
        } else {
            Some(YamlEvent::load(&event.event_mem))
        }
    }

    fn parse(self: Box<Self>) -> YamlEventStream<Self> {
        YamlEventStream {
            parser: self,
        }
    }

    fn load(self: Box<Self>) -> YamlDocumentStream<Self> {
        YamlDocumentStream {
            parser: self,
        }
    }
}

extern fn handle_reader_cb(data: *mut YamlIoParser, buffer: *mut u8, size: libc::size_t, size_read: *mut libc::size_t) -> libc::c_int {
    unsafe {
        let mut buf = slice::from_raw_mut_buf(&buffer, size as usize);
        let parser = &mut *data;
        match parser.reader.read(buf) {
            Ok(size) => {
                *size_read = size as libc::size_t;
                return 1;
            },
            Err(err) => {
                match err.kind {
                    EndOfFile => {
                        *size_read = 0;
                        return 1;
                    },
                    _ => {
                        parser.io_error = Some(err);
                        return 0;
                    }
                }
            }
        }
    }
}

pub struct YamlBaseParser {
    parser_mem: ffi::yaml_parser_t,
}

impl YamlBaseParser {
    unsafe fn new() -> YamlBaseParser {
        YamlBaseParser {
            parser_mem: mem::uninitialized()
        }
    }

    unsafe fn initialize(&mut self) -> bool {
        ffi::yaml_parser_initialize(&mut self.parser_mem) != 0
    }

    unsafe fn set_input_string(&mut self, input: *const u8, size: usize) {
        ffi::yaml_parser_set_input_string(&mut self.parser_mem, input, size as libc::size_t);
    }

    unsafe fn parse(&mut self, event: &mut ffi::yaml_event_t) -> bool {
        ffi::yaml_parser_parse(&mut self.parser_mem, event) != 0
    }

    unsafe fn build_error(&self) -> YamlError {
        let context = YamlErrorContext {
            byte_offset: self.parser_mem.problem_offset as usize,
            problem_mark: YamlMark::conv(&self.parser_mem.problem_mark),
            context: codecs::decode_c_str(self.parser_mem.context as *const ffi::yaml_char_t),
            context_mark: YamlMark::conv(&self.parser_mem.context_mark),
        };

        YamlError {
            kind: self.parser_mem.error,
            problem: codecs::decode_c_str(self.parser_mem.problem as *const ffi::yaml_char_t),
            io_error: None,
            context: Some(context)
        }
    }
}

impl Drop for YamlBaseParser {
    fn drop(&mut self) {
        unsafe {
            ffi::yaml_parser_delete(&mut self.parser_mem);
        }
    }
}

pub struct YamlByteParser<'r> {
    base_parser: YamlBaseParser
}

impl<'r> YamlParser for YamlByteParser<'r> {
    unsafe fn base_parser_ref<'a>(&'a mut self) -> &'a mut YamlBaseParser {
        &mut self.base_parser
    }

    unsafe fn get_error(&mut self) -> YamlError {
        self.base_parser.build_error()
    }
}

impl<'r> YamlByteParser<'r> {
    pub fn init(bytes: &'r [u8], encoding: ffi::YamlEncoding) -> Box<YamlByteParser<'r>> {
        unsafe {
            let mut parser = box YamlByteParser {
                base_parser: YamlBaseParser::new()
            };

            if !parser.base_parser.initialize() {
                panic!("failed to initialize yaml_parser_t");
            }

            ffi::yaml_parser_set_encoding(&mut parser.base_parser.parser_mem, encoding);
            parser.base_parser.set_input_string(bytes.as_ptr(), bytes.len());

            parser
        }
    }
}

pub struct YamlIoParser<'r> {
    base_parser: YamlBaseParser,
    reader: &'r mut (Reader+'r),
    io_error: Option<IoError>,
}

impl<'r> YamlParser for YamlIoParser<'r> {
    unsafe fn base_parser_ref<'a>(&'a mut self) -> &'a mut YamlBaseParser {
        &mut self.base_parser
    }

    unsafe fn get_error(&mut self) -> YamlError {
        let mut error = self.base_parser.build_error();
        mem::swap(&mut (error.io_error), &mut (self.io_error));
        return error;
    }
}

impl<'r> YamlIoParser<'r> {
    pub fn init<'a>(reader: &'a mut Reader, encoding: ffi::YamlEncoding) -> Box<YamlIoParser<'a>> {
        unsafe {
            let mut parser = box YamlIoParser {
                base_parser: YamlBaseParser::new(),
                reader: reader,
                io_error: None
            };

            if !parser.base_parser.initialize() {
                panic!("failed to initialize yaml_parser_t");
            }

            ffi::yaml_parser_set_encoding(&mut parser.base_parser.parser_mem, encoding);

            ffi::yaml_parser_set_input(&mut parser.base_parser.parser_mem, handle_reader_cb, mem::transmute(&mut *parser));

            parser
        }
    }
}

#[cfg(test)]
mod test {
    use event::{YamlEvent, YamlSequenceParam, YamlScalarParam};
    use event::YamlEvent::*;
    use document::{YamlDocument, YamlNode};
    use parser;
    use parser::YamlParser;
    use error::YamlError;
    use ffi::YamlErrorType;
    use ffi::YamlEncoding::*;
    use ffi::YamlScalarStyle::*;
    use ffi::YamlSequenceStyle::*;
    use std::io;

    #[test]
    fn test_byte_parser() {
        let data = "[1, 2, 3]";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let expected = Ok(vec![
            YamlStreamStartEvent(YamlUtf8Encoding),
            YamlDocumentStartEvent(None, vec![], true),
            YamlSequenceStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "3".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlSequenceEndEvent,
            YamlDocumentEndEvent(true),
            YamlStreamEndEvent
        ]);

        let stream: Result<Vec<YamlEvent>, YamlError> = parser.parse().collect();

        assert_eq!(expected, stream);
    }

    #[test]
    fn test_io_parser() {
        let data = "[1, 2, 3]";
        let mut reader = io::BufReader::new(data.as_bytes());
        let parser = parser::YamlIoParser::init(&mut reader, YamlUtf8Encoding);
        let expected = Ok(vec![
            YamlStreamStartEvent(YamlUtf8Encoding),
            YamlDocumentStartEvent(None, vec![], true),
            YamlSequenceStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "3".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlSequenceEndEvent,
            YamlDocumentEndEvent(true),
            YamlStreamEndEvent
        ]);

        let stream: Result<Vec<YamlEvent>, YamlError> = parser.parse().collect();

        assert_eq!(expected, stream);
    }

    #[test]
    fn test_byte_parser_mapping() {
        let data = "{\"a\": 1, \"b\":2}";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let expected = Ok(vec![
            YamlStreamStartEvent(YamlUtf8Encoding),
            YamlDocumentStartEvent(None, vec![], true),
            YamlMappingStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "a".to_string(), plain_implicit: false, quoted_implicit: true, style: YamlDoubleQuotedScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "b".to_string(), plain_implicit: false, quoted_implicit: true, style: YamlDoubleQuotedScalarStyle}),
            YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}),
            YamlMappingEndEvent,
            YamlDocumentEndEvent(true),
            YamlStreamEndEvent
        ]);

        let stream: Result<Vec<YamlEvent>, YamlError> = parser.parse().collect();

        assert_eq!(expected, stream);
    }

    #[test]
    fn test_parser_error() {
        let data = "\"ab";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let mut stream = parser.parse();

        let stream_start = stream.next();
        assert_eq!(Some(Ok(YamlStreamStartEvent(YamlUtf8Encoding))), stream_start);

        let stream_err = stream.next();
        match stream_err {
            Some(Err(err)) => assert_eq!(YamlErrorType::YAML_SCANNER_ERROR, err.kind),
            evt => panic!("unexpected result: {:?}", evt),
        }
    }

    #[test]
    fn test_document() {
        let data = "[1, 2, 3]";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let docs_res:Result<Vec<Box<YamlDocument>>, YamlError> = parser.load().collect();

        match docs_res {
            Err(e) => panic!("unexpected result: {:?}", e),
            Ok(docs) => match docs.as_slice().first().and_then(|doc| doc.root()) {
                Some(YamlNode::YamlSequenceNode(seq)) => {
                    let values:Vec<String> = seq.values().map(|node| {
                        match node {
                            YamlNode::YamlScalarNode(scalar) => scalar.get_value(),
                            _ => panic!("unexpected scalar")
                        }
                    }).collect();
                    assert_eq!(vec!["1".to_string(), "2".to_string(), "3".to_string()], values)
                },
                _ => panic!("unexpected result")
            }
        }
    }

    #[test]
    fn test_mapping_document() {
        let data = "{\"a\": 1, \"b\": 2}";
        let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding);
        let docs_res:Result<Vec<Box<YamlDocument>>, YamlError> = parser.load().collect();

        match docs_res {
            Err(e) => panic!("unexpected result: {:?}", e),
            Ok(docs) => match docs.as_slice().first().and_then(|doc| doc.root()) {
                Some(YamlNode::YamlMappingNode(seq)) => {
                    let values:Vec<(String, String)> = seq.pairs().map(|(key, value)| {
                        (
                            match key {
                                YamlNode::YamlScalarNode(scalar) => scalar.get_value(),
                                _ => panic!("unexpected scalar")
                            },
                            match value {
                                YamlNode::YamlScalarNode(scalar) => scalar.get_value(),
                                _ => panic!("unexpected scalar")
                            }
                        )
                    }).collect();
                    assert_eq!(vec![("a".to_string(), "1".to_string()), ("b".to_string(), "2".to_string())], values)
                },
                _ => panic!("unexpected result")
            }
        }
    }
}
<|endoftext|>