<commit_before>use cairo::{self, MatrixTrait};
use std::cell::Cell;

use attributes::Attribute;
use coord_units::CoordUnits;
use drawing_ctx::DrawingCtx;
use error::RenderingError;
use length::{Length, LengthDir};
use node::{NodeResult, NodeTrait, RsvgNode};
use parsers::{Parse, ParseValue};
use properties::Opacity;
use property_bag::PropertyBag;
use rect::IRect;
use surface_utils::{
    iterators::Pixels,
    shared_surface::SharedImageSurface,
    shared_surface::SurfaceType,
    ImageSurfaceDataExt,
};
use unit_interval::UnitInterval;

coord_units!(MaskUnits, CoordUnits::ObjectBoundingBox);
coord_units!(MaskContentUnits, CoordUnits::UserSpaceOnUse);

pub struct NodeMask {
    x: Cell<Length>,
    y: Cell<Length>,
    width: Cell<Length>,
    height: Cell<Length>,

    units: Cell<MaskUnits>,
    content_units: Cell<MaskContentUnits>,
}

impl NodeMask {
    pub fn new() -> NodeMask {
        NodeMask {
            x: Cell::new(NodeMask::get_default_pos(LengthDir::Horizontal)),
            y: Cell::new(NodeMask::get_default_pos(LengthDir::Vertical)),

            width: Cell::new(NodeMask::get_default_size(LengthDir::Horizontal)),
            height: Cell::new(NodeMask::get_default_size(LengthDir::Vertical)),

            units: Cell::new(MaskUnits::default()),
            content_units: Cell::new(MaskContentUnits::default()),
        }
    }

    fn get_default_pos(dir: LengthDir) -> Length {
        Length::parse_str("-10%", dir).unwrap()
    }

    fn get_default_size(dir: LengthDir) -> Length {
        Length::parse_str("120%", dir).unwrap()
    }

    pub fn generate_cairo_mask(
        &self,
        node: &RsvgNode,
        affine_before_mask: &cairo::Matrix,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<(), RenderingError> {
        let cascaded = node.get_cascaded_values();
        let values = cascaded.get();

        let width = draw_ctx.get_width() as i32;
        let height = draw_ctx.get_height() as i32;

        let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        let mask_units = CoordUnits::from(self.units.get());
        let content_units = CoordUnits::from(self.content_units.get());

        let (x, y, w, h) = {
            let params = if mask_units == CoordUnits::ObjectBoundingBox {
                draw_ctx.push_view_box(1.0, 1.0)
            } else {
                draw_ctx.get_view_params()
            };

            let x = self.x.get().normalize(&values, &params);
            let y = self.y.get().normalize(&values, &params);
            let w = self.width.get().normalize(&values, &params);
            let h = self.height.get().normalize(&values, &params);

            (x, y, w, h)
        };

        // Use a scope because mask_cr needs to release the
        // reference to the surface before we access the pixels
        {
            let bbox_rect = {
                if let Some(ref rect) = draw_ctx.get_bbox().rect {
                    *rect
                } else {
                    // The node being masked is empty / doesn't have a
                    // bounding box, so there's nothing to mask!
                    return Ok(());
                }
            };

            let save_cr = draw_ctx.get_cairo_context();

            let mask_cr = cairo::Context::new(&surface);
            mask_cr.set_matrix(*affine_before_mask);
            mask_cr.transform(node.get_transform());

            draw_ctx.set_cairo_context(&mask_cr);

            if mask_units == CoordUnits::ObjectBoundingBox {
                draw_ctx.clip(
                    x * bbox_rect.width + bbox_rect.x,
                    y * bbox_rect.height + bbox_rect.y,
                    w * bbox_rect.width,
                    h * bbox_rect.height,
                );
            } else {
                draw_ctx.clip(x, y, w, h);
            }

            {
                let _params = if content_units == CoordUnits::ObjectBoundingBox {
                    let bbtransform = cairo::Matrix::new(
                        bbox_rect.width,
                        0.0,
                        0.0,
                        bbox_rect.height,
                        bbox_rect.x,
                        bbox_rect.y,
                    );

                    mask_cr.transform(bbtransform);

                    draw_ctx.push_view_box(1.0, 1.0)
                } else {
                    draw_ctx.get_view_params()
                };

                let res = draw_ctx.with_discrete_layer(node, values, false, &mut |dc| {
                    node.draw_children(&cascaded, dc, false)
                });

                draw_ctx.set_cairo_context(&save_cr);

                res
            }
        }?;

        let Opacity(opacity) = values.opacity;
        let mask_surface = compute_luminance_to_alpha(surface, opacity)?;
        draw_ctx.mask_surface(&mask_surface);

        Ok(())
    }
}

// Returns a surface whose alpha channel for each pixel is equal to the
// luminance of that pixel's unpremultiplied RGB values.  The resulting
// surface's RGB values are not meanignful; only the alpha channel has
// useful luminance data.
//
// This is to get a mask suitable for use with cairo_mask_surface().
fn compute_luminance_to_alpha(
    surface: cairo::ImageSurface,
    opacity: UnitInterval,
) -> Result<cairo::ImageSurface, cairo::Status> {
    let surface = SharedImageSurface::new(surface, SurfaceType::SRgb)?;

    let width = surface.width();
    let height = surface.height();

    let bounds = IRect {
        x0: 0,
        y0: 0,
        x1: width,
        y1: height,
    };

    let opacity = u8::from(opacity);
    let mut output = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height)?;
    let output_stride = output.get_stride() as usize;

    {
        let mut output_data = output.get_data().unwrap();

        for (x, y, pixel) in Pixels::new(&surface, bounds) {
            output_data.set_pixel(output_stride, pixel.to_mask(opacity), x, y);
        }
    }

    Ok(output)
}

impl NodeTrait for NodeMask {
    fn set_atts(&self, _: &RsvgNode, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(attr.parse(value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(attr.parse(value, LengthDir::Vertical)?),
                Attribute::Width => self.width.set(attr.parse_and_validate(
                    value,
                    LengthDir::Horizontal,
                    Length::check_nonnegative,
                )?),
                Attribute::Height => self.height.set(attr.parse_and_validate(
                    value,
                    LengthDir::Vertical,
                    Length::check_nonnegative,
                )?),
                Attribute::MaskUnits => self.units.set(attr.parse(value, ())?),
                Attribute::MaskContentUnits => self.content_units.set(attr.parse(value, ())?),
                _ => (),
            }
        }

        Ok(())
    }
}
<commit_msg>NodeMask: separate the functions to get the default x/y/width/height<commit_after>use cairo::{self, MatrixTrait};
use std::cell::Cell;

use attributes::Attribute;
use coord_units::CoordUnits;
use drawing_ctx::DrawingCtx;
use error::RenderingError;
use length::{Length, LengthDir};
use node::{NodeResult, NodeTrait, RsvgNode};
use parsers::{Parse, ParseValue};
use properties::Opacity;
use property_bag::PropertyBag;
use rect::IRect;
use surface_utils::{
    iterators::Pixels,
    shared_surface::SharedImageSurface,
    shared_surface::SurfaceType,
    ImageSurfaceDataExt,
};
use unit_interval::UnitInterval;

coord_units!(MaskUnits, CoordUnits::ObjectBoundingBox);
coord_units!(MaskContentUnits, CoordUnits::UserSpaceOnUse);

pub struct NodeMask {
    x: Cell<Length>,
    y: Cell<Length>,
    width: Cell<Length>,
    height: Cell<Length>,

    units: Cell<MaskUnits>,
    content_units: Cell<MaskContentUnits>,
}

impl NodeMask {
    pub fn new() -> NodeMask {
        NodeMask {
            x: Cell::new(Self::default_x()),
            y: Cell::new(Self::default_y()),

            width: Cell::new(Self::default_width()),
            height: Cell::new(Self::default_height()),

            units: Cell::new(MaskUnits::default()),
            content_units: Cell::new(MaskContentUnits::default()),
        }
    }

    fn default_x() -> Length {
        // per the spec
        Length::parse_str("-10%", LengthDir::Horizontal).unwrap()
    }

    fn default_y() -> Length {
        // per the spec
        Length::parse_str("-10%", LengthDir::Vertical).unwrap()
    }

    fn default_width() -> Length {
        // per the spec
        Length::parse_str("120%", LengthDir::Horizontal).unwrap()
    }

    fn default_height() -> Length {
        // per the spec
        Length::parse_str("120%", LengthDir::Vertical).unwrap()
    }

    pub fn generate_cairo_mask(
        &self,
        node: &RsvgNode,
        affine_before_mask: &cairo::Matrix,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<(), RenderingError> {
        let cascaded = node.get_cascaded_values();
        let values = cascaded.get();

        let width = draw_ctx.get_width() as i32;
        let height = draw_ctx.get_height() as i32;

        let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        let mask_units = CoordUnits::from(self.units.get());
        let content_units = CoordUnits::from(self.content_units.get());

        let (x, y, w, h) = {
            let params = if mask_units == CoordUnits::ObjectBoundingBox {
                draw_ctx.push_view_box(1.0, 1.0)
            } else {
                draw_ctx.get_view_params()
            };

            let x = self.x.get().normalize(&values, &params);
            let y = self.y.get().normalize(&values, &params);
            let w = self.width.get().normalize(&values, &params);
            let h = self.height.get().normalize(&values, &params);

            (x, y, w, h)
        };

        // Use a scope because mask_cr needs to release the
        // reference to the surface before we access the pixels
        {
            let bbox_rect = {
                if let Some(ref rect) = draw_ctx.get_bbox().rect {
                    *rect
                } else {
                    // The node being masked is empty / doesn't have a
                    // bounding box, so there's nothing to mask!
                    return Ok(());
                }
            };

            let save_cr = draw_ctx.get_cairo_context();

            let mask_cr = cairo::Context::new(&surface);
            mask_cr.set_matrix(*affine_before_mask);
            mask_cr.transform(node.get_transform());

            draw_ctx.set_cairo_context(&mask_cr);

            if mask_units == CoordUnits::ObjectBoundingBox {
                draw_ctx.clip(
                    x * bbox_rect.width + bbox_rect.x,
                    y * bbox_rect.height + bbox_rect.y,
                    w * bbox_rect.width,
                    h * bbox_rect.height,
                );
            } else {
                draw_ctx.clip(x, y, w, h);
            }

            {
                let _params = if content_units == CoordUnits::ObjectBoundingBox {
                    let bbtransform = cairo::Matrix::new(
                        bbox_rect.width,
                        0.0,
                        0.0,
                        bbox_rect.height,
                        bbox_rect.x,
                        bbox_rect.y,
                    );

                    mask_cr.transform(bbtransform);

                    draw_ctx.push_view_box(1.0, 1.0)
                } else {
                    draw_ctx.get_view_params()
                };

                let res = draw_ctx.with_discrete_layer(node, values, false, &mut |dc| {
                    node.draw_children(&cascaded, dc, false)
                });

                draw_ctx.set_cairo_context(&save_cr);

                res
            }
        }?;

        let Opacity(opacity) = values.opacity;
        let mask_surface = compute_luminance_to_alpha(surface, opacity)?;
        draw_ctx.mask_surface(&mask_surface);

        Ok(())
    }
}

// Returns a surface whose alpha channel for each pixel is equal to the
// luminance of that pixel's unpremultiplied RGB values.  The resulting
// surface's RGB values are not meanignful; only the alpha channel has
// useful luminance data.
//
// This is to get a mask suitable for use with cairo_mask_surface().
fn compute_luminance_to_alpha(
    surface: cairo::ImageSurface,
    opacity: UnitInterval,
) -> Result<cairo::ImageSurface, cairo::Status> {
    let surface = SharedImageSurface::new(surface, SurfaceType::SRgb)?;

    let width = surface.width();
    let height = surface.height();

    let bounds = IRect {
        x0: 0,
        y0: 0,
        x1: width,
        y1: height,
    };

    let opacity = u8::from(opacity);
    let mut output = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height)?;
    let output_stride = output.get_stride() as usize;

    {
        let mut output_data = output.get_data().unwrap();

        for (x, y, pixel) in Pixels::new(&surface, bounds) {
            output_data.set_pixel(output_stride, pixel.to_mask(opacity), x, y);
        }
    }

    Ok(output)
}

impl NodeTrait for NodeMask {
    fn set_atts(&self, _: &RsvgNode, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(attr.parse(value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(attr.parse(value, LengthDir::Vertical)?),
                Attribute::Width => self.width.set(attr.parse_and_validate(
                    value,
                    LengthDir::Horizontal,
                    Length::check_nonnegative,
                )?),
                Attribute::Height => self.height.set(attr.parse_and_validate(
                    value,
                    LengthDir::Vertical,
                    Length::check_nonnegative,
                )?),
                Attribute::MaskUnits => self.units.set(attr.parse(value, ())?),
                Attribute::MaskContentUnits => self.content_units.set(attr.parse(value, ())?),
                _ => (),
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use module::Module;
use super::parser::{FileHeaderParser, Parser, ParserError};
use storage::file_id::*;

use regex::Regex;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: String, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Vec<FileHeaderSpec> },
}

#[derive(Debug)]
#[derive(Clone)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

impl FileHeaderData {

    pub fn matches_with(&self, r: &Regex) -> bool {
        match self {
            &FileHeaderData::Text(ref t) => r.is_match(&t[..]),
            &FileHeaderData::Key{name: ref n, value: ref val} => {
                r.is_match(n) || val.matches_with(r)
            },

            &FileHeaderData::Map{keys: ref dks} => {
                dks.iter().any(|x| x.matches_with(r))
            },

            &FileHeaderData::Array{values: ref vs} => {
                vs.iter().any(|x| x.matches_with(r))
            }

            _ => false,
        }
    }
}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    debug!("Start matching:\n'{:?}'\non\n{:?}", spec, data);
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            debug!("Matching Key: '{:?}' == '{:?}', Value: '{:?}' == '{:?}'",
                    kname, n,
                    vtype, val);
            if kname != n {
                debug!("Keys not matching");
                unimplemented!();
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            debug!("Matching Map: '{:?}' == '{:?}'", sks, dks);

            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            debug!("Matching Array: '{:?}' == '{:?}'", vtypes, vs);
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File<'a> {
    owning_module   : &'a Module,
    header          : FileHeaderData,
    data            : String,
    id              : FileID,
}

impl<'a> File<'a> {

    pub fn new(module: &'a Module) -> File<'a> {
        let f = File {
            owning_module: module,
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object: {:?}", f);
        f
    }

    pub fn from_parser_result(module: &Module, id: FileID, header: FileHeaderData, data: String) -> File {
        let f = File {
            owning_module: module,
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        f
    }

    pub fn new_with_header(module: &Module, h: FileHeaderData) -> File {
        let f = File {
            owning_module: module,
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        f
    }

    pub fn new_with_data(module: &Module, d: String) -> File {
        let f = File {
            owning_module: module,
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        f
    }

    pub fn new_with_content(module: &Module, h: FileHeaderData, d: String) -> File {
        let f = File {
            owning_module: module,
            header: h,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        f
    }

    pub fn header(&self) -> FileHeaderData {
        self.header.clone()
    }

    pub fn data(&self) -> String {
        self.data.clone()
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header(), self.data())
    }

    pub fn id(&self) -> FileID {
        self.id.clone()
    }

    pub fn owner(&self) -> &Module {
        self.owning_module
    }

    pub fn matches_with(&self, r: &Regex) -> bool {
        r.is_match(&self.data[..]) || self.header.matches_with(r)
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        FileID::new(FileIDType::UUID, Uuid::new_v4().to_hyphenated_string())
    }
}

impl<'a> Display for File<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

impl<'a> Debug for File<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}
<commit_msg>Add missing Clone for FileHeaderSpec<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use module::Module;
use super::parser::{FileHeaderParser, Parser, ParserError};
use storage::file_id::*;

use regex::Regex;

#[derive(Debug)]
#[derive(Clone)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: String, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Vec<FileHeaderSpec> },
}

#[derive(Debug)]
#[derive(Clone)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

impl FileHeaderData {

    pub fn matches_with(&self, r: &Regex) -> bool {
        match self {
            &FileHeaderData::Text(ref t) => r.is_match(&t[..]),
            &FileHeaderData::Key{name: ref n, value: ref val} => {
                r.is_match(n) || val.matches_with(r)
            },

            &FileHeaderData::Map{keys: ref dks} => {
                dks.iter().any(|x| x.matches_with(r))
            },

            &FileHeaderData::Array{values: ref vs} => {
                vs.iter().any(|x| x.matches_with(r))
            }

            _ => false,
        }
    }
}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    debug!("Start matching:\n'{:?}'\non\n{:?}", spec, data);
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            debug!("Matching Key: '{:?}' == '{:?}', Value: '{:?}' == '{:?}'",
                    kname, n,
                    vtype, val);
            if kname != n {
                debug!("Keys not matching");
                unimplemented!();
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            debug!("Matching Map: '{:?}' == '{:?}'", sks, dks);

            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            debug!("Matching Array: '{:?}' == '{:?}'", vtypes, vs);
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File<'a> {
    owning_module   : &'a Module,
    header          : FileHeaderData,
    data            : String,
    id              : FileID,
}

impl<'a> File<'a> {

    pub fn new(module: &'a Module) -> File<'a> {
        let f = File {
            owning_module: module,
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object: {:?}", f);
        f
    }

    pub fn from_parser_result(module: &Module, id: FileID, header: FileHeaderData, data: String) -> File {
        let f = File {
            owning_module: module,
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        f
    }

    pub fn new_with_header(module: &Module, h: FileHeaderData) -> File {
        let f = File {
            owning_module: module,
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        f
    }

    pub fn new_with_data(module: &Module, d: String) -> File {
        let f = File {
            owning_module: module,
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        f
    }

    pub fn new_with_content(module: &Module, h: FileHeaderData, d: String) -> File {
        let f = File {
            owning_module: module,
            header: h,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        f
    }

    pub fn header(&self) -> FileHeaderData {
        self.header.clone()
    }

    pub fn data(&self) -> String {
        self.data.clone()
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header(), self.data())
    }

    pub fn id(&self) -> FileID {
        self.id.clone()
    }

    pub fn owner(&self) -> &Module {
        self.owning_module
    }

    pub fn matches_with(&self, r: &Regex) -> bool {
        r.is_match(&self.data[..]) || self.header.matches_with(r)
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        FileID::new(FileIDType::UUID, Uuid::new_v4().to_hyphenated_string())
    }
}

impl<'a> Display for File<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

impl<'a> Debug for File<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}
<|endoftext|>


<commit_before>use crate::utils::{match_qpath, paths, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
    ///
    /// **Why is this bad?** Sometimes `std::fs::crate_dir` is mistakenly chosen over `std::fs::create_dir_all`.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// std::fs::create_dir("foo")
    /// ```
    /// Use instead:
    /// ```rust
    /// std::fs::create_dir_all("foo")
    /// ```
    pub CREATE_DIR,
    restriction,
    "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`"
}

declare_lint_pass!(CreateDir => [CREATE_DIR]);

impl LateLintPass<'_> for CreateDir {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        if_chain! {
            if let ExprKind::Call(ref func, ref args) = expr.kind;
            if let ExprKind::Path(ref path) = func.kind;
            if match_qpath(path, &paths::STD_FS_CREATE_DIR);
            then {
                span_lint_and_sugg(
                    cx,
                    CREATE_DIR,
                    expr.span,
                    "calling `std::fs::create_dir` where there may be a better way",
                    "consider calling `std::fs::create_dir_all` instead",
                    format!("std::fs::create_dir_all({})", snippet(cx, args[0].span, "..")),
                    Applicability::MachineApplicable,
                )
            }
        }
    }
}
<commit_msg>Fix errors<commit_after>use crate::utils::{match_qpath, paths, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
    ///
    /// **Why is this bad?** Sometimes `std::fs::crate_dir` is mistakenly chosen over `std::fs::create_dir_all`.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// std::fs::create_dir("foo");
    /// ```
    /// Use instead:
    /// ```rust
    /// std::fs::create_dir_all("foo");
    /// ```
    pub CREATE_DIR,
    restriction,
    "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`"
}

declare_lint_pass!(CreateDir => [CREATE_DIR]);

impl LateLintPass<'_> for CreateDir {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        if_chain! {
            if let ExprKind::Call(ref func, ref args) = expr.kind;
            if let ExprKind::Path(ref path) = func.kind;
            if match_qpath(path, &paths::STD_FS_CREATE_DIR);
            then {
                span_lint_and_sugg(
                    cx,
                    CREATE_DIR,
                    expr.span,
                    "calling `std::fs::create_dir` where there may be a better way",
                    "consider calling `std::fs::create_dir_all` instead",
                    format!("std::fs::create_dir_all({})", snippet(cx, args[0].span, "..")),
                    Applicability::MachineApplicable,
                )
            }
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(any(target_os = "linux", target_os = "android"))]
mod epoll;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::epoll::{Events, Selector};

#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd",
    target_os = "dragonfly", target_os = "netbsd",))]
mod kqueue;

#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd",
    target_os = "dragonfly", target_os = "netbsd",))]
pub use self::kqueue::{Events, Selector};

mod awakener;
mod eventedfd;
mod io;
mod net;
mod socket;
mod tcp;
mod udp;
mod uds;

pub use self::awakener::Awakener;
pub use self::eventedfd::EventedFd;
pub use self::io::Io;
pub use self::socket::Socket;
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;
pub use self::uds::UnixSocket;

pub fn pipe() -> ::io::Result<(Io, Io)> {
    use nix::fcntl::{O_NONBLOCK, O_CLOEXEC};
    use nix::unistd::pipe2;

    let (rd, wr) = try!(pipe2(O_NONBLOCK | O_CLOEXEC)
        .map_err(from_nix_error));

    Ok((Io::from_raw_fd(rd), Io::from_raw_fd(wr)))
}

pub fn from_nix_error(err: ::nix::Error) -> ::io::Error {
    ::io::Error::from_raw_os_error(err.errno() as i32)
}

mod nix {
    pub use nix::{
        c_int,
        Error,
    };
    pub use nix::errno::{EINPROGRESS, EAGAIN};
    pub use nix::fcntl::{fcntl, FcntlArg, O_NONBLOCK};
    pub use nix::sys::socket::{
        sockopt,
        AddressFamily,
        SockAddr,
        SockType,
        SockLevel,
        InetAddr,
        Ipv4Addr,
        Ipv6Addr,
        ControlMessage,
        CmsgSpace,
        MSG_DONTWAIT,
        SOCK_NONBLOCK,
        SOCK_CLOEXEC,
        accept4,
        bind,
        connect,
        getpeername,
        getsockname,
        getsockopt,
        ip_mreq,
        ipv6_mreq,
        linger,
        listen,
        recvfrom,
        recvmsg,
        sendto,
        sendmsg,
        setsockopt,
        socket,
        shutdown,
        Shutdown,
    };
    pub use nix::sys::time::TimeVal;
    pub use nix::sys::uio::IoVec;
    pub use nix::unistd::{
        read,
        write,
        dup,
    };
}
<commit_msg>Choose kqueue for OpenBSD family<commit_after>#[cfg(any(target_os = "linux", target_os = "android"))]
mod epoll;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::epoll::{Events, Selector};

#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
    target_os = "freebsd", target_os = "ios", target_os = "macos",
    target_os = "netbsd", target_os = "openbsd"))]
mod kqueue;

#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
    target_os = "freebsd", target_os = "ios", target_os = "macos",
    target_os = "netbsd", target_os = "openbsd"))]
pub use self::kqueue::{Events, Selector};

mod awakener;
mod eventedfd;
mod io;
mod net;
mod socket;
mod tcp;
mod udp;
mod uds;

pub use self::awakener::Awakener;
pub use self::eventedfd::EventedFd;
pub use self::io::Io;
pub use self::socket::Socket;
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;
pub use self::uds::UnixSocket;

pub fn pipe() -> ::io::Result<(Io, Io)> {
    use nix::fcntl::{O_NONBLOCK, O_CLOEXEC};
    use nix::unistd::pipe2;

    let (rd, wr) = try!(pipe2(O_NONBLOCK | O_CLOEXEC)
        .map_err(from_nix_error));

    Ok((Io::from_raw_fd(rd), Io::from_raw_fd(wr)))
}

pub fn from_nix_error(err: ::nix::Error) -> ::io::Error {
    ::io::Error::from_raw_os_error(err.errno() as i32)
}

mod nix {
    pub use nix::{
        c_int,
        Error,
    };
    pub use nix::errno::{EINPROGRESS, EAGAIN};
    pub use nix::fcntl::{fcntl, FcntlArg, O_NONBLOCK};
    pub use nix::sys::socket::{
        sockopt,
        AddressFamily,
        SockAddr,
        SockType,
        SockLevel,
        InetAddr,
        Ipv4Addr,
        Ipv6Addr,
        ControlMessage,
        CmsgSpace,
        MSG_DONTWAIT,
        SOCK_NONBLOCK,
        SOCK_CLOEXEC,
        accept4,
        bind,
        connect,
        getpeername,
        getsockname,
        getsockopt,
        ip_mreq,
        ipv6_mreq,
        linger,
        listen,
        recvfrom,
        recvmsg,
        sendto,
        sendmsg,
        setsockopt,
        socket,
        shutdown,
        Shutdown,
    };
    pub use nix::sys::time::TimeVal;
    pub use nix::sys::uio::IoVec;
    pub use nix::unistd::{
        read,
        write,
        dup,
    };
}
<|endoftext|>


<commit_before>use {
    BackEnd,
    Borrowed,
    CanTransform,
    Color,
    Draw,
    Field,
    HasTransform,
    Image,
    Matrix2d,
    Rectangle,
    RelativeRectangle,
    Value,
    View,
};
use vecmath::{
    identity,
    margin_rectangle,
    relative_rectangle,
};
use triangulation::{
    rect_tri_list_xy_f32,
    rect_tri_list_rgba_f32,
    rect_tri_list_uv_f32,
};

/// An image rectangle context.
pub struct ImageRectangleColorContext<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current image.
    pub image: Field<'a, Image>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> HasTransform<'a, Matrix2d> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, ImageRectangleColorContext<'a>, Matrix2d> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> Draw<'a> for ImageRectangleColorContext<'a> {
    fn draw<B: BackEnd>(&'a self, back_end: &mut B) {
        if back_end.supports_single_texture()
        && back_end.supports_tri_list_xy_f32_rgba_f32_uv_f32() {
            let rect = self.rect.get();
            let color = self.color.get();
            let color: [f32, ..4] = [color[0], color[1], color[2], color[3]];
            let texture_id = self.image.get().texture_id;
            // Complete transparency does not need to be rendered.
            if color[3] == 0.0 { return; }
            // Turn on alpha blending if not completely opaque or if the texture has alpha channel.
            let needs_alpha = color[3] != 1.0 || back_end.has_texture_alpha(texture_id);
            if needs_alpha { back_end.enable_alpha_blend(); }
            back_end.enable_single_texture(texture_id);
            back_end.tri_list_xy_f32_rgba_f32_uv_f32(
                rect_tri_list_xy_f32(self.transform.get(), rect),
                rect_tri_list_rgba_f32(color),
                rect_tri_list_uv_f32(self.image.get())
            );
            back_end.disable_single_texture();
            if needs_alpha { back_end.disable_alpha_blend(); }
        } else {
            unimplemented!();
        }
    }
}

impl<'a> RelativeRectangle<'a> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn margin(&'a self, m: f64) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            image: Borrowed(self.image.get()),
            rect: Value(margin_rectangle(self.rect.get(), m)),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn rel(&'a self, x: f64, y: f64) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            image: Borrowed(self.image.get()),
            rect: Value(relative_rectangle(self.rect.get(), x, y)),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> View<'a> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

<commit_msg>Implemented `HasColor` and `CanColor` for `ImageRectangleColorContext`<commit_after>use {
    BackEnd,
    Borrowed,
    CanColor,
    CanTransform,
    Color,
    Draw,
    Field,
    HasColor,
    HasTransform,
    Image,
    Matrix2d,
    Rectangle,
    RelativeRectangle,
    Value,
    View,
};
use vecmath::{
    identity,
    margin_rectangle,
    relative_rectangle,
};
use triangulation::{
    rect_tri_list_xy_f32,
    rect_tri_list_rgba_f32,
    rect_tri_list_uv_f32,
};

/// An image rectangle context.
pub struct ImageRectangleColorContext<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current image.
    pub image: Field<'a, Image>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> HasTransform<'a, Matrix2d> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, ImageRectangleColorContext<'a>, Matrix2d> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, ImageRectangleColorContext<'a>, Color> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
        }
    }
}

impl<'a> Draw<'a> for ImageRectangleColorContext<'a> {
    fn draw<B: BackEnd>(&'a self, back_end: &mut B) {
        if back_end.supports_single_texture()
        && back_end.supports_tri_list_xy_f32_rgba_f32_uv_f32() {
            let rect = self.rect.get();
            let color = self.color.get();
            let color: [f32, ..4] = [color[0], color[1], color[2], color[3]];
            let texture_id = self.image.get().texture_id;
            // Complete transparency does not need to be rendered.
            if color[3] == 0.0 { return; }
            // Turn on alpha blending if not completely opaque or if the texture has alpha channel.
            let needs_alpha = color[3] != 1.0 || back_end.has_texture_alpha(texture_id);
            if needs_alpha { back_end.enable_alpha_blend(); }
            back_end.enable_single_texture(texture_id);
            back_end.tri_list_xy_f32_rgba_f32_uv_f32(
                rect_tri_list_xy_f32(self.transform.get(), rect),
                rect_tri_list_rgba_f32(color),
                rect_tri_list_uv_f32(self.image.get())
            );
            back_end.disable_single_texture();
            if needs_alpha { back_end.disable_alpha_blend(); }
        } else {
            unimplemented!();
        }
    }
}

impl<'a> RelativeRectangle<'a> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn margin(&'a self, m: f64) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            image: Borrowed(self.image.get()),
            rect: Value(margin_rectangle(self.rect.get(), m)),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn rel(&'a self, x: f64, y: f64) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            image: Borrowed(self.image.get()),
            rect: Value(relative_rectangle(self.rect.get(), x, y)),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> View<'a> for ImageRectangleColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            image: Borrowed(self.image.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

<|endoftext|>


<commit_before>extern crate green_moon;

use green_moon::{ANIMATE_NONE, ANIMATE_ONCE, ANIMATE_LOOP, ANIMATE_PING_PONG};
use green_moon::AnimationBuilder;

#[test]
fn test_animate_none() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];

    // ANIMATE_NONE is the default
    let mut animation = AnimationBuilder::new()
        .set_frames(frames)
        .build().unwrap();

    // Should not advance since we have ANIMATE_NONE
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_none2() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];

    // Set ANIMATE_NONE explicitply
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_NONE)
        .set_frames(frames)
        .build().unwrap();

    // Should not advance since we have ANIMATE_NONE
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_once() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 21);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);

    // End of animation reached, only the last frame should be shown from now on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 22);
}

#[test]
fn test_animate_once_single_rame() {
    let frames = vec![(20, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on, but last frame already reached
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_loop() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_LOOP)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 21);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);

    // End of animation reached, start from beginning
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
}

#[test]
fn test_animate_loop_single_rame() {
    let frames = vec![(20, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_LOOP)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on, but last frame already reached
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_ping_pong() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_PING_PONG)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 21);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);

    // End of animation reached, move backwards
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_ping_pong_single_rame() {
    let frames = vec![(20, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on, but last frame already reached
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_reset() {
    let frames = vec![(20, 100), (21, 100), (22, 100), (23, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);

    // Should restart animation from beginning
    animation.reset();

    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);

    // Should restart animation from beginning
    animation.reset();

    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);

}

#[test]
fn test_pause_resume() {
    let frames = vec![(20, 100), (21, 100), (22, 100), (23, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);

    // Animation should not advance after call to pause
    animation.pause();

    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);

    // Now it should go on
    animation.resume();

    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
}
<commit_msg>add more test cases for animation<commit_after>extern crate green_moon;

use green_moon::{ANIMATE_NONE, ANIMATE_ONCE, ANIMATE_LOOP, ANIMATE_PING_PONG};
use green_moon::AnimationBuilder;

#[test]
fn test_animate_none() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];

    // ANIMATE_NONE is the default
    let mut animation = AnimationBuilder::new()
        .set_frames(frames)
        .build().unwrap();

    // Should not advance since we have ANIMATE_NONE
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_none2() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];

    // Set ANIMATE_NONE explicitply
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_NONE)
        .set_frames(frames)
        .build().unwrap();

    // Should not advance since we have ANIMATE_NONE
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_once() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 21);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);

    // End of animation reached, only the last frame should be shown from now on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 22);
}

#[test]
fn test_animate_once_single_rame() {
    let frames = vec![(20, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on, but last frame already reached
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_loop() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_LOOP)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 21);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);

    // End of animation reached, start from beginning
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
}

#[test]
fn test_animate_loop_single_rame() {
    let frames = vec![(20, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_LOOP)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on, but last frame already reached
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_ping_pong() {
    let frames = vec![(20, 100), (21, 100), (22, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_PING_PONG)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 21);

    // Now the animation should move on
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);

    // End of animation reached, move backwards
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_animate_ping_pong_single_rame() {
    let frames = vec![(20, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    // Elapsed time < frame duration, so should not advance
    animation.next(0);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);

    // Now the animation should move on, but last frame already reached
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(50);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(99);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(200);
    assert_eq!(animation.get_sprite_index(), 20);
}

#[test]
fn test_reset() {
    let frames = vec![(20, 100), (21, 100), (22, 100), (23, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);

    // Should restart animation from beginning
    animation.reset();

    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);

    // Should restart animation from beginning
    animation.reset();

    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
}

#[test]
fn test_pause_resume() {
    let frames = vec![(20, 100), (21, 100), (22, 100), (23, 100)];
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .set_frames(frames)
        .build().unwrap();

    assert_eq!(animation.get_sprite_index(), 20);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);

    // Animation should not advance after call to pause
    animation.pause();

    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 21);

    // Now it should go on
    animation.resume();

    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 22);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 23);
}

#[test]
fn test_add_frame() {
    let mut animation = AnimationBuilder::new()
        .animation_type(ANIMATE_ONCE)
        .add_frame((40, 150))
        .add_frame((41, 100))
        .add_frame((42, 180))
        .add_frame((43, 210))
        .build().unwrap();

    assert_eq!(animation.get_sprite_index(), 40);
    animation.next(150);
    assert_eq!(animation.get_sprite_index(), 41);
    animation.next(100);
    assert_eq!(animation.get_sprite_index(), 42);
    animation.next(150);
    assert_eq!(animation.get_sprite_index(), 42);
    animation.next(300);
    assert_eq!(animation.get_sprite_index(), 43);
}
<|endoftext|>


<commit_before>use common::{Body, Method, Version};
use headers::Headers;

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidRequest,
}

#[derive(PartialEq)]
struct RequestLine {
    method: Method,
    uri: String,
    http_version: Version,
}

impl RequestLine {
    fn try_from(byte_stream: &[u8]) -> Result<Self, Error> {
        let method_len = helpers::request_line::check_method(byte_stream)?;
        let version_len = helpers::request_line::check_http_version(byte_stream)?;

        let request_uri =
            helpers::request_line::get_request_uri(byte_stream, method_len, version_len)?;

        Ok(RequestLine {
            http_version: Version::Http10,
            method: Method::Get,
            uri: request_uri,
        })
    }
}

#[allow(unused)]
pub struct Request {
    request_line: RequestLine,
    headers: Headers,
    body: Option<Body>,
}

impl Request {
    /// Parses a byte slice into a HTTP Request.
    /// The byte slice is expected to have the following format: </br>
    ///     * Request Line: "GET SP Request-uri SP HTTP/1.0 CRLF" - Mandatory </br>
    ///     * Request Headers "<headers> CRLF"- Optional </br>
    ///     * Entity Body - Optional </br>
    /// The request headers and the entity body is not parsed and None is returned because
    /// these are not used by the MMDS server.
    /// The only supported method is GET and the HTTP protocol is expected to be HTTP/1.0.
    ///
    /// # Errors
    /// The function returns InvalidRequest when parsing the byte stream fails.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate micro_http;
    /// use micro_http::Request;
    ///
    /// let http_request = Request::try_from(b"GET http://localhost/home HTTP/1.0\r\n");
    ///
    pub fn try_from(byte_stream: &[u8]) -> Result<Self, Error> {
        // The first line of the request is the Request Line. The line ending is LF.
        let lf_pos = helpers::request::get_first_lf(byte_stream)?;

        // The Request Line should include the trailing LF.
        let request_line = RequestLine::try_from(&byte_stream[0..=lf_pos])?;
        // We ignore the Headers and Entity body because we don't need them for MMDS requests.
        Ok(Request {
            request_line,
            headers: Headers::default(),
            body: None,
        })
    }
}

mod helpers {
    use super::{Error, Method, Version};
    use ascii::{CRLF, LF, SP};

    // Module used for grouping functions that parse a Request.
    pub mod request {
        use super::*;

        // Helper function that returns the first position of the LF character in a u8 slice.
        // Returns Error::InvalidRequest if LF is not found.
        pub fn get_first_lf(byte_stream: &[u8]) -> Result<usize, Error> {
            for i in 0..byte_stream.len() {
                if byte_stream[i] == LF[0] {
                    return Ok(i);
                }
            }
            return Err(Error::InvalidRequest);
        }
    }

    // Module used for grouping functions that parse a RequestLine.
    pub mod request_line {
        use super::*;
        use std;

        // Checks that the HTTP method is correct (only GET is supported).
        // When the method is correct, returns the length of the method + 1, where the additional 1
        // is the length of SP character.
        pub fn check_method(byte_stream: &[u8]) -> Result<usize, Error> {
            // The first 3 characters from the request line should be the method.
            // We only support GET requests. Check that the first three letters are GET, followed
            // by SP.
            let request_line_prefix = [Method::Get.raw(), SP].concat();

            if byte_stream.starts_with(request_line_prefix.as_slice()) {
                return Ok(request_line_prefix.len());
            }

            return Err(Error::InvalidRequest);
        }

        // Checks that the HTTP version is 1.0. When the version is correct, it returns the length
        // of the suffix defined as "SP HTTP_Version CRLF/LF".
        pub fn check_http_version(byte_stream: &[u8]) -> Result<usize, Error> {
            let http_version = Version::Http10.raw();

            let line_suffix_with_crlf = [SP, http_version.clone(), CRLF].concat();
            let line_suffix_with_lf = [SP, http_version, LF].concat();

            if byte_stream.ends_with(line_suffix_with_crlf.as_slice()) {
                return Ok(line_suffix_with_crlf.len());
            }

            if byte_stream.ends_with(line_suffix_with_lf.as_slice()) {
                return Ok(line_suffix_with_lf.len());
            }

            return Err(Error::InvalidRequest);
        }

        // Returns the request URI.
        // The prefix should be GET SP and the suffix one of SP HTTP/1.0 CRLF or SP HTTP/1.0 LF.
        // TODO: we need some validation of the URI.
        pub fn get_request_uri(
            byte_stream: &[u8],
            prefix_len: usize,
            suffix_len: usize,
        ) -> Result<String, Error> {
            if prefix_len + suffix_len >= byte_stream.len() {
                return Err(Error::InvalidRequest);
            }

            match std::str::from_utf8(&byte_stream[prefix_len..(byte_stream.len() - suffix_len)]) {
                Ok(request_uri) => Ok(String::from(request_uri)),
                Err(_) => Err(Error::InvalidRequest),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::helpers::request_line::{check_http_version, check_method, get_request_uri};
    use super::*;

    impl PartialEq for Request {
        fn eq(&self, other: &Request) -> bool {
            // Ignore the other fields of Request for now because they are not used.
            return self.request_line == other.request_line;
        }
    }

    #[test]
    fn test_check_http_method() {
        let request_line = b"GET http://localhost/home HTTP/1.0\r\n";
        match check_method(request_line) {
            Ok(len) => assert_eq!(len, 4),
            Err(_) => assert!(false),
        };

        let request_line = b"PUT http://localhost/home HTTP/1.0\r\n";
        assert!(check_method(request_line).is_err());

        assert!(check_method(b"").is_err());
    }

    #[test]
    fn test_check_http_version() {
        // Test CRLF ending for Request Line.
        let request_line = b"GET http://localhost/home HTTP/1.0\r\n";
        let expected_http_version = b" HTTP/1.0\r\n";
        match check_http_version(request_line) {
            Ok(val) => assert_eq!(val, expected_http_version.len()),
            Err(_) => assert!(false),
        };

        // Test LF ending for Request Line.
        let request_line = b"GET http://localhost/home HTTP/1.0\n";
        let expected_http_version = b" HTTP/1.0\n";
        match check_http_version(request_line) {
            Ok(val) => assert_eq!(val, expected_http_version.len()),
            Err(_) => assert!(false),
        };

        // Test Invalid HTTP version.
        let request_line = b"GET http://localhost/home HTTP/1.1\n";
        match check_http_version(request_line) {
            Ok(_) => assert!(false),
            Err(e) => assert_eq!(e, Error::InvalidRequest),
        };

        assert!(check_http_version(b"").is_err());
    }

    #[test]
    fn test_get_request_uri() {
        let request_line = b"GET http://localhost/home HTTP/1.0\r\n";
        let prefix = b"GET ";
        let suffix = b" HTTP/1.0\r\n";
        let request_uri = String::from("http://localhost/home");

        match get_request_uri(request_line, prefix.len(), suffix.len()) {
            Ok(req_uri) => assert_eq!(req_uri, request_uri),
            Err(_) => assert!(false),
        };

        assert!(get_request_uri(request_line, 50, 50).is_err());
    }

    #[test]
    fn test_into_request_line() {
        let expected_request_line = RequestLine {
            http_version: Version::Http10,
            method: Method::Get,
            uri: String::from("http://localhost/home"),
        };

        let request_line = b"GET http://localhost/home HTTP/1.0\r\n";
        match RequestLine::try_from(request_line) {
            Ok(request) => assert!(request == expected_request_line),
            Err(_) => assert!(false),
        };

        // Test for invalid method.
        let request_line = b"PUT http://localhost/home HTTP/1.0\r\n";
        assert!(RequestLine::try_from(request_line).is_err());

        // Test for invalid uri.
        let request_line = b"GET  HTTP/1.0\r\n";
        assert!(RequestLine::try_from(request_line).is_err());

        // Test for invalid HTTP version.
        let request_line = b"GET http://localhost/home HTTP/2.0\r\n";
        assert!(RequestLine::try_from(request_line).is_err());
    }

    #[test]
    fn test_into_request() {
        let expected_request = Request {
            request_line: RequestLine {
                http_version: Version::Http10,
                method: Method::Get,
                uri: String::from("http://localhost/home"),
            },
            body: None,
            headers: Headers::default(),
        };
        let request_bytes = b"GET http://localhost/home HTTP/1.0\r\n \
                                     Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT";
        assert!(Request::try_from(request_bytes) == Ok(expected_request));
    }
}
<commit_msg>micro_http: add getter for Request uri<commit_after>use common::{Body, Method, Version};
use headers::Headers;

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidRequest,
}

#[derive(PartialEq)]
struct RequestLine {
    method: Method,
    uri: String,
    http_version: Version,
}

impl RequestLine {
    fn try_from(byte_stream: &[u8]) -> Result<Self, Error> {
        let method_len = helpers::request_line::check_method(byte_stream)?;
        let version_len = helpers::request_line::check_http_version(byte_stream)?;

        let request_uri =
            helpers::request_line::get_request_uri(byte_stream, method_len, version_len)?;

        Ok(RequestLine {
            http_version: Version::Http10,
            method: Method::Get,
            uri: request_uri,
        })
    }
}

#[allow(unused)]
pub struct Request {
    request_line: RequestLine,
    headers: Headers,
    body: Option<Body>,
}

impl Request {
    /// Parses a byte slice into a HTTP Request.
    /// The byte slice is expected to have the following format: </br>
    ///     * Request Line: "GET SP Request-uri SP HTTP/1.0 CRLF" - Mandatory </br>
    ///     * Request Headers "<headers> CRLF"- Optional </br>
    ///     * Entity Body - Optional </br>
    /// The request headers and the entity body is not parsed and None is returned because
    /// these are not used by the MMDS server.
    /// The only supported method is GET and the HTTP protocol is expected to be HTTP/1.0.
    ///
    /// # Errors
    /// The function returns InvalidRequest when parsing the byte stream fails.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate micro_http;
    /// use micro_http::Request;
    ///
    /// let http_request = Request::try_from(b"GET http://localhost/home HTTP/1.0\r\n");
    ///
    pub fn try_from(byte_stream: &[u8]) -> Result<Self, Error> {
        // The first line of the request is the Request Line. The line ending is LF.
        let lf_pos = helpers::request::get_first_lf(byte_stream)?;

        // The Request Line should include the trailing LF.
        let request_line = RequestLine::try_from(&byte_stream[0..=lf_pos])?;
        // We ignore the Headers and Entity body because we don't need them for MMDS requests.
        Ok(Request {
            request_line,
            headers: Headers::default(),
            body: None,
        })
    }

    pub fn get_uri(&self) -> String {
        self.request_line.uri.clone()
    }
}

mod helpers {
    use super::{Error, Method, Version};
    use ascii::{CRLF, LF, SP};

    // Module used for grouping functions that parse a Request.
    pub mod request {
        use super::*;

        // Helper function that returns the first position of the LF character in a u8 slice.
        // Returns Error::InvalidRequest if LF is not found.
        pub fn get_first_lf(byte_stream: &[u8]) -> Result<usize, Error> {
            for i in 0..byte_stream.len() {
                if byte_stream[i] == LF[0] {
                    return Ok(i);
                }
            }
            return Err(Error::InvalidRequest);
        }
    }

    // Module used for grouping functions that parse a RequestLine.
    pub mod request_line {
        use super::*;
        use std;

        // Checks that the HTTP method is correct (only GET is supported).
        // When the method is correct, returns the length of the method + 1, where the additional 1
        // is the length of SP character.
        pub fn check_method(byte_stream: &[u8]) -> Result<usize, Error> {
            // The first 3 characters from the request line should be the method.
            // We only support GET requests. Check that the first three letters are GET, followed
            // by SP.
            let request_line_prefix = [Method::Get.raw(), SP].concat();

            if byte_stream.starts_with(request_line_prefix.as_slice()) {
                return Ok(request_line_prefix.len());
            }

            return Err(Error::InvalidRequest);
        }

        // Checks that the HTTP version is 1.0. When the version is correct, it returns the length
        // of the suffix defined as "SP HTTP_Version CRLF/LF".
        pub fn check_http_version(byte_stream: &[u8]) -> Result<usize, Error> {
            let http_version = Version::Http10.raw();

            let line_suffix_with_crlf = [SP, http_version.clone(), CRLF].concat();
            let line_suffix_with_lf = [SP, http_version, LF].concat();

            if byte_stream.ends_with(line_suffix_with_crlf.as_slice()) {
                return Ok(line_suffix_with_crlf.len());
            }

            if byte_stream.ends_with(line_suffix_with_lf.as_slice()) {
                return Ok(line_suffix_with_lf.len());
            }

            return Err(Error::InvalidRequest);
        }

        // Returns the request URI.
        // The prefix should be GET SP and the suffix one of SP HTTP/1.0 CRLF or SP HTTP/1.0 LF.
        // TODO: we need some validation of the URI.
        pub fn get_request_uri(
            byte_stream: &[u8],
            prefix_len: usize,
            suffix_len: usize,
        ) -> Result<String, Error> {
            if prefix_len + suffix_len >= byte_stream.len() {
                return Err(Error::InvalidRequest);
            }

            match std::str::from_utf8(&byte_stream[prefix_len..(byte_stream.len() - suffix_len)]) {
                Ok(request_uri) => Ok(String::from(request_uri)),
                Err(_) => Err(Error::InvalidRequest),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::helpers::request_line::{check_http_version, check_method, get_request_uri};
    use super::*;

    impl PartialEq for Request {
        fn eq(&self, other: &Request) -> bool {
            // Ignore the other fields of Request for now because they are not used.
            return self.request_line == other.request_line;
        }
    }

    #[test]
    fn test_check_http_method() {
        let request_line = b"GET http://localhost/home HTTP/1.0\r\n";
        match check_method(request_line) {
            Ok(len) => assert_eq!(len, 4),
            Err(_) => assert!(false),
        };

        let request_line = b"PUT http://localhost/home HTTP/1.0\r\n";
        assert!(check_method(request_line).is_err());

        assert!(check_method(b"").is_err());
    }

    #[test]
    fn test_check_http_version() {
        // Test CRLF ending for Request Line.
        let request_line = b"GET http://localhost/home HTTP/1.0\r\n";
        let expected_http_version = b" HTTP/1.0\r\n";
        match check_http_version(request_line) {
            Ok(val) => assert_eq!(val, expected_http_version.len()),
            Err(_) => assert!(false),
        };

        // Test LF ending for Request Line.
        let request_line = b"GET http://localhost/home HTTP/1.0\n";
        let expected_http_version = b" HTTP/1.0\n";
        match check_http_version(request_line) {
            Ok(val) => assert_eq!(val, expected_http_version.len()),
            Err(_) => assert!(false),
        };

        // Test Invalid HTTP version.
        let request_line = b"GET http://localhost/home HTTP/1.1\n";
        match check_http_version(request_line) {
            Ok(_) => assert!(false),
            Err(e) => assert_eq!(e, Error::InvalidRequest),
        };

        assert!(check_http_version(b"").is_err());
    }

    #[test]
    fn test_get_request_uri() {
        let request_line = b"GET http://localhost/home HTTP/1.0\r\n";
        let prefix = b"GET ";
        let suffix = b" HTTP/1.0\r\n";
        let request_uri = String::from("http://localhost/home");

        match get_request_uri(request_line, prefix.len(), suffix.len()) {
            Ok(req_uri) => assert_eq!(req_uri, request_uri),
            Err(_) => assert!(false),
        };

        assert!(get_request_uri(request_line, 50, 50).is_err());
    }

    #[test]
    fn test_into_request_line() {
        let expected_request_line = RequestLine {
            http_version: Version::Http10,
            method: Method::Get,
            uri: String::from("http://localhost/home"),
        };

        let request_line = b"GET http://localhost/home HTTP/1.0\r\n";
        match RequestLine::try_from(request_line) {
            Ok(request) => assert!(request == expected_request_line),
            Err(_) => assert!(false),
        };

        // Test for invalid method.
        let request_line = b"PUT http://localhost/home HTTP/1.0\r\n";
        assert!(RequestLine::try_from(request_line).is_err());

        // Test for invalid uri.
        let request_line = b"GET  HTTP/1.0\r\n";
        assert!(RequestLine::try_from(request_line).is_err());

        // Test for invalid HTTP version.
        let request_line = b"GET http://localhost/home HTTP/2.0\r\n";
        assert!(RequestLine::try_from(request_line).is_err());
    }

    #[test]
    fn test_into_request() {
        let expected_request = Request {
            request_line: RequestLine {
                http_version: Version::Http10,
                method: Method::Get,
                uri: String::from("http://localhost/home"),
            },
            body: None,
            headers: Headers::default(),
        };
        let request_bytes = b"GET http://localhost/home HTTP/1.0\r\n \
                                     Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT";
        assert!(Request::try_from(request_bytes) == Ok(expected_request));
    }
}
<|endoftext|>