<commit_before>//! [PLY](https://en.wikipedia.org/wiki/PLY_(file_format)) encoding.
//!
//! This module provides support for the PLY format via the `FromPly` and
//! `ToPly` traits. These traits can be used with a decoder and encoder to read
//! and write mesh data structures to and from the PLY format.
//!
//! PLY support is implemented using the
//! [`ply-rs`](https://crates.io/crates/ply-rs) crate.
//!
//! # Examples
//!
//! Reading a PLY file into a `MeshGraph`:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! #
//! use nalgebra::Point3;
//! use plexus::encoding::ply::{FromPly, PointEncoding};
//! use plexus::graph::MeshGraph;
//! use std::fs::File;
//!
//! // Read from a file, network, etc.
//! fn read<'a>() -> &'a [u8] {
//!     // ...
//!     # include_bytes!("../../data/cube.ply")
//! }
//!
//! # fn main() {
//! let encoding = PointEncoding::default();
//! let (graph, _) = MeshGraph::<Point3<f64>>::from_ply(encoding, read()).unwrap();
//! # }
//! ```

#![cfg(feature = "encoding-ply")]

use num::{NumCast, ToPrimitive};
use ply_rs::parser::Parser;
use ply_rs::ply::KeyMap;
use smallvec::SmallVec;
use std::io::{self, Read, Write};
use std::iter::FromIterator;
use std::marker::PhantomData;
use theon::space::{EuclideanSpace, FiniteDimensional};
use typenum::U3;

use crate::buffer::BufferError;
use crate::encoding::{FaceDecoder, FromEncoding, VertexDecoder};
use crate::graph::GraphError;

pub use ply_rs::ply::{
    ElementDef as ElementDefinition, Property, PropertyDef as PropertyDefinition, PropertyType,
};

// TODO: These traits only allow a single element to be read for each topology
//       (vertices, faces, etc.). It may be useful to allow code to aggregate
//       various elements to produce an output for a single topology.
// TODO: Consider using the new-type pattern to hide underlying types and
//       expose a smaller and more tailored API surface.

pub type Header = KeyMap<ElementDefinition>;
pub type Payload = KeyMap<Vec<Element>>;
pub type Element = KeyMap<Property>;

#[derive(Debug)]
pub enum PlyError {
    ElementNotFound,
    PropertyNotFound,
    Encoding,
    Io(io::Error),
}

impl From<BufferError> for PlyError {
    fn from(_: BufferError) -> Self {
        PlyError::Encoding
    }
}

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

impl From<GraphError> for PlyError {
    fn from(_: GraphError) -> Self {
        PlyError::Encoding
    }
}

pub trait ElementExt {
    fn read_scalar<T>(&self, key: &str) -> Result<T, PlyError>
    where
        T: NumCast;

    fn read_list<T, I>(&self, key: &str) -> Result<I, PlyError>
    where
        T: NumCast,
        I: FromIterator<T>;
}

impl ElementExt for Element {
    fn read_scalar<T>(&self, key: &str) -> Result<T, PlyError>
    where
        T: NumCast,
    {
        self.get(key)
            .ok_or_else(|| PlyError::PropertyNotFound)?
            .clone()
            .into_scalar()
    }

    fn read_list<T, I>(&self, key: &str) -> Result<I, PlyError>
    where
        T: NumCast,
        I: FromIterator<T>,
    {
        self.get(key)
            .ok_or_else(|| PlyError::PropertyNotFound)?
            .clone()
            .into_list()
    }
}

pub trait PropertyExt {
    fn into_scalar<T>(self) -> Result<T, PlyError>
    where
        T: NumCast;

    fn into_list<T, I>(self) -> Result<I, PlyError>
    where
        T: NumCast,
        I: FromIterator<T>;
}

impl PropertyExt for Property {
    fn into_scalar<T>(self) -> Result<T, PlyError>
    where
        T: NumCast,
    {
        match self {
            Property::Char(value) => num_cast_scalar(value),
            Property::UChar(value) => num_cast_scalar(value),
            Property::Short(value) => num_cast_scalar(value),
            Property::UShort(value) => num_cast_scalar(value),
            Property::Int(value) => num_cast_scalar(value),
            Property::UInt(value) => num_cast_scalar(value),
            Property::Float(value) => num_cast_scalar(value),
            Property::Double(value) => num_cast_scalar(value),
            _ => Err(PlyError::Encoding),
        }
    }

    fn into_list<T, I>(self) -> Result<I, PlyError>
    where
        T: NumCast,
        I: FromIterator<T>,
    {
        match self {
            Property::ListChar(values) => num_cast_list(values),
            Property::ListUChar(values) => num_cast_list(values),
            Property::ListShort(values) => num_cast_list(values),
            Property::ListUShort(values) => num_cast_list(values),
            Property::ListInt(values) => num_cast_list(values),
            Property::ListUInt(values) => num_cast_list(values),
            Property::ListFloat(values) => num_cast_list(values),
            Property::ListDouble(values) => num_cast_list(values),
            _ => Err(PlyError::Encoding),
        }
    }
}

pub trait VertexElementDecoder {
    fn decode_vertex_elements<'a>(
        &self,
        definitions: &'a Header,
        elements: &'a Payload,
    ) -> Result<(&'a ElementDefinition, &'a Vec<Element>), PlyError> {
        definitions
            .get("vertex")
            .ok_or_else(|| PlyError::ElementNotFound)
            .map(|definition| (definition, elements.get(&definition.name).unwrap()))
    }
}

pub trait VertexPropertyDecoder: VertexDecoder {
    fn decode_vertex_properties<'a, I>(
        &self,
        definition: &'a ElementDefinition,
        elements: I,
    ) -> Result<Self::Output, PlyError>
    where
        I: IntoIterator<Item = &'a Element>;
}

pub trait FaceElementDecoder {
    fn decode_face_elements<'a>(
        &self,
        definitions: &'a Header,
        elements: &'a Payload,
    ) -> Result<(&'a ElementDefinition, &'a Vec<Element>), PlyError> {
        definitions
            .get("face")
            .ok_or_else(|| PlyError::ElementNotFound)
            .map(|definition| (definition, elements.get(&definition.name).unwrap()))
    }
}

pub trait FacePropertyDecoder: FaceDecoder {
    fn decode_face_properties<'a, I>(
        &self,
        definition: &'a ElementDefinition,
        elements: I,
    ) -> Result<Self::Output, PlyError>
    where
        I: IntoIterator<Item = &'a Element>;
}

pub trait FromPly<E>: Sized {
    fn from_ply<R>(decoder: E, read: R) -> Result<(Self, Header), PlyError>
    where
        R: Read;
}

impl<T, E> FromPly<E> for T
where
    T: FromEncoding<E>,
    PlyError: From<<T as FromEncoding<E>>::Error>,
    E: FaceElementDecoder + FacePropertyDecoder + VertexPropertyDecoder + VertexElementDecoder,
{
    fn from_ply<R>(decoder: E, mut read: R) -> Result<(Self, Header), PlyError>
    where
        R: Read,
    {
        let ply = Parser::<Element>::new().read_ply(&mut read)?;
        let vertices = decoder
            .decode_vertex_elements(&ply.header.elements, &ply.payload)
            .and_then(|(definition, elements)| {
                decoder.decode_vertex_properties(definition, elements)
            })?;
        let faces = decoder
            .decode_face_elements(&ply.header.elements, &ply.payload)
            .and_then(|(definition, elements)| {
                decoder.decode_face_properties(definition, elements)
            })?;
        let mesh = T::from_encoding(vertices, faces)?;
        Ok((mesh, ply.header.elements))
    }
}

pub trait ToPly<E> {
    fn to_ply<W>(&self, definitions: Header, encoder: E, write: W) -> Result<usize, PlyError>
    where
        W: Write;
}

pub struct PointEncoding<T> {
    phantom: PhantomData<T>,
}

impl<T> Default for PointEncoding<T> {
    fn default() -> Self {
        PointEncoding {
            phantom: PhantomData,
        }
    }
}

impl<T> FaceDecoder for PointEncoding<T> {
    type Output = Vec<(Self::Index, Self::Face)>;
    type Index = SmallVec<[usize; 4]>;
    type Face = ();
}

impl<T> FaceElementDecoder for PointEncoding<T> {}

impl<T> FacePropertyDecoder for PointEncoding<T> {
    fn decode_face_properties<'a, I>(
        &self,
        _: &'a ElementDefinition,
        elements: I,
    ) -> Result<<Self as FaceDecoder>::Output, PlyError>
    where
        I: IntoIterator<Item = &'a Element>,
    {
        elements
            .into_iter()
            .map(|element| {
                let indices = element.read_list("index")?;
                Ok((indices, ()))
            })
            .collect::<Result<_, _>>()
    }
}

impl<T> VertexDecoder for PointEncoding<T> {
    type Output = Vec<Self::Vertex>;
    type Vertex = T;
}

impl<T> VertexElementDecoder for PointEncoding<T> {}

// TODO: Support two-dimensional spaces.
impl<T> VertexPropertyDecoder for PointEncoding<T>
where
    T: EuclideanSpace + FiniteDimensional<N = U3>,
{
    fn decode_vertex_properties<'a, I>(
        &self,
        _: &'a ElementDefinition,
        elements: I,
    ) -> Result<<Self as VertexDecoder>::Output, PlyError>
    where
        I: IntoIterator<Item = &'a Element>,
    {
        elements
            .into_iter()
            .map(|element| {
                let vertex = EuclideanSpace::from_xyz(
                    element.read_scalar("x")?,
                    element.read_scalar("y")?,
                    element.read_scalar("z")?,
                );
                Ok(vertex)
            })
            .collect::<Result<_, _>>()
    }
}

fn num_cast_scalar<T, U>(value: T) -> Result<U, PlyError>
where
    T: ToPrimitive,
    U: NumCast,
{
    NumCast::from(value).ok_or_else(|| PlyError::Encoding)
}

fn num_cast_list<T, U, I>(values: Vec<T>) -> Result<I, PlyError>
where
    T: ToPrimitive,
    U: NumCast,
    I: FromIterator<U>,
{
    values
        .into_iter()
        .map(|value| num_cast_scalar(value))
        .collect::<Result<_, _>>()
}

#[cfg(test)]
mod tests {
    use nalgebra::Point3;

    use crate::encoding::ply::{FromPly, PointEncoding};
    use crate::graph::MeshGraph;

    #[test]
    fn decode() {
        let ply: &[u8] = include_bytes!("../../data/cube.ply");
        let (graph, _) = MeshGraph::<Point3<f64>>::from_ply(PointEncoding::default(), ply).unwrap();
        assert_eq!(8, graph.vertex_count());
        assert_eq!(12, graph.edge_count());
        assert_eq!(6, graph.face_count());
    }
}
<commit_msg>Remove unused import from example.<commit_after>//! [PLY](https://en.wikipedia.org/wiki/PLY_(file_format)) encoding.
//!
//! This module provides support for the PLY format via the `FromPly` and
//! `ToPly` traits. These traits can be used with a decoder and encoder to read
//! and write mesh data structures to and from the PLY format.
//!
//! PLY support is implemented using the
//! [`ply-rs`](https://crates.io/crates/ply-rs) crate.
//!
//! # Examples
//!
//! Reading a PLY file into a `MeshGraph`:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! #
//! use nalgebra::Point3;
//! use plexus::encoding::ply::{FromPly, PointEncoding};
//! use plexus::graph::MeshGraph;
//! use std::io::Read;
//!
//! // Read from a file, network, etc.
//! fn read() -> impl Read {
//!     // ...
//!     # include_bytes!("../../data/cube.ply")
//! }
//!
//! # fn main() {
//! let encoding = PointEncoding::default();
//! let (graph, _) = MeshGraph::<Point3<f64>>::from_ply(encoding, read()).unwrap();
//! # }
//! ```

#![cfg(feature = "encoding-ply")]

use num::{NumCast, ToPrimitive};
use ply_rs::parser::Parser;
use ply_rs::ply::KeyMap;
use smallvec::SmallVec;
use std::io::{self, Read, Write};
use std::iter::FromIterator;
use std::marker::PhantomData;
use theon::space::{EuclideanSpace, FiniteDimensional};
use typenum::U3;

use crate::buffer::BufferError;
use crate::encoding::{FaceDecoder, FromEncoding, VertexDecoder};
use crate::graph::GraphError;

pub use ply_rs::ply::{
    ElementDef as ElementDefinition, Property, PropertyDef as PropertyDefinition, PropertyType,
};

// TODO: These traits only allow a single element to be read for each topology
//       (vertices, faces, etc.). It may be useful to allow code to aggregate
//       various elements to produce an output for a single topology.
// TODO: Consider using the new-type pattern to hide underlying types and
//       expose a smaller and more tailored API surface.

pub type Header = KeyMap<ElementDefinition>;
pub type Payload = KeyMap<Vec<Element>>;
pub type Element = KeyMap<Property>;

#[derive(Debug)]
pub enum PlyError {
    ElementNotFound,
    PropertyNotFound,
    Encoding,
    Io(io::Error),
}

impl From<BufferError> for PlyError {
    fn from(_: BufferError) -> Self {
        PlyError::Encoding
    }
}

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

impl From<GraphError> for PlyError {
    fn from(_: GraphError) -> Self {
        PlyError::Encoding
    }
}

pub trait ElementExt {
    fn read_scalar<T>(&self, key: &str) -> Result<T, PlyError>
    where
        T: NumCast;

    fn read_list<T, I>(&self, key: &str) -> Result<I, PlyError>
    where
        T: NumCast,
        I: FromIterator<T>;
}

impl ElementExt for Element {
    fn read_scalar<T>(&self, key: &str) -> Result<T, PlyError>
    where
        T: NumCast,
    {
        self.get(key)
            .ok_or_else(|| PlyError::PropertyNotFound)?
            .clone()
            .into_scalar()
    }

    fn read_list<T, I>(&self, key: &str) -> Result<I, PlyError>
    where
        T: NumCast,
        I: FromIterator<T>,
    {
        self.get(key)
            .ok_or_else(|| PlyError::PropertyNotFound)?
            .clone()
            .into_list()
    }
}

pub trait PropertyExt {
    fn into_scalar<T>(self) -> Result<T, PlyError>
    where
        T: NumCast;

    fn into_list<T, I>(self) -> Result<I, PlyError>
    where
        T: NumCast,
        I: FromIterator<T>;
}

impl PropertyExt for Property {
    fn into_scalar<T>(self) -> Result<T, PlyError>
    where
        T: NumCast,
    {
        match self {
            Property::Char(value) => num_cast_scalar(value),
            Property::UChar(value) => num_cast_scalar(value),
            Property::Short(value) => num_cast_scalar(value),
            Property::UShort(value) => num_cast_scalar(value),
            Property::Int(value) => num_cast_scalar(value),
            Property::UInt(value) => num_cast_scalar(value),
            Property::Float(value) => num_cast_scalar(value),
            Property::Double(value) => num_cast_scalar(value),
            _ => Err(PlyError::Encoding),
        }
    }

    fn into_list<T, I>(self) -> Result<I, PlyError>
    where
        T: NumCast,
        I: FromIterator<T>,
    {
        match self {
            Property::ListChar(values) => num_cast_list(values),
            Property::ListUChar(values) => num_cast_list(values),
            Property::ListShort(values) => num_cast_list(values),
            Property::ListUShort(values) => num_cast_list(values),
            Property::ListInt(values) => num_cast_list(values),
            Property::ListUInt(values) => num_cast_list(values),
            Property::ListFloat(values) => num_cast_list(values),
            Property::ListDouble(values) => num_cast_list(values),
            _ => Err(PlyError::Encoding),
        }
    }
}

pub trait VertexElementDecoder {
    fn decode_vertex_elements<'a>(
        &self,
        definitions: &'a Header,
        elements: &'a Payload,
    ) -> Result<(&'a ElementDefinition, &'a Vec<Element>), PlyError> {
        definitions
            .get("vertex")
            .ok_or_else(|| PlyError::ElementNotFound)
            .map(|definition| (definition, elements.get(&definition.name).unwrap()))
    }
}

pub trait VertexPropertyDecoder: VertexDecoder {
    fn decode_vertex_properties<'a, I>(
        &self,
        definition: &'a ElementDefinition,
        elements: I,
    ) -> Result<Self::Output, PlyError>
    where
        I: IntoIterator<Item = &'a Element>;
}

pub trait FaceElementDecoder {
    fn decode_face_elements<'a>(
        &self,
        definitions: &'a Header,
        elements: &'a Payload,
    ) -> Result<(&'a ElementDefinition, &'a Vec<Element>), PlyError> {
        definitions
            .get("face")
            .ok_or_else(|| PlyError::ElementNotFound)
            .map(|definition| (definition, elements.get(&definition.name).unwrap()))
    }
}

pub trait FacePropertyDecoder: FaceDecoder {
    fn decode_face_properties<'a, I>(
        &self,
        definition: &'a ElementDefinition,
        elements: I,
    ) -> Result<Self::Output, PlyError>
    where
        I: IntoIterator<Item = &'a Element>;
}

pub trait FromPly<E>: Sized {
    fn from_ply<R>(decoder: E, read: R) -> Result<(Self, Header), PlyError>
    where
        R: Read;
}

impl<T, E> FromPly<E> for T
where
    T: FromEncoding<E>,
    PlyError: From<<T as FromEncoding<E>>::Error>,
    E: FaceElementDecoder + FacePropertyDecoder + VertexPropertyDecoder + VertexElementDecoder,
{
    fn from_ply<R>(decoder: E, mut read: R) -> Result<(Self, Header), PlyError>
    where
        R: Read,
    {
        let ply = Parser::<Element>::new().read_ply(&mut read)?;
        let vertices = decoder
            .decode_vertex_elements(&ply.header.elements, &ply.payload)
            .and_then(|(definition, elements)| {
                decoder.decode_vertex_properties(definition, elements)
            })?;
        let faces = decoder
            .decode_face_elements(&ply.header.elements, &ply.payload)
            .and_then(|(definition, elements)| {
                decoder.decode_face_properties(definition, elements)
            })?;
        let mesh = T::from_encoding(vertices, faces)?;
        Ok((mesh, ply.header.elements))
    }
}

pub trait ToPly<E> {
    fn to_ply<W>(&self, definitions: Header, encoder: E, write: W) -> Result<usize, PlyError>
    where
        W: Write;
}

pub struct PointEncoding<T> {
    phantom: PhantomData<T>,
}

impl<T> Default for PointEncoding<T> {
    fn default() -> Self {
        PointEncoding {
            phantom: PhantomData,
        }
    }
}

impl<T> FaceDecoder for PointEncoding<T> {
    type Output = Vec<(Self::Index, Self::Face)>;
    type Index = SmallVec<[usize; 4]>;
    type Face = ();
}

impl<T> FaceElementDecoder for PointEncoding<T> {}

impl<T> FacePropertyDecoder for PointEncoding<T> {
    fn decode_face_properties<'a, I>(
        &self,
        _: &'a ElementDefinition,
        elements: I,
    ) -> Result<<Self as FaceDecoder>::Output, PlyError>
    where
        I: IntoIterator<Item = &'a Element>,
    {
        elements
            .into_iter()
            .map(|element| {
                let indices = element.read_list("index")?;
                Ok((indices, ()))
            })
            .collect::<Result<_, _>>()
    }
}

impl<T> VertexDecoder for PointEncoding<T> {
    type Output = Vec<Self::Vertex>;
    type Vertex = T;
}

impl<T> VertexElementDecoder for PointEncoding<T> {}

// TODO: Support two-dimensional spaces.
impl<T> VertexPropertyDecoder for PointEncoding<T>
where
    T: EuclideanSpace + FiniteDimensional<N = U3>,
{
    fn decode_vertex_properties<'a, I>(
        &self,
        _: &'a ElementDefinition,
        elements: I,
    ) -> Result<<Self as VertexDecoder>::Output, PlyError>
    where
        I: IntoIterator<Item = &'a Element>,
    {
        elements
            .into_iter()
            .map(|element| {
                let vertex = EuclideanSpace::from_xyz(
                    element.read_scalar("x")?,
                    element.read_scalar("y")?,
                    element.read_scalar("z")?,
                );
                Ok(vertex)
            })
            .collect::<Result<_, _>>()
    }
}

fn num_cast_scalar<T, U>(value: T) -> Result<U, PlyError>
where
    T: ToPrimitive,
    U: NumCast,
{
    NumCast::from(value).ok_or_else(|| PlyError::Encoding)
}

fn num_cast_list<T, U, I>(values: Vec<T>) -> Result<I, PlyError>
where
    T: ToPrimitive,
    U: NumCast,
    I: FromIterator<U>,
{
    values
        .into_iter()
        .map(|value| num_cast_scalar(value))
        .collect::<Result<_, _>>()
}

#[cfg(test)]
mod tests {
    use nalgebra::Point3;

    use crate::encoding::ply::{FromPly, PointEncoding};
    use crate::graph::MeshGraph;

    #[test]
    fn decode() {
        let ply: &[u8] = include_bytes!("../../data/cube.ply");
        let (graph, _) = MeshGraph::<Point3<f64>>::from_ply(PointEncoding::default(), ply).unwrap();
        assert_eq!(8, graph.vertex_count());
        assert_eq!(12, graph.edge_count());
        assert_eq!(6, graph.face_count());
    }
}
<|endoftext|>


<commit_before>use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::node::Node;
use crate::property_defs::ColorInterpolationFilters;
use crate::xml::Attributes;

use super::context::{FilterContext, FilterInput, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Input, Primitive, PrimitiveParams, ResolvedPrimitive};

/// The `feTile` filter primitive.
#[derive(Clone)]
pub struct FeTile {
    base: Primitive,
    in1: Input,
}

/// Resolved `feTile` primitive for rendering.
pub struct Tile {
    in1: Input,
}

impl Default for FeTile {
    /// Constructs a new `Tile` with empty properties.
    #[inline]
    fn default() -> FeTile {
        FeTile {
            base: Default::default(),
            in1: Default::default(),
        }
    }
}

impl SetAttributes for FeTile {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        self.in1 = self.base.parse_one_input(attrs)?;
        Ok(())
    }
}

impl Tile {
    pub fn render(
        &self,
        primitive: &ResolvedPrimitive,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        // https://www.w3.org/TR/filter-effects/#ColorInterpolationFiltersProperty
        //
        // "Note: The color-interpolation-filters property just has an
        // effect on filter operations. Therefore, it has no effect on
        // filter primitives like [...], feTile"
        //
        // This is why we pass Auto here.
        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            ColorInterpolationFilters::Auto,
        )?;

        // feTile doesn't consider its inputs in the filter primitive subregion calculation.
        let bounds = primitive.get_bounds(ctx)?.into_irect(ctx, draw_ctx);

        let surface = match input_1 {
            FilterInput::StandardInput(input_surface) => input_surface,
            FilterInput::PrimitiveOutput(FilterOutput {
                surface: input_surface,
                bounds: input_bounds,
            }) => {
                let tile_surface = input_surface.tile(input_bounds)?;

                ctx.source_graphic().paint_image_tiled(
                    bounds,
                    &tile_surface,
                    input_bounds.x0,
                    input_bounds.y0,
                )?
            }
        };

        Ok(FilterResult {
            name: primitive.result.clone(),
            output: FilterOutput { surface, bounds },
        })
    }
}

impl FilterEffect for FeTile {
    fn resolve(&self, _node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError> {
        Ok((
            self.base.clone(),
            PrimitiveParams::Tile(Tile {
                in1: self.in1.clone(),
            }),
        ))
    }
}
<commit_msg>feTile: shorten code by implementing Default and Clone for its parameters<commit_after>use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::node::Node;
use crate::property_defs::ColorInterpolationFilters;
use crate::xml::Attributes;

use super::context::{FilterContext, FilterInput, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Input, Primitive, PrimitiveParams, ResolvedPrimitive};

/// The `feTile` filter primitive.
#[derive(Default)]
pub struct FeTile {
    base: Primitive,
    params: Tile,
}

/// Resolved `feTile` primitive for rendering.
#[derive(Clone, Default)]
pub struct Tile {
    in1: Input,
}

impl SetAttributes for FeTile {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        self.params.in1 = self.base.parse_one_input(attrs)?;
        Ok(())
    }
}

impl Tile {
    pub fn render(
        &self,
        primitive: &ResolvedPrimitive,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        // https://www.w3.org/TR/filter-effects/#ColorInterpolationFiltersProperty
        //
        // "Note: The color-interpolation-filters property just has an
        // effect on filter operations. Therefore, it has no effect on
        // filter primitives like [...], feTile"
        //
        // This is why we pass Auto here.
        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            ColorInterpolationFilters::Auto,
        )?;

        // feTile doesn't consider its inputs in the filter primitive subregion calculation.
        let bounds = primitive.get_bounds(ctx)?.into_irect(ctx, draw_ctx);

        let surface = match input_1 {
            FilterInput::StandardInput(input_surface) => input_surface,
            FilterInput::PrimitiveOutput(FilterOutput {
                surface: input_surface,
                bounds: input_bounds,
            }) => {
                let tile_surface = input_surface.tile(input_bounds)?;

                ctx.source_graphic().paint_image_tiled(
                    bounds,
                    &tile_surface,
                    input_bounds.x0,
                    input_bounds.y0,
                )?
            }
        };

        Ok(FilterResult {
            name: primitive.result.clone(),
            output: FilterOutput { surface, bounds },
        })
    }
}

impl FilterEffect for FeTile {
    fn resolve(&self, _node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError> {
        Ok((
            self.base.clone(),
            PrimitiveParams::Tile(self.params.clone()),
        ))
    }
}
<|endoftext|>


<commit_before>//extern crate serde_json;
use rustc_serialize::json;

use std::error::Error;
use std::ffi::OsStr;
use std::fs;
use std::fs::File;
use std::io::{ BufReader, BufRead, Read };
use std::path::{ Path, PathBuf };
use std::str::FromStr;

use download;
use verify;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => return Err(format!("An error occured during package finding. {}", why)),
    });
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct Package {
    pub name: String,
    pub version: String,
    pub crc32: String,
    pub url: String,
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    packages: Vec<Package>,
    version: i32
}

pub fn update_package_list(url: &str, path: &Path) -> Result<bool, String> {
    if (path.extension().is_some() &&
        path.extension().unwrap_or(OsStr::new("")) != ".json") ||
       (path.extension().is_none())
    {
        return Err(String::from(
            format!("Extension of package list is not .json: {}", path.to_str().unwrap_or("Invalid File"))
        ));
    }

    let mut path_temp = PathBuf::new();
    path_temp.push(path);
    path_temp.set_extension("json.tmp");

    if download::download_file(url, path_temp.as_path()).is_err() {
        return Err(String::from("Error occured while downloading package list"))
    }

    if verify::verify_file_crc32(&custom_try!(File::open(&path_temp))) ==
       verify::verify_file_crc32(&custom_try!(File::open(&path)))
    {
        fs::remove_file(path_temp);
        return Ok(false)
    } else {
        fs::remove_file(path);
        fs::rename(path_temp, path);
        return Ok(true)
    }
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, String> {
    let mut list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = String::new();

    reader.read_to_string(&mut buffer);
    let package_list: PackageList = custom_try!(json::decode(&buffer));

    let filtered = package_list.packages
                    .into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err(String::from("Package not found")),
        _ => Ok(filtered)
    }
}

pub fn download_and_find(name: &str, url:&str, path:&Path) -> Result<Vec<Package>, String>{
    if update_package_list(url, path).is_ok() {
        return find_package(name, path)
    } else {
        return Err(String::from("Error occured while downloading package list"))
    }
}
<commit_msg>Split package selection from installation.rs to find_package<commit_after>//extern crate serde_json;
use rustc_serialize::json;

use std::error::Error;
use std::ffi::OsStr;
use std::fs;
use std::fs::File;
use std::io::{ BufReader, BufRead, Read };
use std::path::{ Path, PathBuf };
use std::str::FromStr;

use download;
use verify;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => return Err(format!("An error occured during package finding. {}", why)),
    });
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct Package {
    pub name: String,
    pub version: String,
    pub crc32: String,
    pub url: String,
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    packages: Vec<Package>,
    version: i32
}

pub fn update_package_list(url: &str, path: &Path) -> Result<bool, String> {
    if (path.extension().is_some() &&
        path.extension().unwrap_or(OsStr::new("")) != ".json") ||
       (path.extension().is_none())
    {
        return Err(String::from(
            format!("Extension of package list is not .json: {}", path.to_str().unwrap_or("Invalid File"))
        ));
    }

    let mut path_temp = PathBuf::new();
    path_temp.push(path);
    path_temp.set_extension("json.tmp");

    if download::download_file(url, path_temp.as_path()).is_err() {
        return Err(String::from("Error occured while downloading package list"))
    }

    if verify::verify_file_crc32(&custom_try!(File::open(&path_temp))) ==
       verify::verify_file_crc32(&custom_try!(File::open(&path)))
    {
        fs::remove_file(path_temp);
        return Ok(false)
    } else {
        fs::remove_file(path);
        fs::rename(path_temp, path);
        return Ok(true)
    }
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, String> {
    let mut list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = String::new();

    reader.read_to_string(&mut buffer);
    let package_list: PackageList = custom_try!(json::decode(&buffer));

    let filtered = package_list.packages
                    .into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err(String::from("Package not found")),
        _ => Ok(filtered)
    }
}

pub fn download_and_find(name: &str, url:&str, path:&Path) -> Result<Vec<Package>, String>{
    if update_package_list(url, path).is_ok() {
        return find_package(name, path)
    } else {
        return Err(String::from("Error occured while downloading package list"))
    }
}

pub fn select_package(name: &str, patj: &Path) -> Result<Package, String>{
    let found_packages = find_package(name, path)?;

    if found_packages.len() > 1 {
        for (i, package) in found_packages.iter().enumerate() {
            println!("Package {}: {}", i, package.name);
        }

        let mut input = String::new();
        io::stdin().read_line(&mut input)?;

        let input: u16 = input.trim().parse()?;

        if input > found_packages.len() as u16 {
            return Err(String::from("Invalid input"))
        } else {
            return found_packages[input];
        }
    } else {
        return found_packages[0];
    }
}<|endoftext|>


<commit_before>use cookie_factory::*;
use nom::{be_u8,be_u16,be_u32,IResult};
use method::{method,Method};
use format::field::*;
use generated::*;

use std::collections::HashMap;

named!(pub protocol_header<&[u8]>,
  preceded!(
    tag!(b"AMQP\0"),
    tag!(&[0, 9, 1])
  )
);

pub fn gen_protocol_header<'a>(x:(&'a mut [u8],usize)) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(
    x,
    gen_slice!(b"AMQP") >>
    gen_slice!(&[0, 0, 9, 1])
  )
}

// 0      1         3             7                    size+7 size+8
// +------+---------+-------------+   +------------+   +-----------+
// | type | channel |    size     |   | payload    |   | frame-end |
// +------+---------+-------------+   +------------+   +-----------+
//   octet  short        long        size octets           octet

#[derive(Clone,Copy,Debug,PartialEq,Eq)]
pub enum FrameType {
  Method,
  Header,
  Body,
  Heartbeat
}

named!(pub frame_type<FrameType>,
  switch!(be_u8,
    1 => value!(FrameType::Method)
  | 2 => value!(FrameType::Header)
  | 3 => value!(FrameType::Body)
  | 8 => value!(FrameType::Heartbeat)
  )
);

#[derive(Clone,Copy,Debug,PartialEq,Eq)]
pub enum Channel {
  Global,
  Id(u16),
}

named!(pub channel_id<Channel>,
  switch!(be_u16,
    0 => value!(Channel::Global)
  | i => value!(Channel::Id(i))
  )
);

//FIXME: maybe parse the frame header, and leave the payload for later
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
pub struct RawFrame<'a> {
  pub frame_type: FrameType,
  pub channel_id: u16,
  pub size:       u32,
  pub payload:    &'a[u8],
}

named!(pub raw_frame<RawFrame>,
  do_parse!(
    frame:   frame_type    >>
    channel: be_u16        >>
    size:    be_u32        >>
    payload: take!(size)   >>
             tag!(&[0xCE]) >>
    (RawFrame {
      frame_type: frame,
      channel_id: channel,
      size:       size,
      payload:    payload,
    })
  )
);

#[derive(Clone,Debug,PartialEq)]
pub enum Frame<'a> {
  Method(u16, Method),
  //content header
  Header(u16, ()),
  //content Body
  Body(u16, &'a[u8]),
  Heartbeat(u16)
}

pub fn frame(input: &[u8]) -> IResult<&[u8], Frame> {
  let (remaining, raw) = try_parse!(input, raw_frame);
  match raw.frame_type {
    FrameType::Header    => IResult::Done(remaining, Frame::Header(raw.channel_id, ())),
    FrameType::Body      => IResult::Done(remaining, Frame::Body(raw.channel_id, raw.payload)),
    FrameType::Heartbeat => IResult::Done(remaining, Frame::Heartbeat(raw.channel_id)),
    FrameType::Method    => {
      println!("will try to parse a method");
      let (remaining2, m) = try_parse!(raw.payload, method);
      IResult::Done(remaining2, Frame::Method(raw.channel_id, m))
    },
  }
}

pub fn gen_method_frame<'a>(input:(&'a mut [u8],usize), channel: u16, class: &Class) -> Result<(&'a mut [u8],usize),GenError> {
  if let Ok(input1) = gen_be_u8!(input, 1u8) {
    if let Ok((sl2, index2)) = gen_be_u16!(input1, channel) {
      if let Ok((sl3, index3)) = gen_class((sl2, index2 + 4), class) {
        if let Ok((sl4, index4)) = gen_be_u32!((sl3, index2), index3 - index2 - 4) {
          gen_be_u8!((sl4, index3), 0xCE)
          //if let Ok((sl5, index5)) = gen_be_u8!((sl4, index3), 0xCE)
          //{
          //}
        } else {
          Err(GenError::CustomError(42))
        }
      } else {
        Err(GenError::CustomError(42))
      }
    } else {
      Err(GenError::CustomError(42))
    }
  } else {
    Err(GenError::CustomError(42))
  }
}

pub fn gen_heartbeat_frame<'a>(input:(&'a mut [u8],usize)) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(input, gen_slice!(&[8, 0, 0, 0xCE]))
}

pub fn gen_content_header_frame<'a>(input:(&'a mut [u8],usize), channel_id: u16, class_id: u16, length: u64) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(input,
    gen_be_u8!( 2 ) >>
    gen_be_u16!(channel_id) >>

    gen_be_u32!( 42 ) >> //calculate static size

    gen_be_u16!(class_id) >>
    gen_be_u16!(0) >> // weight
    gen_be_u64!(length) >>
    gen_be_u8!(0) >> // properties
    gen_field_table(&HashMap::new()) >>

    gen_be_u8!(0xCE)
  )
}

pub fn gen_content_body_frame<'a>(input:(&'a mut [u8],usize), channel_id: u16, slice: &[u8]) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(input,
    gen_be_u8!( 3 ) >>
    gen_be_u16!(channel_id) >>

    gen_slice!(slice) >>

    gen_be_u8!(0xCE)
  )
}
<commit_msg>fix content header and content body frames<commit_after>use cookie_factory::*;
use nom::{be_u8,be_u16,be_u32,IResult};
use method::{method,Method};
use format::field::*;
use generated::*;

use std::collections::HashMap;

named!(pub protocol_header<&[u8]>,
  preceded!(
    tag!(b"AMQP\0"),
    tag!(&[0, 9, 1])
  )
);

pub fn gen_protocol_header<'a>(x:(&'a mut [u8],usize)) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(
    x,
    gen_slice!(b"AMQP") >>
    gen_slice!(&[0, 0, 9, 1])
  )
}

// 0      1         3             7                    size+7 size+8
// +------+---------+-------------+   +------------+   +-----------+
// | type | channel |    size     |   | payload    |   | frame-end |
// +------+---------+-------------+   +------------+   +-----------+
//   octet  short        long        size octets           octet

#[derive(Clone,Copy,Debug,PartialEq,Eq)]
pub enum FrameType {
  Method,
  Header,
  Body,
  Heartbeat
}

named!(pub frame_type<FrameType>,
  switch!(be_u8,
    1 => value!(FrameType::Method)
  | 2 => value!(FrameType::Header)
  | 3 => value!(FrameType::Body)
  | 8 => value!(FrameType::Heartbeat)
  )
);

#[derive(Clone,Copy,Debug,PartialEq,Eq)]
pub enum Channel {
  Global,
  Id(u16),
}

named!(pub channel_id<Channel>,
  switch!(be_u16,
    0 => value!(Channel::Global)
  | i => value!(Channel::Id(i))
  )
);

//FIXME: maybe parse the frame header, and leave the payload for later
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
pub struct RawFrame<'a> {
  pub frame_type: FrameType,
  pub channel_id: u16,
  pub size:       u32,
  pub payload:    &'a[u8],
}

named!(pub raw_frame<RawFrame>,
  do_parse!(
    frame:   frame_type    >>
    channel: be_u16        >>
    size:    be_u32        >>
    payload: take!(size)   >>
             tag!(&[0xCE]) >>
    (RawFrame {
      frame_type: frame,
      channel_id: channel,
      size:       size,
      payload:    payload,
    })
  )
);

#[derive(Clone,Debug,PartialEq)]
pub enum Frame<'a> {
  Method(u16, Method),
  //content header
  Header(u16, ()),
  //content Body
  Body(u16, &'a[u8]),
  Heartbeat(u16)
}

pub fn frame(input: &[u8]) -> IResult<&[u8], Frame> {
  let (remaining, raw) = try_parse!(input, raw_frame);
  match raw.frame_type {
    FrameType::Header    => IResult::Done(remaining, Frame::Header(raw.channel_id, ())),
    FrameType::Body      => IResult::Done(remaining, Frame::Body(raw.channel_id, raw.payload)),
    FrameType::Heartbeat => IResult::Done(remaining, Frame::Heartbeat(raw.channel_id)),
    FrameType::Method    => {
      println!("will try to parse a method");
      let (remaining2, m) = try_parse!(raw.payload, method);
      IResult::Done(remaining2, Frame::Method(raw.channel_id, m))
    },
  }
}

pub fn gen_method_frame<'a>(input:(&'a mut [u8],usize), channel: u16, class: &Class) -> Result<(&'a mut [u8],usize),GenError> {
  if let Ok(input1) = gen_be_u8!(input, 1u8) {
    if let Ok((sl2, index2)) = gen_be_u16!(input1, channel) {
      if let Ok((sl3, index3)) = gen_class((sl2, index2 + 4), class) {
        if let Ok((sl4, index4)) = gen_be_u32!((sl3, index2), index3 - index2 - 4) {
          gen_be_u8!((sl4, index3), 0xCE)
          //if let Ok((sl5, index5)) = gen_be_u8!((sl4, index3), 0xCE)
          //{
          //}
        } else {
          Err(GenError::CustomError(42))
        }
      } else {
        Err(GenError::CustomError(42))
      }
    } else {
      Err(GenError::CustomError(42))
    }
  } else {
    Err(GenError::CustomError(42))
  }
}

pub fn gen_heartbeat_frame<'a>(input:(&'a mut [u8],usize)) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(input, gen_slice!(&[8, 0, 0, 0xCE]))
}

pub fn gen_content_header_frame<'a>(input:(&'a mut [u8],usize), channel_id: u16, class_id: u16, length: u64) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(input,
    gen_be_u8!( 2 ) >>
    gen_be_u16!(channel_id) >>

    ofs_len: gen_skip!(4) >>

    start: do_gen!(
      gen_be_u16!(class_id) >>
      gen_be_u16!(0) >> // weight
      gen_be_u64!(length) >>
      gen_be_u16!(0x2000) >> // property flags. Why this value?
      gen_field_table(&HashMap::new())
    ) >>
    end: gen_at_offset!(ofs_len, gen_be_u32!(end-start)) >>

    gen_be_u8!(0xCE)
  )
}

pub fn gen_content_body_frame<'a>(input:(&'a mut [u8],usize), channel_id: u16, slice: &[u8]) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(input,
    gen_be_u8!( 3 ) >>
    gen_be_u16!(channel_id) >>
    gen_be_u32!(slice.len()) >>

    gen_slice!(slice) >>

    gen_be_u8!(0xCE)
  )
}
<|endoftext|>


<commit_before>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::to_u32;

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  )
}

fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      (bytes[1] as u16) >> 2;
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn sample_block(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let sample_byte = bytes[0] & 0x0f;

      if sample_byte != 0x0f {
        let block_byte = bytes[0] >> 4;

        IResult::Done(i, (sample_byte, block_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let channel_assignment = match bytes[0] >> 4 {
        0b0000...0b0111 => ChannelAssignment::Independent,
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (bytes[0] >> 1) & 0b0111;
      let is_valid  = (bytes[0] & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn sample_or_frame_number(input: &[u8], is_sample: bool,
                          (size, value): (usize, u8))
                          -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100 => opt!(input, map!(take!(1), to_u32)),
    0b1101 => opt!(input, map!(take!(2), to_u32)),
    0b1110 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
              -> IResult<'a, &'a [u8], Header> {
  chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: sample_block ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(sample_or_frame_number, is_variable_block_size,
                   number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (sample_byte, block_byte)       = tuple0;
      let (channel_assignment, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0000          => 0,
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        0b1111 => 0,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0011 => 0,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        0b0111 => 0,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  )
}

named!(footer <&[u8], Footer>, map!(be_u16, Footer));
<commit_msg>Reswap the order of block_byte and sample_byte<commit_after>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::to_u32;

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  )
}

fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      (bytes[1] as u16) >> 2;
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let sample_byte = bytes[0] & 0x0f;

      if sample_byte != 0x0f {
        let block_byte = bytes[0] >> 4;

        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let channel_assignment = match bytes[0] >> 4 {
        0b0000...0b0111 => ChannelAssignment::Independent,
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (bytes[0] >> 1) & 0b0111;
      let is_valid  = (bytes[0] & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn sample_or_frame_number(input: &[u8], is_sample: bool,
                          (size, value): (usize, u8))
                          -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100 => opt!(input, map!(take!(1), to_u32)),
    0b1101 => opt!(input, map!(take!(2), to_u32)),
    0b1110 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
              -> IResult<'a, &'a [u8], Header> {
  chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(sample_or_frame_number, is_variable_block_size,
                   number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)       = tuple0;
      let (channel_assignment, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0000          => 0,
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        0b1111 => 0,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0011 => 0,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        0b0111 => 0,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  )
}

named!(footer <&[u8], Footer>, map!(be_u16, Footer));
<|endoftext|>


<commit_before>use std::io::{Read, Cursor};

use FromCursor;
use compression::Compression;
use frame::frame_response::ResponseBody;
use super::*;
use types::{from_bytes, UUID_LEN, CStringList};
use types::data_serialization_types::decode_timeuuid;
use error;

pub fn parse_frame(mut cursor: &mut Read, compressor: &Compression) -> error::Result<Frame> {
    let mut version_bytes = [0; VERSION_LEN];
    let mut flag_bytes = [0; FLAG_LEN];
    let mut opcode_bytes = [0; OPCODE_LEN];
    let mut stream_bytes = [0; STREAM_LEN];
    let mut length_bytes =[0; LENGTH_LEN];

    // NOTE: order of reads matters
    try!(cursor.read(&mut version_bytes));
    try!(cursor.read(&mut flag_bytes));
    try!(cursor.read(&mut stream_bytes));
    try!(cursor.read(&mut opcode_bytes));
    try!(cursor.read(&mut length_bytes));

    let version = Version::from(version_bytes.to_vec());
    let flags = Flag::get_collection(flag_bytes[0]);
    let stream = from_bytes(stream_bytes.to_vec());
    let opcode = Opcode::from(opcode_bytes[0]);
    let length = from_bytes(length_bytes.to_vec()) as usize;

    let mut body_bytes = Vec::with_capacity(length);
    unsafe {
        body_bytes.set_len(length);
    }
    try!(cursor.read_exact(&mut body_bytes));

    let full_body = if flags.iter().any(|flag| flag == &Flag::Compression) {
        try!(compressor.decode(body_bytes))
    } else {
        try!(Compression::None.decode(body_bytes))
    };

    // TODO: use cursor to get tracing id, warnings and actual body
    let mut body_cursor = Cursor::new(full_body);

    let tracing_id = if flags.iter().any(|flag| flag == &Flag::Tracing) {
        let mut tracing_bytes = Vec::with_capacity(UUID_LEN);
        unsafe {
            tracing_bytes.set_len(UUID_LEN);
        }
        try!(body_cursor.read_exact(&mut tracing_bytes));

        decode_timeuuid(tracing_bytes).ok()
    } else {
        None
    };

    let warnings = if flags.iter().any(|flag| flag == &Flag::Warning) {
        CStringList::from_cursor(&mut body_cursor).into_plain()
    } else {
        vec![]
    };

    let mut body = vec![];

    try!(body_cursor.read_to_end(&mut body));

    let frame = Frame {
        version: version,
        flags: flags,
        opcode: opcode,
        stream: stream,
        body: body,
        tracing_id: tracing_id,
        warnings: warnings
    };

    return conver_frame_into_result(frame);
}

fn conver_frame_into_result(frame: Frame) -> error::Result<Frame> {
    match frame.opcode {
        Opcode::Error => match frame.get_body() {
            ResponseBody::Error(err) => Err(error::Error::Server(err)),
            _ => unreachable!()
        },
        _ => Ok(frame)
    }
}
<commit_msg>Fame parser. Remove obsolete TODO comment<commit_after>use std::io::{Read, Cursor};

use FromCursor;
use compression::Compression;
use frame::frame_response::ResponseBody;
use super::*;
use types::{from_bytes, UUID_LEN, CStringList};
use types::data_serialization_types::decode_timeuuid;
use error;

pub fn parse_frame(mut cursor: &mut Read, compressor: &Compression) -> error::Result<Frame> {
    let mut version_bytes = [0; VERSION_LEN];
    let mut flag_bytes = [0; FLAG_LEN];
    let mut opcode_bytes = [0; OPCODE_LEN];
    let mut stream_bytes = [0; STREAM_LEN];
    let mut length_bytes =[0; LENGTH_LEN];

    // NOTE: order of reads matters
    try!(cursor.read(&mut version_bytes));
    try!(cursor.read(&mut flag_bytes));
    try!(cursor.read(&mut stream_bytes));
    try!(cursor.read(&mut opcode_bytes));
    try!(cursor.read(&mut length_bytes));

    let version = Version::from(version_bytes.to_vec());
    let flags = Flag::get_collection(flag_bytes[0]);
    let stream = from_bytes(stream_bytes.to_vec());
    let opcode = Opcode::from(opcode_bytes[0]);
    let length = from_bytes(length_bytes.to_vec()) as usize;

    let mut body_bytes = Vec::with_capacity(length);
    unsafe {
        body_bytes.set_len(length);
    }
    try!(cursor.read_exact(&mut body_bytes));

    let full_body = if flags.iter().any(|flag| flag == &Flag::Compression) {
        try!(compressor.decode(body_bytes))
    } else {
        try!(Compression::None.decode(body_bytes))
    };

    // Use cursor to get tracing id, warnings and actual body
    let mut body_cursor = Cursor::new(full_body);

    let tracing_id = if flags.iter().any(|flag| flag == &Flag::Tracing) {
        let mut tracing_bytes = Vec::with_capacity(UUID_LEN);
        unsafe {
            tracing_bytes.set_len(UUID_LEN);
        }
        try!(body_cursor.read_exact(&mut tracing_bytes));

        decode_timeuuid(tracing_bytes).ok()
    } else {
        None
    };

    let warnings = if flags.iter().any(|flag| flag == &Flag::Warning) {
        CStringList::from_cursor(&mut body_cursor).into_plain()
    } else {
        vec![]
    };

    let mut body = vec![];

    try!(body_cursor.read_to_end(&mut body));

    let frame = Frame {
        version: version,
        flags: flags,
        opcode: opcode,
        stream: stream,
        body: body,
        tracing_id: tracing_id,
        warnings: warnings
    };

    return conver_frame_into_result(frame);
}

fn conver_frame_into_result(frame: Frame) -> error::Result<Frame> {
    match frame.opcode {
        Opcode::Error => match frame.get_body() {
            ResponseBody::Error(err) => Err(error::Error::Server(err)),
            _ => unreachable!()
        },
        _ => Ok(frame)
    }
}
<|endoftext|>


<commit_before>//! General utilities for PortAudio

use util::to_pa_result;
use ll;
use std::fmt;
use std::ffi::CStr;

/// PortAudio version
pub fn version() -> i32
{
    let version = unsafe { ll::Pa_GetVersion() };
    version as i32
}

/// Human-readable PortAudio version
pub fn version_text() -> String
{
    let version_c = unsafe { ll::Pa_GetVersionText() };
    let version_s = String::from_utf8_lossy(unsafe { CStr::from_ptr(version_c).to_bytes() });
    version_s.into_owned()
}

/// Initialize the PortAudio API
///
/// Each successful call must be matched by a call to terminate
pub fn initialize() -> PaResult
{
    to_pa_result(unsafe { ll::Pa_Initialize() })
}

/// Terminate the PortAudio API
///
/// Call this function exactly once for each successful call to initialize
pub fn terminate() -> PaResult
{
    to_pa_result(unsafe { ll::Pa_Terminate() })
}

// PaError and PaResult

/// Enum for all possible errors given by PortAudio
///
/// The NoError value (0) is not present since the Result type can be used then.
#[repr(i32)]
#[derive(PartialEq, Copy, Clone)]
#[allow(missing_docs)]
pub enum PaError
{
    // paNoError is not present in this enum
    NotInitialized = ll::paNotInitialized,
    UnanticipatedHostError = ll::paUnanticipatedHostError,
    InvalidChannelCount = ll::paInvalidChannelCount,
    InvalidSampleRate = ll::paInvalidSampleRate,
    InvalidDevice = ll::paInvalidDevice,
    InvalidFlag = ll::paInvalidFlag,
    SampleFormatNotSupported = ll::paSampleFormatNotSupported,
    BadIODeviceCombination = ll::paBadIODeviceCombination,
    InsufficientMemory = ll::paInsufficientMemory,
    BufferTooBig = ll::paBufferTooBig,
    BufferTooSmall = ll::paBufferTooSmall,
    NullCallback = ll::paNullCallback,
    BadStreamPtr = ll::paBadStreamPtr,
    TimedOut = ll::paTimedOut,
    InternalError = ll::paInternalError,
    DeviceUnavailable = ll::paDeviceUnavailable,
    IncompatibleHostApiSpecificStreamInfo = ll::paIncompatibleHostApiSpecificStreamInfo,
    StreamIsStopped = ll::paStreamIsStopped,
    StreamIsNotStopped = ll::paStreamIsNotStopped,
    InputOverflowed = ll::paInputOverflowed,
    OutputUnderflowed = ll::paOutputUnderflowed,
    HostApiNotFound = ll::paHostApiNotFound,
    InvalidHostApi = ll::paInvalidHostApi,
    CanNotReadFromACallbackStream = ll::paCanNotReadFromACallbackStream,
    CanNotWriteToACallbackStream = ll::paCanNotWriteToACallbackStream,
    CanNotReadFromAnOutputOnlyStream = ll::paCanNotReadFromAnOutputOnlyStream,
    CanNotWriteToAnInputOnlyStream = ll::paCanNotWriteToAnInputOnlyStream,
    IncompatibleStreamHostApi = ll::paIncompatibleStreamHostApi,
    BadBufferPtr = ll::paBadBufferPtr,

    /// Added variant for when FromPrimitive returns None
    UnknownError,
}

impl PaError {
    /// Get the enum value corresponding to the given i32
    pub fn from_i32(num: i32) -> PaError {
        match num {
            ll::paNotInitialized => PaError::NotInitialized,
            ll::paUnanticipatedHostError => PaError::UnanticipatedHostError,
            ll::paInvalidChannelCount => PaError::InvalidChannelCount,
            ll::paInvalidSampleRate => PaError::InvalidSampleRate,
            ll::paInvalidDevice => PaError::InvalidDevice,
            ll::paInvalidFlag => PaError::InvalidFlag,
            ll::paSampleFormatNotSupported => PaError::SampleFormatNotSupported,
            ll::paBadIODeviceCombination => PaError::BadIODeviceCombination,
            ll::paInsufficientMemory => PaError::InsufficientMemory,
            ll::paBufferTooBig => PaError::BufferTooBig,
            ll::paBufferTooSmall => PaError::BufferTooSmall,
            ll::paNullCallback => PaError::NullCallback,
            ll::paBadStreamPtr => PaError::BadStreamPtr,
            ll::paTimedOut => PaError::TimedOut,
            ll::paInternalError => PaError::InternalError,
            ll::paDeviceUnavailable => PaError::DeviceUnavailable,
            ll::paIncompatibleHostApiSpecificStreamInfo => PaError::IncompatibleHostApiSpecificStreamInfo,
            ll::paStreamIsStopped => PaError::StreamIsStopped,
            ll::paStreamIsNotStopped => PaError::StreamIsNotStopped,
            ll::paInputOverflowed => PaError::InputOverflowed,
            ll::paOutputUnderflowed => PaError::OutputUnderflowed,
            ll::paHostApiNotFound => PaError::HostApiNotFound,
            ll::paInvalidHostApi => PaError::InvalidHostApi,
            ll::paCanNotReadFromACallbackStream => PaError::CanNotReadFromACallbackStream,
            ll::paCanNotWriteToACallbackStream => PaError::CanNotWriteToACallbackStream,
            ll::paCanNotReadFromAnOutputOnlyStream => PaError::CanNotReadFromAnOutputOnlyStream,
            ll::paCanNotWriteToAnInputOnlyStream => PaError::CanNotWriteToAnInputOnlyStream,
            ll::paIncompatibleStreamHostApi => PaError::IncompatibleStreamHostApi,
            ll::paBadBufferPtr => PaError::BadBufferPtr,
            _ => PaError::UnknownError,
        }
    }
}

impl fmt::Display for PaError
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self
        {
            PaError::UnknownError => write!(f, "Unknown Error"),
            other =>
            {
                let message_c = unsafe { ll::Pa_GetErrorText(other as i32) };
                let message_s = String::from_utf8_lossy(unsafe { CStr::from_ptr(message_c).to_bytes() });
                f.write_str(&*message_s)
            }
        }
    }
}

impl fmt::Debug for PaError
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        ::std::fmt::Display::fmt(self, fmt)
    }
}

/// A result type wrapping PaError.
///
/// The original NoError is mapped to Ok(()) and other values mapped to Err(x)
pub type PaResult = Result<(), PaError>;
<commit_msg>Implement error for PaError<commit_after>//! General utilities for PortAudio

use util::to_pa_result;
use ll;
use std::fmt;
use std::ffi::CStr;

/// PortAudio version
pub fn version() -> i32
{
    let version = unsafe { ll::Pa_GetVersion() };
    version as i32
}

/// Human-readable PortAudio version
pub fn version_text() -> String
{
    let version_c = unsafe { ll::Pa_GetVersionText() };
    let version_s = String::from_utf8_lossy(unsafe { CStr::from_ptr(version_c).to_bytes() });
    version_s.into_owned()
}

/// Initialize the PortAudio API
///
/// Each successful call must be matched by a call to terminate
pub fn initialize() -> PaResult
{
    to_pa_result(unsafe { ll::Pa_Initialize() })
}

/// Terminate the PortAudio API
///
/// Call this function exactly once for each successful call to initialize
pub fn terminate() -> PaResult
{
    to_pa_result(unsafe { ll::Pa_Terminate() })
}

// PaError and PaResult

/// Enum for all possible errors given by PortAudio
///
/// The NoError value (0) is not present since the Result type can be used then.
#[repr(i32)]
#[derive(PartialEq, Copy, Clone)]
#[allow(missing_docs)]
pub enum PaError
{
    // paNoError is not present in this enum
    NotInitialized = ll::paNotInitialized,
    UnanticipatedHostError = ll::paUnanticipatedHostError,
    InvalidChannelCount = ll::paInvalidChannelCount,
    InvalidSampleRate = ll::paInvalidSampleRate,
    InvalidDevice = ll::paInvalidDevice,
    InvalidFlag = ll::paInvalidFlag,
    SampleFormatNotSupported = ll::paSampleFormatNotSupported,
    BadIODeviceCombination = ll::paBadIODeviceCombination,
    InsufficientMemory = ll::paInsufficientMemory,
    BufferTooBig = ll::paBufferTooBig,
    BufferTooSmall = ll::paBufferTooSmall,
    NullCallback = ll::paNullCallback,
    BadStreamPtr = ll::paBadStreamPtr,
    TimedOut = ll::paTimedOut,
    InternalError = ll::paInternalError,
    DeviceUnavailable = ll::paDeviceUnavailable,
    IncompatibleHostApiSpecificStreamInfo = ll::paIncompatibleHostApiSpecificStreamInfo,
    StreamIsStopped = ll::paStreamIsStopped,
    StreamIsNotStopped = ll::paStreamIsNotStopped,
    InputOverflowed = ll::paInputOverflowed,
    OutputUnderflowed = ll::paOutputUnderflowed,
    HostApiNotFound = ll::paHostApiNotFound,
    InvalidHostApi = ll::paInvalidHostApi,
    CanNotReadFromACallbackStream = ll::paCanNotReadFromACallbackStream,
    CanNotWriteToACallbackStream = ll::paCanNotWriteToACallbackStream,
    CanNotReadFromAnOutputOnlyStream = ll::paCanNotReadFromAnOutputOnlyStream,
    CanNotWriteToAnInputOnlyStream = ll::paCanNotWriteToAnInputOnlyStream,
    IncompatibleStreamHostApi = ll::paIncompatibleStreamHostApi,
    BadBufferPtr = ll::paBadBufferPtr,

    /// Added variant for when FromPrimitive returns None
    UnknownError,
}

impl PaError {
    /// Get the enum value corresponding to the given i32
    pub fn from_i32(num: i32) -> PaError {
        match num {
            ll::paNotInitialized => PaError::NotInitialized,
            ll::paUnanticipatedHostError => PaError::UnanticipatedHostError,
            ll::paInvalidChannelCount => PaError::InvalidChannelCount,
            ll::paInvalidSampleRate => PaError::InvalidSampleRate,
            ll::paInvalidDevice => PaError::InvalidDevice,
            ll::paInvalidFlag => PaError::InvalidFlag,
            ll::paSampleFormatNotSupported => PaError::SampleFormatNotSupported,
            ll::paBadIODeviceCombination => PaError::BadIODeviceCombination,
            ll::paInsufficientMemory => PaError::InsufficientMemory,
            ll::paBufferTooBig => PaError::BufferTooBig,
            ll::paBufferTooSmall => PaError::BufferTooSmall,
            ll::paNullCallback => PaError::NullCallback,
            ll::paBadStreamPtr => PaError::BadStreamPtr,
            ll::paTimedOut => PaError::TimedOut,
            ll::paInternalError => PaError::InternalError,
            ll::paDeviceUnavailable => PaError::DeviceUnavailable,
            ll::paIncompatibleHostApiSpecificStreamInfo => PaError::IncompatibleHostApiSpecificStreamInfo,
            ll::paStreamIsStopped => PaError::StreamIsStopped,
            ll::paStreamIsNotStopped => PaError::StreamIsNotStopped,
            ll::paInputOverflowed => PaError::InputOverflowed,
            ll::paOutputUnderflowed => PaError::OutputUnderflowed,
            ll::paHostApiNotFound => PaError::HostApiNotFound,
            ll::paInvalidHostApi => PaError::InvalidHostApi,
            ll::paCanNotReadFromACallbackStream => PaError::CanNotReadFromACallbackStream,
            ll::paCanNotWriteToACallbackStream => PaError::CanNotWriteToACallbackStream,
            ll::paCanNotReadFromAnOutputOnlyStream => PaError::CanNotReadFromAnOutputOnlyStream,
            ll::paCanNotWriteToAnInputOnlyStream => PaError::CanNotWriteToAnInputOnlyStream,
            ll::paIncompatibleStreamHostApi => PaError::IncompatibleStreamHostApi,
            ll::paBadBufferPtr => PaError::BadBufferPtr,
            _ => PaError::UnknownError,
        }
    }
}

impl fmt::Display for PaError
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self
        {
            PaError::UnknownError => write!(f, "Unknown Error"),
            other =>
            {
                let message_c = unsafe { ll::Pa_GetErrorText(other as i32) };
                let message_s = String::from_utf8_lossy(unsafe { CStr::from_ptr(message_c).to_bytes() });
                f.write_str(&*message_s)
            }
        }
    }
}

impl fmt::Debug for PaError
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        ::std::fmt::Display::fmt(self, fmt)
    }
}

impl std::error::Error for PaError {}

/// A result type wrapping PaError.
///
/// The original NoError is mapped to Ok(()) and other values mapped to Err(x)
pub type PaResult = Result<(), PaError>;
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc::*;

///
/// A scheduler thread reads from the scheduler queue
///
pub struct SchedulerThread {
    /// The jobs that this thread should run
    jobs: Sender<Box<dyn FnOnce() -> ()+Send>>,

    /// The thread itself
    thread: thread::JoinHandle<()>,
}

impl SchedulerThread {
    ///
    /// Creates a new scheduler thread
    ///
    pub fn new() -> SchedulerThread {
        // All the thread does is run jobs from its channel
        let (jobs_in, jobs_out): (Sender<Box<dyn FnOnce() -> ()+Send>>, Receiver<Box<dyn FnOnce() -> ()+Send>>) = channel();
        let thread = thread::Builder::new()
            .name("desync jobs thread".to_string())
            .spawn(move || {
                while let Ok(mut job) = jobs_out.recv() {
                    (*job)();
                }
            }).unwrap();

        SchedulerThread {
            jobs:   jobs_in,
            thread: thread
        }
    }

    ///
    /// Schedules a job to be run on this thread
    ///
    pub fn run<Job: 'static+FnOnce() -> ()+Send>(&self, job: Job) {
        self.jobs.send(Box::new(job)).unwrap();
    }

    ///
    /// De-spawns this thread and returns the join handle
    ///
    pub fn despawn(self) -> thread::JoinHandle<()> {
        self.thread
    }
}
<commit_msg>Work around Box<FnOnce> limitation<commit_after>use std::thread;
use std::sync::mpsc::*;

///
/// Creates a FnMut that runs a FnOnce once (or panics)
///
/// The scheduler only runs jobs once so it accepts them as FnOnce values, but it's currently not possible to
/// box FnOnce values such that they can be run, so we wrap them in FnMut values that panic if called more
/// than once.
///
/// (Nightly rust has FnBox to get around this)
///
fn wrap_fnonce<TFn: FnOnce() -> ()>(job: TFn) -> impl FnMut() -> () {
    let mut job = Some(job);

    move || {
        let job = job.take();

        if let Some(job) = job {
            job()
        } else {
            panic!("Cannot evaluate a job more than once")
        }
    }
}

///
/// A scheduler thread reads from the scheduler queue
///
pub struct SchedulerThread {
    /// The jobs that this thread should run
    jobs: Sender<Box<dyn FnMut() -> ()+Send>>,

    /// The thread itself
    thread: thread::JoinHandle<()>,
}

impl SchedulerThread {
    ///
    /// Creates a new scheduler thread
    ///
    pub fn new() -> SchedulerThread {
        // All the thread does is run jobs from its channel
        let (jobs_in, jobs_out): (Sender<Box<dyn FnMut() -> ()+Send>>, Receiver<Box<dyn FnMut() -> ()+Send>>) = channel();
        let thread = thread::Builder::new()
            .name("desync jobs thread".to_string())
            .spawn(move || {
                while let Ok(mut job) = jobs_out.recv() {
                    (*job)();
                }
            }).unwrap();

        SchedulerThread {
            jobs:   jobs_in,
            thread: thread
        }
    }

    ///
    /// Schedules a job to be run on this thread
    ///
    pub fn run<Job: 'static+FnOnce() -> ()+Send>(&self, job: Job) {
        self.jobs.send(Box::new(wrap_fnonce(job))).unwrap();
    }

    ///
    /// De-spawns this thread and returns the join handle
    ///
    pub fn despawn(self) -> thread::JoinHandle<()> {
        self.thread
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer]);
    }

    pub fn input(&self) {
        let mut buffer = [0; 1];
        let mut stdin = io::stdin();
        stdin.read_exact(&mut buffer).unwrap();
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: &Command) {
        match command {
            &Command::Output => self.output(),
            &Command::Input => self.input(),
            &Command::Increment => self.increment(),
            &Command::Decrement => self.decrement(),
            &Command::RightShift => self.right_shift(),
            &Command::LeftShift => self.left_shift(),
        }
    }

    pub fn apply_many(&mut self, commands: &[Command]) {
        for command in commands {
            self.apply(&command)
        }
    }
}
<commit_msg>Change vm output command to print as char<commit_after>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&self) {
        let mut buffer = [0; 1];
        let mut stdin = io::stdin();
        stdin.read_exact(&mut buffer).unwrap();
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: &Command) {
        match command {
            &Command::Output => self.output(),
            &Command::Input => self.input(),
            &Command::Increment => self.increment(),
            &Command::Decrement => self.decrement(),
            &Command::RightShift => self.right_shift(),
            &Command::LeftShift => self.left_shift(),
        }
    }

    pub fn apply_many(&mut self, commands: &[Command]) {
        for command in commands {
            self.apply(&command)
        }
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::{DirBuilder, metadata};
use super::Error;

use super::super::identifier::Identifier;

#[derive(Clone)]
pub struct Database {
    name: Identifier,
    config: DatabaseConfig
}

impl Database {
    pub fn create(name: &str, config: DatabaseConfig) -> Result<Database, Error> {
        info!("created new database: {}", &name);
        let d = Database { name: try!(Identifier::new(name)), config: config.clone() };

        DirBuilder::new()
            .recursive(true)
            .create(Path::new(&config.path).join(name)).unwrap();

        Ok(d)
    }

    pub fn load(name: &str, config: DatabaseConfig) -> Result<Database, Error>{
        if try!(metadata(Path::new(&config.path).join(name))).is_dir() {
            info!("loaded database: {}", name.to_string());
            Ok(Database { name: try!(Identifier::new(name)), config:  config })
        } else {
            error!("could not load database: {} at {}", name, &config.path);
            Err(Error::LoadDatabase)
        }
    }

    // TODO: write database delete static function

    pub fn get_name(&self) -> String {
        self.name.get_name()
    }

    pub fn get_path(&self) -> PathBuf {
        Path::new(&self.config.path.clone()).join(&self.name.get_name())
    }
}

#[derive(Clone)]
pub struct DatabaseConfig {
    path: String
}

impl DatabaseConfig {
    pub fn new(p: &str) -> Self {
        DatabaseConfig { path: p.to_string() }
    }
}

impl From<String> for DatabaseConfig {
    fn from(p: String) -> Self {
        DatabaseConfig { path: p }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::{File, metadata};
    use std::path::Path;

    #[test]
    fn create_db() {
        let path = "/tmp/test1/";
        let name = "test_db";
        let mut db = Database::create(&name, DatabaseConfig::new(&path));

        assert!(metadata(&path).is_ok());
        assert!(metadata(&path).unwrap().is_dir());
    }

    #[test]
    fn load_db() {
        let path = "/tmp/test2/";
        let name = "test_db2";
        let db = Database::create(&name, DatabaseConfig::new(&path)).unwrap();

        let db2 = Database::load(&name, DatabaseConfig::new(&path)).unwrap();

        assert_eq!(db.get_name(), db2.get_name());
    }
}
<commit_msg>better error handling for databse<commit_after>use std::path::{Path, PathBuf};
use std::fs::{DirBuilder, metadata};
use super::Error;

use super::super::identifier::Identifier;

#[derive(Clone)]
pub struct Database {
    name: Identifier,
    config: DatabaseConfig
}

impl Database {
    pub fn create(name: &str, config: DatabaseConfig) -> Result<Database, Error> {
        info!("created new database: {}", &name);
        let d = Database { name: try!(Identifier::new(name)), config: config.clone() };

        try!(DirBuilder::new()
            .recursive(true)
            .create(Path::new(&config.path).join(name)));

        Ok(d)
    }

    pub fn load(name: &str, config: DatabaseConfig) -> Result<Database, Error>{
        if try!(metadata(Path::new(&config.path).join(name))).is_dir() {
            info!("loaded database: {}", name.to_string());
            Ok(Database { name: try!(Identifier::new(name)), config:  config })
        } else {
            error!("could not load database: {} at {}", name, &config.path);
            Err(Error::LoadDatabase)
        }
    }

    // TODO: write database delete static function

    pub fn get_name(&self) -> String {
        self.name.get_name()
    }

    pub fn get_path(&self) -> PathBuf {
        Path::new(&self.config.path.clone()).join(&self.name.get_name())
    }
}

#[derive(Clone)]
pub struct DatabaseConfig {
    path: String
}

impl DatabaseConfig {
    pub fn new(p: &str) -> Self {
        DatabaseConfig { path: p.to_string() }
    }
}

impl From<String> for DatabaseConfig {
    fn from(p: String) -> Self {
        DatabaseConfig { path: p }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::{File, metadata};
    use std::path::Path;

    #[test]
    fn create_db() {
        let path = "/tmp/test1/";
        let name = "test_db";
        let mut db = Database::create(&name, DatabaseConfig::new(&path));

        assert!(metadata(&path).is_ok());
        assert!(metadata(&path).unwrap().is_dir());
    }

    #[test]
    fn load_db() {
        let path = "/tmp/test2/";
        let name = "test_db2";
        let db = Database::create(&name, DatabaseConfig::new(&path)).unwrap();

        let db2 = Database::load(&name, DatabaseConfig::new(&path)).unwrap();

        assert_eq!(db.get_name(), db2.get_name());
    }
}
<|endoftext|>


<commit_before>use super::peripherals::*;

use std::rc::Rc;
use std::cell::RefCell;

macro_rules! println_if_trace {
    ($fmt: expr, $( $t: expr ),*) => {{
        #[cfg(feature = "trace-interconnect")]
        println!($fmt, $($t),* );
    }}
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct Interconnect {
    memory: Rc<RefCell<Memory>>,

    ay: Rc<RefCell<Ay>>,

    ula: Rc<RefCell<Ula>>,

    ula_contention: Vec<u8>,
    ula_contention_no_mreq: Vec<u8>,
}

impl Interconnect {
    pub fn new(memory: Rc<RefCell<Memory>>,
               ay : Rc<RefCell<Ay>>,
               ula : Rc<RefCell<Ula>>) -> Self {

        let ula_contention = include_bytes!("peripherals/ulacontention.bin");
        let ula_contention_no_mreq = include_bytes!("peripherals/ulacontentionnomreq.bin");

        Interconnect {
            memory: memory,
            ay: ay,
            ula: ula,
            ula_contention: ula_contention.to_vec(),
            ula_contention_no_mreq: ula_contention_no_mreq.to_vec(),
        }
    }

    fn is_addr_contended(&self, addr: u16) -> bool {
        (addr >= 0x4000 && addr < 0x8000) ||
        (addr >= 0xC000 && (self.memory.borrow().get_c000_bank() % 2 != 0))
    }

    #[inline(always)]
    pub fn contend_read(&mut self, addr: u16, curr_tcycle: u32, tcycles: u32) -> u32 {
        println_if_trace!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + tcycles
    }

    #[inline(always)]
    pub fn contend_read_no_mreq(&mut self, addr: u16, curr_tcycle: u32) -> u32 {
        println_if_trace!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    #[inline(always)]
    pub fn contend_write_no_mreq(&mut self, addr: u16, curr_tcycle: u32) -> u32 {
        println_if_trace!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    #[cfg_attr(not(feature = "trace-interconnect"), allow(unused_variables))]
    pub fn read_word(&self, addr: u16, curr_tcycle: u32) -> u8 {
        let val = self.memory.borrow().read_word(addr);
        println_if_trace!("{: >5} MR {:04x} {:02x}", curr_tcycle, addr, val);
        val
    }

    #[cfg_attr(not(feature = "trace-interconnect"), allow(unused_variables))]
    pub fn write_word(&mut self, addr: u16, val: u8, curr_tcycle: u32) {
        self.memory.borrow_mut().write_word(addr, val);
        println_if_trace!("{: >5} MW {:04x} {:02x}", curr_tcycle, addr, val);
    }

    pub fn contend_port_early(&mut self, port: u16, curr_tcycle: u32) -> u32 {
        let delay = if self.is_addr_contended(port) {
            println_if_trace!("{: >5} PC {:04x}", curr_tcycle, port);
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    pub fn contend_port_late(&mut self, port: u16, curr_tcycle: u32) -> u32 {
        let delay = if (port & 0x0001) == 0 {
            println_if_trace!("{: >5} PC {:04x}", curr_tcycle, port);
            (self.ula_contention_no_mreq[curr_tcycle as usize] as u32) + 2
        } else {
            if self.is_addr_contended(port) {
                let mut delay: u32 = 0;
                println_if_trace!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += (self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32) + 1;
                println_if_trace!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += (self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32) + 1;
                println_if_trace!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32;
                delay
            } else {
                2
            }
        };
        delay + 1
    }

    #[cfg_attr(not(feature = "trace-interconnect"), allow(unused_variables))]
    pub fn read_port(&mut self, port: u16, curr_tcycle: u32) -> u8 {
        let val = match port {
            port if port & 0x0001 == 0 => self.ula.borrow().read_port(port),
            0x7ffd => self.memory.borrow().read_port(port),
            0xfffd | 0xbffd => self.ay.borrow().read_port(port),
            _ => 0,
        };
        println_if_trace!("{: >5} PR {:04x} {:02x}", curr_tcycle, port, val);
        val
    }

    #[cfg_attr(not(feature = "trace-interconnect"), allow(unused_variables))]
    pub fn write_port(&mut self, port: u16, val: u8, curr_tcycle: u32) {
        println_if_trace!("{: >5} PW {:04x} {:02x}", curr_tcycle, port, val);
        match port {
            port if port & 0x0001 == 0 => self.ula.borrow_mut().write_port(port, val),
            0x7ffd => self.memory.borrow_mut().write_port(port, val),
            0xfffd | 0xbffd => self.ay.borrow_mut().write_port(port, val),
            _ => (),
        };
    }

    pub fn reset(&mut self) {
        self.memory.borrow_mut().clear();
    }
}
<commit_msg>Remove mut qualifier from interconnect functions<commit_after>use super::peripherals::*;

use std::rc::Rc;
use std::cell::RefCell;

macro_rules! println_if_trace {
    ($fmt: expr, $( $t: expr ),*) => {{
        #[cfg(feature = "trace-interconnect")]
        println!($fmt, $($t),* );
    }}
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct Interconnect {
    memory: Rc<RefCell<Memory>>,

    ay: Rc<RefCell<Ay>>,

    ula: Rc<RefCell<Ula>>,

    ula_contention: Vec<u8>,
    ula_contention_no_mreq: Vec<u8>,
}

impl Interconnect {
    pub fn new(memory: Rc<RefCell<Memory>>,
               ay : Rc<RefCell<Ay>>,
               ula : Rc<RefCell<Ula>>) -> Self {

        let ula_contention = include_bytes!("peripherals/ulacontention.bin");
        let ula_contention_no_mreq = include_bytes!("peripherals/ulacontentionnomreq.bin");

        Interconnect {
            memory: memory,
            ay: ay,
            ula: ula,
            ula_contention: ula_contention.to_vec(),
            ula_contention_no_mreq: ula_contention_no_mreq.to_vec(),
        }
    }

    fn is_addr_contended(&self, addr: u16) -> bool {
        (addr >= 0x4000 && addr < 0x8000) ||
        (addr >= 0xC000 && (self.memory.borrow().get_c000_bank() % 2 != 0))
    }

    #[inline(always)]
    pub fn contend_read(&self, addr: u16, curr_tcycle: u32, tcycles: u32) -> u32 {
        println_if_trace!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + tcycles
    }

    #[inline(always)]
    pub fn contend_read_no_mreq(&self, addr: u16, curr_tcycle: u32) -> u32 {
        println_if_trace!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    #[inline(always)]
    pub fn contend_write_no_mreq(&self, addr: u16, curr_tcycle: u32) -> u32 {
        println_if_trace!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    #[cfg_attr(not(feature = "trace-interconnect"), allow(unused_variables))]
    pub fn read_word(&self, addr: u16, curr_tcycle: u32) -> u8 {
        let val = self.memory.borrow().read_word(addr);
        println_if_trace!("{: >5} MR {:04x} {:02x}", curr_tcycle, addr, val);
        val
    }

    #[cfg_attr(not(feature = "trace-interconnect"), allow(unused_variables))]
    pub fn write_word(&self, addr: u16, val: u8, curr_tcycle: u32) {
        self.memory.borrow_mut().write_word(addr, val);
        println_if_trace!("{: >5} MW {:04x} {:02x}", curr_tcycle, addr, val);
    }

    pub fn contend_port_early(&self, port: u16, curr_tcycle: u32) -> u32 {
        let delay = if self.is_addr_contended(port) {
            println_if_trace!("{: >5} PC {:04x}", curr_tcycle, port);
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    pub fn contend_port_late(&self, port: u16, curr_tcycle: u32) -> u32 {
        let delay = if (port & 0x0001) == 0 {
            println_if_trace!("{: >5} PC {:04x}", curr_tcycle, port);
            (self.ula_contention_no_mreq[curr_tcycle as usize] as u32) + 2
        } else {
            if self.is_addr_contended(port) {
                let mut delay: u32 = 0;
                println_if_trace!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += (self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32) + 1;
                println_if_trace!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += (self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32) + 1;
                println_if_trace!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32;
                delay
            } else {
                2
            }
        };
        delay + 1
    }

    #[cfg_attr(not(feature = "trace-interconnect"), allow(unused_variables))]
    pub fn read_port(&self, port: u16, curr_tcycle: u32) -> u8 {
        let val = match port {
            port if port & 0x0001 == 0 => self.ula.borrow().read_port(port),
            0x7ffd => self.memory.borrow().read_port(port),
            0xfffd | 0xbffd => self.ay.borrow().read_port(port),
            _ => 0,
        };
        println_if_trace!("{: >5} PR {:04x} {:02x}", curr_tcycle, port, val);
        val
    }

    #[cfg_attr(not(feature = "trace-interconnect"), allow(unused_variables))]
    pub fn write_port(&self, port: u16, val: u8, curr_tcycle: u32) {
        println_if_trace!("{: >5} PW {:04x} {:02x}", curr_tcycle, port, val);
        match port {
            port if port & 0x0001 == 0 => self.ula.borrow_mut().write_port(port, val),
            0x7ffd => self.memory.borrow_mut().write_port(port, val),
            0xfffd | 0xbffd => self.ay.borrow_mut().write_port(port, val),
            _ => (),
        };
    }

    pub fn reset(&self) {
        self.memory.borrow_mut().clear();
    }
}
<|endoftext|>