<commit_before>#[cfg(target_arch="x86")]
const B: [usize; 5] = [ 0x2, 0xC, 0xF0
                      , 0xFF00
                      , 0xFFFF0000];
#[cfg(target_arch="x86")]
const S: [usize; 5] = [ 1, 2, 4, 8, 16 ];

#[cfg(target_arch="x86_64")]
const B: [usize; 6] = [ 0x2, 0xC, 0xF0
                      , 0xFF00, 0xFFFF0000
                      , 0xFFFFFFFF00000000];
#[cfg(target_arch="x86_64")]
const S: [usize; 6] = [ 1, 2, 4, 8, 16, 32 ];

pub trait PowersOf2 {
    fn is_pow2(&self) -> bool;
    fn next_pow2(&self) -> Self;
    fn log2(&self) -> Self;
}

impl PowersOf2 for usize {
    fn is_pow2(&self) -> bool {
        *self != 0 && self & (self - 1) == 0
    }

    /// Returns the next power of 2
    ///
    /// # Examples:
    /// ```
    /// assert_eq!(1.next_pow2(), 2);
    /// ```
    /// ```
    /// assert_eq!(0.next_pow2(), 1);
    /// ```
    /// ```
    /// assert_eq!(3.next_pow2(), 4);
    /// ```
    /// ```
    /// assert_eq!(5678.next_pow2(), 8192);
    /// ```
    fn next_pow2(&self) -> usize {
        let mut v = *self;
        if v == 0 {
            1
        } else {
            v -= 1;
            v = v | (v >> 1);
            v = v | (v >> 2);
            v = v | (v >> 4);
            v = v | (v >> 8);
            v = v | (v >> 16);
            v + 1
        }
    }

    #[cfg(not(any(target_arch="x86_64", target_arch="x86")))]
    fn log2(&self) -> usize {
        // This is the "obvious" log base 2 implementation. The lookup table
        // -based approach would be much faster, but we can't use it for
        // `usize` since we aren't sure what size a usize is without conditional
        // compilation.
        unimplemented!()
    }

    #[cfg(any(target_arch="x86_64", target_arch="x86"))]
    fn log2(&self) -> usize {
        // // let mut r: usize = 0;
        // // let mut v = *self;
        // S.iter()
        //  .zip(B.iter()) // this purely-functional implementation may be slower
        //  .fold((0, *self), // but it's cute and I had fun figuring it out
        //     |(r, v), (s, b)| if v & b != 0 { (r | s, v >> s) }
        //                      else { (r, v) })
        //   .0
        // // for in 0..S.len() {
        // //     if v & B[i] != 0 {
        // //         v = v >> S[i];
        // //         r = r | S[i];
        // //     }
        // // }
        // // r
        //
        let mut res = 0;
        let mut num = *self;
        loop {
            num >>= 1;

            if num == 0 {
                break;
            }

            res += 1;
        }

        res
    }
}
<commit_msg>[alloc] Better unit tests for powers of 2<commit_after>#[cfg(target_arch="x86")]
const B: [usize; 5] = [ 0x2, 0xC, 0xF0
                      , 0xFF00
                      , 0xFFFF0000];
#[cfg(target_arch="x86")]
const S: [usize; 5] = [ 1, 2, 4, 8, 16 ];

#[cfg(target_arch="x86_64")]
const B: [usize; 6] = [ 0x2, 0xC, 0xF0
                      , 0xFF00, 0xFFFF0000
                      , 0xFFFFFFFF00000000];
#[cfg(target_arch="x86_64")]
const S: [usize; 6] = [ 1, 2, 4, 8, 16, 32 ];

pub trait PowersOf2 {
    fn is_pow2(&self) -> bool;
    fn next_pow2(&self) -> Self;
    fn log2(&self) -> Self;
}

impl PowersOf2 for usize {
    fn is_pow2(&self) -> bool {
        *self != 0 && (self & (self - 1)) == 0
    }

    /// Returns the next power of 2
    fn next_pow2(&self) -> usize {
        let mut v = *self;
        if v == 0 {
            1
        } else {
            v -= 1;
            v = v | (v >> 1);
            v = v | (v >> 2);
            v = v | (v >> 4);
            v = v | (v >> 8);
            v = v | (v >> 16);
            v + 1
        }
    }

    #[cfg(not(any(target_arch="x86_64", target_arch="x86")))]
    fn log2(&self) -> usize {
        // This is the "obvious" log base 2 implementation. The lookup table
        // -based approach would be much faster, but we can't use it for
        // `usize` since we aren't sure what size a usize is without conditional
        // compilation.
        unimplemented!()
    }

    #[cfg(any(target_arch="x86_64", target_arch="x86"))]
    fn log2(&self) -> usize {
        // // let mut r: usize = 0;
        // // let mut v = *self;
        // S.iter()
        //  .zip(B.iter()) // this purely-functional implementation may be slower
        //  .fold((0, *self), // but it's cute and I had fun figuring it out
        //     |(r, v), (s, b)| if v & b != 0 { (r | s, v >> s) }
        //                      else { (r, v) })
        //   .0
        // // for in 0..S.len() {
        // //     if v & B[i] != 0 {
        // //         v = v >> S[i];
        // //         r = r | S[i];
        // //     }
        // // }
        // // r
        //
        let mut res = 0;
        let mut num = *self;
        loop {
            num >>= 1;

            if num == 0 {
                break;
            }

            res += 1;
        }

        res
    }
}

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

    #[test]
    fn test_next_pow2() {
        assert_eq!(2usize.next_pow2(), 2);
        assert_eq!(0usize.next_pow2(), 1);
        assert_eq!(3usize.next_pow2(), 4);
        assert_eq!(5678usize.next_pow2(), 8192);
    }
}
<|endoftext|>


<commit_before>//! Run the tests in a single test file.

use std::borrow::Cow;
use std::path::Path;
use std::time;
use cretonne::ir::Function;
use cretonne::isa::TargetIsa;
use cretonne::settings::Flags;
use cretonne::verify_function;
use cton_reader::parse_test;
use cton_reader::IsaSpec;
use utils::read_to_string;
use filetest::{TestResult, new_subtest};
use filetest::subtest::{SubTest, Context, Result};

/// Load `path` and run the test in it.
///
/// If running this test causes a panic, it will propagate as normal.
pub fn run(path: &Path) -> TestResult {
    dbg!("---\nFile: {}", path.to_string_lossy());
    let started = time::Instant::now();
    let buffer = read_to_string(path).map_err(|e| e.to_string())?;
    let testfile = parse_test(&buffer).map_err(|e| e.to_string())?;
    if testfile.functions.is_empty() {
        return Err("no functions found".to_string());
    }

    // Parse the test commands.
    let mut tests = testfile.commands
        .iter()
        .map(new_subtest)
        .collect::<Result<Vec<_>>>()?;

    // Flags to use for those tests that don't need an ISA.
    // This is the cumulative effect of all the `set` commands in the file.
    let flags = match testfile.isa_spec {
        IsaSpec::None(ref f) => f,
        IsaSpec::Some(ref v) => v.last().expect("Empty ISA list").flags(),
    };

    // Sort the tests so the mutators are at the end, and those that don't need the verifier are at
    // the front.
    tests.sort_by_key(|st| (st.is_mutating(), st.needs_verifier()));

    // Expand the tests into (test, flags, isa) tuples.
    let mut tuples = test_tuples(&tests, &testfile.isa_spec, flags)?;

    // Isolate the last test in the hope that this is the only mutating test.
    // If so, we can completely avoid cloning functions.
    let last_tuple = match tuples.pop() {
        None => return Err("no test commands found".to_string()),
        Some(t) => t,
    };

    for (func, details) in testfile.functions {
        let mut context = Context {
            preamble_comments: &testfile.preamble_comments,
            details: details,
            verified: false,
            flags: flags,
            isa: None,
        };

        for tuple in &tuples {
            run_one_test(*tuple, Cow::Borrowed(&func), &mut context)?;
        }
        // Run the last test with an owned function which means it won't need to clone it before
        // mutating.
        run_one_test(last_tuple, Cow::Owned(func), &mut context)?;
    }

    // TODO: Actually run the tests.
    Ok(started.elapsed())
}

// Given a slice of tests, generate a vector of (test, flags, isa) tuples.
fn test_tuples<'a>(tests: &'a [Box<SubTest>],
                   isa_spec: &'a IsaSpec,
                   no_isa_flags: &'a Flags)
                   -> Result<Vec<(&'a SubTest, &'a Flags, Option<&'a TargetIsa>)>> {
    let mut out = Vec::new();
    for test in tests {
        if test.needs_isa() {
            match *isa_spec {
                IsaSpec::None(_) => {
                    // TODO: Generate a list of default ISAs.
                    return Err(format!("test {} requires an ISA", test.name()));
                }
                IsaSpec::Some(ref isas) => {
                    for isa in isas {
                        out.push((&**test, isa.flags(), Some(&**isa)));
                    }
                }
            }
        } else {
            // This test doesn't require an ISA, and we only want to run one instance of it.
            // Still, give it an ISA ref if we happen to have a unique one.
            // For example, `test cat` can use this to print encodings and register names.
            out.push((&**test, no_isa_flags, isa_spec.unique_isa()));
        }
    }
    Ok(out)
}

fn run_one_test<'a>(tuple: (&'a SubTest, &'a Flags, Option<&'a TargetIsa>),
                    func: Cow<Function>,
                    context: &mut Context<'a>)
                    -> Result<()> {
    let (test, flags, isa) = tuple;
    let name = format!("{}({})", test.name(), func.name);
    dbg!("Test: {} {}", name, isa.map(TargetIsa::name).unwrap_or("-"));

    context.flags = flags;
    context.isa = isa;

    // Should we run the verifier before this test?
    if !context.verified && test.needs_verifier() {
        verify_function(&func).map_err(|e| e.to_string())?;
        context.verified = true;
    }

    test.run(func, context).map_err(|e| format!("{}: {}", name, e))
}
<commit_msg>Use pretty_verifier_error in runone too.<commit_after>//! Run the tests in a single test file.

use std::borrow::Cow;
use std::path::Path;
use std::time;
use cretonne::ir::Function;
use cretonne::isa::TargetIsa;
use cretonne::settings::Flags;
use cretonne::verify_function;
use cton_reader::parse_test;
use cton_reader::IsaSpec;
use utils::{read_to_string, pretty_verifier_error};
use filetest::{TestResult, new_subtest};
use filetest::subtest::{SubTest, Context, Result};

/// Load `path` and run the test in it.
///
/// If running this test causes a panic, it will propagate as normal.
pub fn run(path: &Path) -> TestResult {
    dbg!("---\nFile: {}", path.to_string_lossy());
    let started = time::Instant::now();
    let buffer = read_to_string(path).map_err(|e| e.to_string())?;
    let testfile = parse_test(&buffer).map_err(|e| e.to_string())?;
    if testfile.functions.is_empty() {
        return Err("no functions found".to_string());
    }

    // Parse the test commands.
    let mut tests = testfile.commands
        .iter()
        .map(new_subtest)
        .collect::<Result<Vec<_>>>()?;

    // Flags to use for those tests that don't need an ISA.
    // This is the cumulative effect of all the `set` commands in the file.
    let flags = match testfile.isa_spec {
        IsaSpec::None(ref f) => f,
        IsaSpec::Some(ref v) => v.last().expect("Empty ISA list").flags(),
    };

    // Sort the tests so the mutators are at the end, and those that don't need the verifier are at
    // the front.
    tests.sort_by_key(|st| (st.is_mutating(), st.needs_verifier()));

    // Expand the tests into (test, flags, isa) tuples.
    let mut tuples = test_tuples(&tests, &testfile.isa_spec, flags)?;

    // Isolate the last test in the hope that this is the only mutating test.
    // If so, we can completely avoid cloning functions.
    let last_tuple = match tuples.pop() {
        None => return Err("no test commands found".to_string()),
        Some(t) => t,
    };

    for (func, details) in testfile.functions {
        let mut context = Context {
            preamble_comments: &testfile.preamble_comments,
            details: details,
            verified: false,
            flags: flags,
            isa: None,
        };

        for tuple in &tuples {
            run_one_test(*tuple, Cow::Borrowed(&func), &mut context)?;
        }
        // Run the last test with an owned function which means it won't need to clone it before
        // mutating.
        run_one_test(last_tuple, Cow::Owned(func), &mut context)?;
    }

    // TODO: Actually run the tests.
    Ok(started.elapsed())
}

// Given a slice of tests, generate a vector of (test, flags, isa) tuples.
fn test_tuples<'a>(tests: &'a [Box<SubTest>],
                   isa_spec: &'a IsaSpec,
                   no_isa_flags: &'a Flags)
                   -> Result<Vec<(&'a SubTest, &'a Flags, Option<&'a TargetIsa>)>> {
    let mut out = Vec::new();
    for test in tests {
        if test.needs_isa() {
            match *isa_spec {
                IsaSpec::None(_) => {
                    // TODO: Generate a list of default ISAs.
                    return Err(format!("test {} requires an ISA", test.name()));
                }
                IsaSpec::Some(ref isas) => {
                    for isa in isas {
                        out.push((&**test, isa.flags(), Some(&**isa)));
                    }
                }
            }
        } else {
            // This test doesn't require an ISA, and we only want to run one instance of it.
            // Still, give it an ISA ref if we happen to have a unique one.
            // For example, `test cat` can use this to print encodings and register names.
            out.push((&**test, no_isa_flags, isa_spec.unique_isa()));
        }
    }
    Ok(out)
}

fn run_one_test<'a>(tuple: (&'a SubTest, &'a Flags, Option<&'a TargetIsa>),
                    func: Cow<Function>,
                    context: &mut Context<'a>)
                    -> Result<()> {
    let (test, flags, isa) = tuple;
    let name = format!("{}({})", test.name(), func.name);
    dbg!("Test: {} {}", name, isa.map(TargetIsa::name).unwrap_or("-"));

    context.flags = flags;
    context.isa = isa;

    // Should we run the verifier before this test?
    if !context.verified && test.needs_verifier() {
        verify_function(&func).map_err(|e| pretty_verifier_error(&func, e))?;
        context.verified = true;
    }

    test.run(func, context).map_err(|e| format!("{}: {}", name, e))
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::f64;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::filter::Filter;
use crate::parsers::CustomIdent;
use crate::properties::ComputedValues;
use crate::rect::{IRect, Rect};
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;

use super::error::FilterError;
use super::Input;

/// A filter primitive output.
#[derive(Debug, Clone)]
pub struct FilterOutput {
    /// The surface after the filter primitive was applied.
    pub surface: SharedImageSurface,

    /// The filter primitive subregion.
    pub bounds: IRect,
}

/// A filter primitive result.
#[derive(Debug, Clone)]
pub struct FilterResult {
    /// The name of this result: the value of the `result` attribute.
    pub name: Option<CustomIdent>,

    /// The output.
    pub output: FilterOutput,
}

/// An input to a filter primitive.
#[derive(Debug, Clone)]
pub enum FilterInput {
    /// One of the standard inputs.
    StandardInput(SharedImageSurface),
    /// Output of another filter primitive.
    PrimitiveOutput(FilterOutput),
}

/// The filter rendering context.
pub struct FilterContext {
    /// Bounding box of node being filtered
    node_bbox: BoundingBox,
    /// Values from the node which referenced this filter.
    computed_from_node_being_filtered: ComputedValues,
    /// The source graphic surface.
    source_surface: SharedImageSurface,
    /// Output of the last filter primitive.
    last_result: Option<FilterOutput>,
    /// Surfaces of the previous filter primitives by name.
    previous_results: HashMap<CustomIdent, FilterOutput>,
    /// The background surface. Computed lazily.
    background_surface: RefCell<Option<Result<SharedImageSurface, FilterError>>>,
    /// Primtive units
    primitive_units: CoordUnits,
    /// The filter effects region.
    effects_region: Rect,
    /// Whether the currently rendered filter primitive uses linear RGB for color operations.
    ///
    /// This affects `get_input()` and `store_result()` which should perform linearization and
    /// unlinearization respectively when this is set to `true`.
    processing_linear_rgb: bool,

    /// The filter element affine matrix.
    ///
    /// If `filterUnits == userSpaceOnUse`, equal to the drawing context matrix, so, for example,
    /// if the target node is in a group with `transform="translate(30, 20)"`, this will be equal
    /// to a matrix that translates to 30, 20 (and does not scale). Note that the target node
    /// bounding box isn't included in the computations in this case.
    ///
    /// If `filterUnits == objectBoundingBox`, equal to the target node bounding box matrix
    /// multiplied by the drawing context matrix, so, for example, if the target node is in a group
    /// with `transform="translate(30, 20)"` and also has `x="1", y="1", width="50", height="50"`,
    /// this will be equal to a matrix that translates to 31, 21 and scales to 50, 50.
    ///
    /// This is to be used in conjunction with setting the viewbox size to account for the scaling.
    /// For `filterUnits == userSpaceOnUse`, the viewbox will have the actual resolution size, and
    /// for `filterUnits == objectBoundingBox`, the viewbox will have the size of 1, 1.
    _affine: Transform,

    /// The filter primitive affine matrix.
    ///
    /// See the comments for `_affine`, they largely apply here.
    paffine: Transform,
}

impl FilterContext {
    /// Creates a new `FilterContext`.
    pub fn new(
        filter: &Filter,
        computed_from_node_being_filtered: &ComputedValues,
        source_surface: SharedImageSurface,
        draw_ctx: &mut DrawingCtx,
        draw_transform: Transform,
        node_bbox: BoundingBox,
    ) -> Self {
        // The rect can be empty (for example, if the filter is applied to an empty group).
        // However, with userSpaceOnUse it's still possible to create images with a filter.
        let bbox_rect = node_bbox.rect.unwrap_or_default();

        let filter_units = filter.get_filter_units();
        let affine = match filter_units {
            CoordUnits::UserSpaceOnUse => draw_transform,
            CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                bbox_rect.width(),
                0.0,
                0.0,
                bbox_rect.height(),
                bbox_rect.x0,
                bbox_rect.y0,
            )
            .post_transform(&draw_transform),
        };

        let primitive_units = filter.get_primitive_units();
        let paffine = match primitive_units {
            CoordUnits::UserSpaceOnUse => draw_transform,
            CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                bbox_rect.width(),
                0.0,
                0.0,
                bbox_rect.height(),
                bbox_rect.x0,
                bbox_rect.y0,
            )
            .post_transform(&draw_transform),
        };

        let effects_region = {
            let params = draw_ctx.push_coord_units(filter_units);
            let filter_rect = filter.get_rect(&computed_from_node_being_filtered, &params);

            let mut bbox = BoundingBox::new();
            let other_bbox = BoundingBox::new()
                .with_transform(affine)
                .with_rect(filter_rect);

            // At this point all of the previous viewbox and matrix business gets converted to pixel
            // coordinates in the final surface, because bbox is created with an identity transform.
            bbox.insert(&other_bbox);

            // Finally, clip to the width and height of our surface.
            let (width, height) = (source_surface.width(), source_surface.height());
            let rect = Rect::from_size(f64::from(width), f64::from(height));
            let other_bbox = BoundingBox::new().with_rect(rect);
            bbox.clip(&other_bbox);

            bbox.rect.unwrap()
        };

        Self {
            node_bbox,
            computed_from_node_being_filtered: computed_from_node_being_filtered.clone(),
            source_surface,
            last_result: None,
            previous_results: HashMap::new(),
            background_surface: RefCell::new(None),
            primitive_units,
            effects_region,
            processing_linear_rgb: false,
            _affine: affine,
            paffine,
        }
    }

    /// Returns the computed values from the node that referenced this filter.
    #[inline]
    pub fn get_computed_values_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Returns the surface corresponding to the source graphic.
    #[inline]
    pub fn source_graphic(&self) -> &SharedImageSurface {
        &self.source_surface
    }

    /// Returns the surface corresponding to the background image snapshot.
    pub fn background_image(
        &self,
        draw_ctx: &DrawingCtx,
    ) -> Result<SharedImageSurface, FilterError> {
        {
            // At this point either no, or only immutable references to background_surface exist, so
            // it's ok to make an immutable reference.
            let bg = self.background_surface.borrow();

            // If background_surface was already computed, return the immutable reference. It will
            // get bound to the &self lifetime by the function return type.
            if let Some(ref result) = *bg {
                return result.clone();
            }
        }

        // If we got here, then background_surface hasn't been computed yet. This means there are
        // no references to it and we can create a mutable reference.
        let mut bg = self.background_surface.borrow_mut();

        *bg = Some(
            draw_ctx
                .get_snapshot(self.source_surface.width(), self.source_surface.height())
                .map_err(FilterError::CairoError),
        );

        // Return the only existing reference as immutable.
        bg.as_ref()
            .unwrap()
            .as_ref()
            .map(|surf| surf.clone())
            .map_err(|e| e.clone())
    }

    /// Converts this `FilterContext` into the surface corresponding to the output of the filter
    /// chain.
    ///
    /// The returned surface is in the sRGB color space.
    // TODO: sRGB conversion should probably be done by the caller.
    #[inline]
    pub fn into_output(self) -> Result<SharedImageSurface, cairo::Status> {
        match self.last_result {
            Some(FilterOutput { surface, bounds }) => surface.to_srgb(bounds),
            None => SharedImageSurface::empty(
                self.source_surface.width(),
                self.source_surface.height(),
                SurfaceType::AlphaOnly,
            ),
        }
    }

    /// Stores a filter primitive result into the context.
    #[inline]
    pub fn store_result(&mut self, result: FilterResult) -> Result<(), FilterError> {
        if let Some(name) = result.name {
            self.previous_results.insert(name, result.output.clone());
        }

        self.last_result = Some(result.output);
        Ok(())
    }

    /// Returns the paffine matrix.
    #[inline]
    pub fn paffine(&self) -> Transform {
        self.paffine
    }

    /// Returns the primitive units.
    #[inline]
    pub fn primitive_units(&self) -> CoordUnits {
        self.primitive_units
    }

    /// Returns the filter effects region.
    #[inline]
    pub fn effects_region(&self) -> Rect {
        self.effects_region
    }

    /// Retrieves the filter input surface according to the SVG rules.
    ///
    /// Does not take `processing_linear_rgb` into account.
    fn get_input_raw(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        if in_.is_none() {
            // No value => use the last result.
            // As per the SVG spec, if the filter primitive is the first in the chain, return the
            // source graphic.
            if let Some(output) = self.last_result.as_ref() {
                return Ok(FilterInput::PrimitiveOutput(output.clone()));
            } else {
                return Ok(FilterInput::StandardInput(self.source_graphic().clone()));
            }
        }

        let values = &self.computed_from_node_being_filtered;

        match *in_.unwrap() {
            Input::SourceGraphic => Ok(FilterInput::StandardInput(self.source_graphic().clone())),

            Input::SourceAlpha => self
                .source_graphic()
                .extract_alpha(self.effects_region().into())
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::BackgroundImage => self
                .background_image(draw_ctx)
                .map(FilterInput::StandardInput),

            Input::BackgroundAlpha => self
                .background_image(draw_ctx)
                .and_then(|surface| {
                    surface
                        .extract_alpha(self.effects_region().into())
                        .map_err(FilterError::CairoError)
                })
                .map(FilterInput::StandardInput),

            Input::FillPaint => draw_ctx
                .get_paint_server_surface(
                    self.source_surface.width(),
                    self.source_surface.height(),
                    acquired_nodes,
                    &values.fill().0,
                    values.fill_opacity().0,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color().0,
                    &values,
                )
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::StrokePaint => draw_ctx
                .get_paint_server_surface(
                    self.source_surface.width(),
                    self.source_surface.height(),
                    acquired_nodes,
                    &values.stroke().0,
                    values.stroke_opacity().0,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color().0,
                    &values,
                )
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::FilterOutput(ref name) => self
                .previous_results
                .get(name)
                .cloned()
                .map(FilterInput::PrimitiveOutput)
                .ok_or(FilterError::InvalidInput),
        }
    }

    /// Retrieves the filter input surface according to the SVG rules.
    pub fn get_input(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        let raw = self.get_input_raw(acquired_nodes, draw_ctx, in_)?;

        // Convert the input surface to the desired format.
        let (surface, bounds) = match raw {
            FilterInput::StandardInput(ref surface) => (surface, self.effects_region().into()),
            FilterInput::PrimitiveOutput(FilterOutput {
                ref surface,
                ref bounds,
            }) => (surface, *bounds),
        };

        let surface = if self.processing_linear_rgb {
            surface.to_linear_rgb(bounds)
        } else {
            surface.to_srgb(bounds)
        };
        surface
            .map_err(FilterError::CairoError)
            .map(|surface| match raw {
                FilterInput::StandardInput(_) => FilterInput::StandardInput(surface),
                FilterInput::PrimitiveOutput(ref output) => {
                    FilterInput::PrimitiveOutput(FilterOutput { surface, ..*output })
                }
            })
    }

    /// Calls the given closure with linear RGB processing enabled.
    #[inline]
    pub fn with_linear_rgb<T, F: FnOnce(&mut FilterContext) -> T>(&mut self, f: F) -> T {
        self.processing_linear_rgb = true;
        let rv = f(self);
        self.processing_linear_rgb = false;
        rv
    }

    /// Applies the `primitiveUnits` coordinate transformation to a non-x or y distance.
    #[inline]
    pub fn transform_dist(&self, d: f64) -> f64 {
        d * (self.paffine.xx.powi(2) + self.paffine.yy.powi(2)).sqrt() / f64::consts::SQRT_2
    }
}

impl FilterInput {
    /// Retrieves the surface from `FilterInput`.
    #[inline]
    pub fn surface(&self) -> &SharedImageSurface {
        match *self {
            FilterInput::StandardInput(ref surface) => surface,
            FilterInput::PrimitiveOutput(FilterOutput { ref surface, .. }) => surface,
        }
    }
}
<commit_msg>filters: use OnceCell for the background surface<commit_after>use once_cell::sync::OnceCell;
use std::collections::HashMap;
use std::f64;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::filter::Filter;
use crate::parsers::CustomIdent;
use crate::properties::ComputedValues;
use crate::rect::{IRect, Rect};
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;

use super::error::FilterError;
use super::Input;

/// A filter primitive output.
#[derive(Debug, Clone)]
pub struct FilterOutput {
    /// The surface after the filter primitive was applied.
    pub surface: SharedImageSurface,

    /// The filter primitive subregion.
    pub bounds: IRect,
}

/// A filter primitive result.
#[derive(Debug, Clone)]
pub struct FilterResult {
    /// The name of this result: the value of the `result` attribute.
    pub name: Option<CustomIdent>,

    /// The output.
    pub output: FilterOutput,
}

/// An input to a filter primitive.
#[derive(Debug, Clone)]
pub enum FilterInput {
    /// One of the standard inputs.
    StandardInput(SharedImageSurface),
    /// Output of another filter primitive.
    PrimitiveOutput(FilterOutput),
}

/// The filter rendering context.
pub struct FilterContext {
    /// Bounding box of node being filtered
    node_bbox: BoundingBox,
    /// Values from the node which referenced this filter.
    computed_from_node_being_filtered: ComputedValues,
    /// The source graphic surface.
    source_surface: SharedImageSurface,
    /// Output of the last filter primitive.
    last_result: Option<FilterOutput>,
    /// Surfaces of the previous filter primitives by name.
    previous_results: HashMap<CustomIdent, FilterOutput>,
    /// The background surface. Computed lazily.
    background_surface: OnceCell<Result<SharedImageSurface, FilterError>>,
    /// Primtive units
    primitive_units: CoordUnits,
    /// The filter effects region.
    effects_region: Rect,
    /// Whether the currently rendered filter primitive uses linear RGB for color operations.
    ///
    /// This affects `get_input()` and `store_result()` which should perform linearization and
    /// unlinearization respectively when this is set to `true`.
    processing_linear_rgb: bool,

    /// The filter element affine matrix.
    ///
    /// If `filterUnits == userSpaceOnUse`, equal to the drawing context matrix, so, for example,
    /// if the target node is in a group with `transform="translate(30, 20)"`, this will be equal
    /// to a matrix that translates to 30, 20 (and does not scale). Note that the target node
    /// bounding box isn't included in the computations in this case.
    ///
    /// If `filterUnits == objectBoundingBox`, equal to the target node bounding box matrix
    /// multiplied by the drawing context matrix, so, for example, if the target node is in a group
    /// with `transform="translate(30, 20)"` and also has `x="1", y="1", width="50", height="50"`,
    /// this will be equal to a matrix that translates to 31, 21 and scales to 50, 50.
    ///
    /// This is to be used in conjunction with setting the viewbox size to account for the scaling.
    /// For `filterUnits == userSpaceOnUse`, the viewbox will have the actual resolution size, and
    /// for `filterUnits == objectBoundingBox`, the viewbox will have the size of 1, 1.
    _affine: Transform,

    /// The filter primitive affine matrix.
    ///
    /// See the comments for `_affine`, they largely apply here.
    paffine: Transform,
}

impl FilterContext {
    /// Creates a new `FilterContext`.
    pub fn new(
        filter: &Filter,
        computed_from_node_being_filtered: &ComputedValues,
        source_surface: SharedImageSurface,
        draw_ctx: &mut DrawingCtx,
        draw_transform: Transform,
        node_bbox: BoundingBox,
    ) -> Self {
        // The rect can be empty (for example, if the filter is applied to an empty group).
        // However, with userSpaceOnUse it's still possible to create images with a filter.
        let bbox_rect = node_bbox.rect.unwrap_or_default();

        let filter_units = filter.get_filter_units();
        let affine = match filter_units {
            CoordUnits::UserSpaceOnUse => draw_transform,
            CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                bbox_rect.width(),
                0.0,
                0.0,
                bbox_rect.height(),
                bbox_rect.x0,
                bbox_rect.y0,
            )
            .post_transform(&draw_transform),
        };

        let primitive_units = filter.get_primitive_units();
        let paffine = match primitive_units {
            CoordUnits::UserSpaceOnUse => draw_transform,
            CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                bbox_rect.width(),
                0.0,
                0.0,
                bbox_rect.height(),
                bbox_rect.x0,
                bbox_rect.y0,
            )
            .post_transform(&draw_transform),
        };

        let effects_region = {
            let params = draw_ctx.push_coord_units(filter_units);
            let filter_rect = filter.get_rect(&computed_from_node_being_filtered, &params);

            let mut bbox = BoundingBox::new();
            let other_bbox = BoundingBox::new()
                .with_transform(affine)
                .with_rect(filter_rect);

            // At this point all of the previous viewbox and matrix business gets converted to pixel
            // coordinates in the final surface, because bbox is created with an identity transform.
            bbox.insert(&other_bbox);

            // Finally, clip to the width and height of our surface.
            let (width, height) = (source_surface.width(), source_surface.height());
            let rect = Rect::from_size(f64::from(width), f64::from(height));
            let other_bbox = BoundingBox::new().with_rect(rect);
            bbox.clip(&other_bbox);

            bbox.rect.unwrap()
        };

        Self {
            node_bbox,
            computed_from_node_being_filtered: computed_from_node_being_filtered.clone(),
            source_surface,
            last_result: None,
            previous_results: HashMap::new(),
            background_surface: OnceCell::new(),
            primitive_units,
            effects_region,
            processing_linear_rgb: false,
            _affine: affine,
            paffine,
        }
    }

    /// Returns the computed values from the node that referenced this filter.
    #[inline]
    pub fn get_computed_values_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Returns the surface corresponding to the source graphic.
    #[inline]
    pub fn source_graphic(&self) -> &SharedImageSurface {
        &self.source_surface
    }

    /// Returns the surface corresponding to the background image snapshot.
    pub fn background_image(
        &self,
        draw_ctx: &DrawingCtx,
    ) -> Result<SharedImageSurface, FilterError> {
        let res = self.background_surface.get_or_init(|| {
            draw_ctx
                .get_snapshot(self.source_surface.width(), self.source_surface.height())
                .map_err(FilterError::CairoError)
        });

        // Return the only existing reference as immutable.
        res.as_ref().map(|s| s.clone()).map_err(|e| e.clone())
    }

    /// Converts this `FilterContext` into the surface corresponding to the output of the filter
    /// chain.
    ///
    /// The returned surface is in the sRGB color space.
    // TODO: sRGB conversion should probably be done by the caller.
    #[inline]
    pub fn into_output(self) -> Result<SharedImageSurface, cairo::Status> {
        match self.last_result {
            Some(FilterOutput { surface, bounds }) => surface.to_srgb(bounds),
            None => SharedImageSurface::empty(
                self.source_surface.width(),
                self.source_surface.height(),
                SurfaceType::AlphaOnly,
            ),
        }
    }

    /// Stores a filter primitive result into the context.
    #[inline]
    pub fn store_result(&mut self, result: FilterResult) -> Result<(), FilterError> {
        if let Some(name) = result.name {
            self.previous_results.insert(name, result.output.clone());
        }

        self.last_result = Some(result.output);
        Ok(())
    }

    /// Returns the paffine matrix.
    #[inline]
    pub fn paffine(&self) -> Transform {
        self.paffine
    }

    /// Returns the primitive units.
    #[inline]
    pub fn primitive_units(&self) -> CoordUnits {
        self.primitive_units
    }

    /// Returns the filter effects region.
    #[inline]
    pub fn effects_region(&self) -> Rect {
        self.effects_region
    }

    /// Retrieves the filter input surface according to the SVG rules.
    ///
    /// Does not take `processing_linear_rgb` into account.
    fn get_input_raw(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        if in_.is_none() {
            // No value => use the last result.
            // As per the SVG spec, if the filter primitive is the first in the chain, return the
            // source graphic.
            if let Some(output) = self.last_result.as_ref() {
                return Ok(FilterInput::PrimitiveOutput(output.clone()));
            } else {
                return Ok(FilterInput::StandardInput(self.source_graphic().clone()));
            }
        }

        let values = &self.computed_from_node_being_filtered;

        match *in_.unwrap() {
            Input::SourceGraphic => Ok(FilterInput::StandardInput(self.source_graphic().clone())),

            Input::SourceAlpha => self
                .source_graphic()
                .extract_alpha(self.effects_region().into())
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::BackgroundImage => self
                .background_image(draw_ctx)
                .map(FilterInput::StandardInput),

            Input::BackgroundAlpha => self
                .background_image(draw_ctx)
                .and_then(|surface| {
                    surface
                        .extract_alpha(self.effects_region().into())
                        .map_err(FilterError::CairoError)
                })
                .map(FilterInput::StandardInput),

            Input::FillPaint => draw_ctx
                .get_paint_server_surface(
                    self.source_surface.width(),
                    self.source_surface.height(),
                    acquired_nodes,
                    &values.fill().0,
                    values.fill_opacity().0,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color().0,
                    &values,
                )
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::StrokePaint => draw_ctx
                .get_paint_server_surface(
                    self.source_surface.width(),
                    self.source_surface.height(),
                    acquired_nodes,
                    &values.stroke().0,
                    values.stroke_opacity().0,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color().0,
                    &values,
                )
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::FilterOutput(ref name) => self
                .previous_results
                .get(name)
                .cloned()
                .map(FilterInput::PrimitiveOutput)
                .ok_or(FilterError::InvalidInput),
        }
    }

    /// Retrieves the filter input surface according to the SVG rules.
    pub fn get_input(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        let raw = self.get_input_raw(acquired_nodes, draw_ctx, in_)?;

        // Convert the input surface to the desired format.
        let (surface, bounds) = match raw {
            FilterInput::StandardInput(ref surface) => (surface, self.effects_region().into()),
            FilterInput::PrimitiveOutput(FilterOutput {
                ref surface,
                ref bounds,
            }) => (surface, *bounds),
        };

        let surface = if self.processing_linear_rgb {
            surface.to_linear_rgb(bounds)
        } else {
            surface.to_srgb(bounds)
        };
        surface
            .map_err(FilterError::CairoError)
            .map(|surface| match raw {
                FilterInput::StandardInput(_) => FilterInput::StandardInput(surface),
                FilterInput::PrimitiveOutput(ref output) => {
                    FilterInput::PrimitiveOutput(FilterOutput { surface, ..*output })
                }
            })
    }

    /// Calls the given closure with linear RGB processing enabled.
    #[inline]
    pub fn with_linear_rgb<T, F: FnOnce(&mut FilterContext) -> T>(&mut self, f: F) -> T {
        self.processing_linear_rgb = true;
        let rv = f(self);
        self.processing_linear_rgb = false;
        rv
    }

    /// Applies the `primitiveUnits` coordinate transformation to a non-x or y distance.
    #[inline]
    pub fn transform_dist(&self, d: f64) -> f64 {
        d * (self.paffine.xx.powi(2) + self.paffine.yy.powi(2)).sqrt() / f64::consts::SQRT_2
    }
}

impl FilterInput {
    /// Retrieves the surface from `FilterInput`.
    #[inline]
    pub fn surface(&self) -> &SharedImageSurface {
        match *self {
            FilterInput::StandardInput(ref surface) => surface,
            FilterInput::PrimitiveOutput(FilterOutput { ref surface, .. }) => surface,
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;

use rmps::{Deserializer, Serializer};
use serde::{Deserialize, Serialize};

use std::path::Path;
use std::io;
use std::io::{Write, Read, Error, ErrorKind};

use tensor::TensorKind;

pub fn save<P, T: Serialize>(path: P, arg: &Vec<T>) -> io::Result<usize>
    where P: AsRef<Path>
{
    let mut buffer = File::create(path)?;
    let mut encoded = Vec::new();
    arg.serialize(&mut Serializer::new(&mut encoded)).unwrap();
    buffer.write(encoded.as_slice())
}

pub fn load<'a, P, T: 'a + Deserialize<'a>>(path: P) -> io::Result<Vec<T>>
    where P: AsRef<Path>
{
    let mut buffer = File::open(path)?;
    let mut encoded = Vec::new();
    let size = buffer.read_to_end(&mut encoded)?;
    if size == 0 {
        return Err(Error::new(ErrorKind::UnexpectedEof, "Empty File"));
    };
    let mut de = Deserializer::new(&encoded[..]);
    let decoded = Deserialize::deserialize(&mut de).expect("decode failed");
    Ok(decoded)
}
<commit_msg>remove unused import<commit_after>use std::fs::File;

use rmps::{Deserializer, Serializer};
use serde::{Deserialize, Serialize};

use std::path::Path;
use std::io;
use std::io::{Write, Read, Error, ErrorKind};

pub fn save<P, T: Serialize>(path: P, arg: &Vec<T>) -> io::Result<usize>
    where P: AsRef<Path>
{
    let mut buffer = File::create(path)?;
    let mut encoded = Vec::new();
    arg.serialize(&mut Serializer::new(&mut encoded)).unwrap();
    buffer.write(encoded.as_slice())
}

pub fn load<'a, P, T: 'a + Deserialize<'a>>(path: P) -> io::Result<Vec<T>>
    where P: AsRef<Path>
{
    let mut buffer = File::open(path)?;
    let mut encoded = Vec::new();
    let size = buffer.read_to_end(&mut encoded)?;
    if size == 0 {
        return Err(Error::new(ErrorKind::UnexpectedEof, "Empty File"));
    };
    let mut de = Deserializer::new(&encoded[..]);
    let decoded = Deserialize::deserialize(&mut de).expect("decode failed");
    Ok(decoded)
}
<|endoftext|>


<commit_before>use super::ease::Easing;
/// This struct captures Quart easing functions
pub struct Quart;

impl Easing for Quart {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let inner_t = t / d;
        c * inner_t.powi(4) + b
    }

    fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let inner_t = t / d - 1.0;
        -c * (inner_t.powi(4) - 1.0) + b
    }

    fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let mut inner_t = t / (d / 2.0);

        if inner_t < 1.0 {
            return c / 2.0 * inner_t * inner_t * inner_t * inner_t + b;
        }

        inner_t -= 2.0;
        return -c / 2.0 * (inner_t.powi(4) - 2.0) + b;
    }
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use functions::ease::Easing;
    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Quart::ease_in(1.0, 2.0, 3.0, 4.0), 2.011719);
    }

    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Quart::ease_out(1.0, 2.0, 3.0, 4.0), 4.050781);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Quart::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.093750);
        assert_relative_eq!(super::Quart::ease_in_out(51.0, 1.0, 100.0, 100.0),
                            54.881588);
    }
}
<commit_msg>Clear the Quart easing functions<commit_after>use super::ease::Easing;

/// This struct captures Quart easing functions
pub struct Quart;

impl Easing for Quart {
    fn ease_in(mut t: f32, b: f32, c: f32, d: f32) -> f32 {
        t = t / d;
        c * (t * t * t * t) + b
    }

    fn ease_out(mut t: f32, b: f32, c: f32, d: f32) -> f32 {
        t = t / d - 1.0;
        -c * ((t * t * t * t) - 1.0) + b
    }

    fn ease_in_out(mut t: f32, b: f32, c: f32, d: f32) -> f32 {
        t = t / (d / 2.0);
        if t < 1.0 {
            c / 2.0 * (t * t * t * t) + b
        }
        else {
            t -= 2.0;
            -c / 2.0 * ((t * t * t * t) - 2.0) + b
        }

    }
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use functions::ease::Easing;
    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Quart::ease_in(1.0, 2.0, 3.0, 4.0), 2.011719);
    }

    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Quart::ease_out(1.0, 2.0, 3.0, 4.0), 4.050781);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Quart::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.093750);
        assert_relative_eq!(super::Quart::ease_in_out(51.0, 1.0, 100.0, 100.0),
                            54.881588);
    }
}
<|endoftext|>


<commit_before>//! Types for HVIF shapes

use types::path::*;

#[derive(Debug)]
/// An HVIF shape, consisting of a single style, one or more paths, and optional additional transformation data
pub struct HVIFShape {
  /// The index of the style used in the shape
  pub style_index: u8,
  /// The indices of the paths that use this shape's style
  pub path_indices: Vec<u8>,
  /// A list of any optional modifications to this shape
  pub modifiers: Vec<HVIFShapeModifier>,

}

#[derive(Debug)]
/// A modifier to an HVIF shape
pub enum HVIFShapeModifier {
  /// A single affine transformation matrix
  HVIFTransformMatrix(HVIFMatrix),
  /// The shape uses hinting
  HVIFHinting,
  /// Level of Detail scales
  /// Represents the allowable scales at which this shape will appear correctly
  HVIFLODScale {
    #[doc = "Minimum LOD for this shape"] min: f32,
    #[doc = "Maximum LOD for this shape"] max: f32
  },
  /// An optional linear translation of the shape (offset)
  HVIFTranslation(HVIFPoint),
  /// A list of optional transformers
  HVIFTransformerList(Vec<HVIFTransformer>)

}

#[derive(Debug, Copy, Clone)]
/// A temporary implementation of an f24 value, as three bytes
pub struct HVIFf24 {
  #[doc = "First (most significant) bits"] pub fst: u8,
  #[doc = "Middle bits"] pub snd: u8,
  #[doc = "Last (least significant) bits"] pub thr: u8
}

#[derive(Debug, Copy, Clone)]
/// A 2D affine transformation matrix
/// As per HVIF spec, consists of six f24 values
pub struct HVIFMatrix {
  #[doc = "x1"] pub x1: HVIFf24, #[doc = "y1"] pub y1: HVIFf24, #[doc = "z1"] pub z1: HVIFf24,
  #[doc = "x2"] pub x2: HVIFf24, #[doc = "y2"] pub y2: HVIFf24, #[doc = "z2"] pub z2: HVIFf24,
}

#[derive(Debug, Copy, Clone)]
/// Some transformation on a basic HVIF shape
pub enum HVIFTransformer {
  /// An affine transformation using a single matrix
  Affine(HVIFMatrix),
  /// ?
  Contour { #[doc="?"] width: f32, #[doc="?"] line_join: u8, #[doc="?"] miter_limit: u8 },
  /// ?
  Perspective,
  /// ?
  Stroke { #[doc="?"] width: f32, #[doc="?"] line_join: u8, #[doc="?"] line_cap: u8, #[doc="?"] miter_limit: u8 }
}
<commit_msg>Added little f24 to f32 conversion<commit_after>//! Types for HVIF shapes

use types::path::*;

#[derive(Debug)]
/// An HVIF shape, consisting of a single style, one or more paths, and optional additional transformation data
pub struct HVIFShape {
  /// The index of the style used in the shape
  pub style_index: u8,
  /// The indices of the paths that use this shape's style
  pub path_indices: Vec<u8>,
  /// A list of any optional modifications to this shape
  pub modifiers: Vec<HVIFShapeModifier>,

}

#[derive(Debug)]
/// A modifier to an HVIF shape
pub enum HVIFShapeModifier {
  /// A single affine transformation matrix
  HVIFTransformMatrix(HVIFMatrix),
  /// The shape uses hinting
  HVIFHinting,
  /// Level of Detail scales
  /// Represents the allowable scales at which this shape will appear correctly
  HVIFLODScale {
    #[doc = "Minimum LOD for this shape"] min: f32,
    #[doc = "Maximum LOD for this shape"] max: f32,
  },
  /// An optional linear translation of the shape (offset)
  HVIFTranslation(HVIFPoint),
  /// A list of optional transformers
  HVIFTransformerList(Vec<HVIFTransformer>)

}

#[derive(Debug, Copy, Clone)]
/// A temporary implementation of an f24 value, as three bytes
pub struct HVIFf24 {
  #[doc = "First (most significant) bits"] pub fst: u8,
  #[doc = "Middle bits"] pub snd: u8,
  #[doc = "Last (least significant) bits"] pub thr: u8
}
impl From<HVIFf24> for f32 {
  // Not quite exact in its current form - be warned!
  fn from(hvif_f24: HVIFf24) -> Self {
    let f24_as_u32: u32 = ((hvif_f24.fst as u32) << 16) | ((hvif_f24.snd as u32) << 8) | (hvif_f24.thr as u32);

    // Get the raw bits for each independent component
    let sign_bit      = (f24_as_u32 & 0b100000000000000000000000) >> 23;
    let exponent_bits = (f24_as_u32 & 0b011111100000000000000000) >> 17;
    let mantissa_bits =  f24_as_u32 & 0b000000011111111111111111;

    // The sign is just -1 to the power of this bit
    let sign : i32 = match sign_bit {
      0 =>  1,
      _ => -1,
    };

    // The exponent is actually only 6 bits, so unsigned values range from 0 to 63
    // Make it a signed exponent, and offset it to range from -31 to 32
    let exponent_pre = (exponent_bits as i32) - 31;

    // The mantissa is 1.(bits), so we can divite the exponentiation into whole and fractional parts
    let mantissa_base = f32::powf(2.0, exponent_pre as f32);
    let mantissa_frac = (mantissa_bits as f32) * f32::powf(2.0, (exponent_pre -17) as f32);

    (sign as f32) * (mantissa_base + mantissa_frac)
  }
}

#[derive(Debug, Copy, Clone)]
/// A 2D affine transformation matrix
/// As per HVIF spec, consists of six f24 values
pub struct HVIFMatrix {
  #[doc = "x1"] pub x1: HVIFf24, #[doc = "y1"] pub y1: HVIFf24, #[doc = "z1"] pub z1: HVIFf24,
  #[doc = "x2"] pub x2: HVIFf24, #[doc = "y2"] pub y2: HVIFf24, #[doc = "z2"] pub z2: HVIFf24,
}

#[derive(Debug, Copy, Clone)]
/// Some transformation on a basic HVIF shape
pub enum HVIFTransformer {
  /// An affine transformation using a single matrix
  Affine(HVIFMatrix),
  /// ?
  Contour { #[doc="?"] width: f32, #[doc="?"] line_join: u8, #[doc="?"] miter_limit: u8 },
  /// ?
  Perspective,
  /// ?
  Stroke { #[doc="?"] width: f32, #[doc="?"] line_join: u8, #[doc="?"] line_cap: u8, #[doc="?"] miter_limit: u8 }
}
<|endoftext|>


<commit_before>use std::io::{BufRead, BufReader, Read};
use super::Parser;
use ::errors::{self, Error, ErrorKind};
use ::GameDescriptor;
use ::default_game_descriptor::DefaultGameDescriptor;
use std::i16;

/// Parser for files in the life 1.05 format.
pub struct Life105Parser {}

impl Life105Parser {
	/// Construct a new instance.
	pub fn new() -> Self {
		Life105Parser{}
	}
}

impl Parser for Life105Parser {
	fn parse<'a>(&mut self, input: Box<Read + 'a>) -> errors::Result<Box<GameDescriptor>> {
		let mut ret = DefaultGameDescriptor::new();

		let mut offset = None;
		let mut line_in_block: i16 = 0;
		for (line_num, line) in BufReader::new(input).lines().enumerate() {
			let line_num = line_num + 1; // line numbers don't start at 0
			let line = line
				.map_err(|err| errors::ErrorKind::IOError(err.kind()))?;
			let line = line.trim();

			if line.starts_with("#R") {
				ret.clear_rules();
				parse_rules(line_num, &line, &mut ret)?;
			} else if line.starts_with("#Life") {
				check_file_format(line)?;
			} else if line.starts_with("#N") {
				ret.clear_rules();
				ret.add_survival(2);
				ret.add_survival(3);
				ret.add_birth(3);
			} else if line.starts_with("#P") {
				offset = Some(parse_offset(line_num, &line)?);
				line_in_block = 0;
			} else if let Some((ox, oy)) = offset {
				for (index, char) in line.chars().enumerate() {
					let index_with_offset = index as i32 + ox as i32;
					if index_with_offset > i16::MAX as i32 || index_with_offset < i16::MIN as i32 {
						bail!(ErrorKind::CoordinateOutOfRange(line_num));
					}
					match char {
						'*' => ret.add_live_cell(index as i16 + ox, line_in_block + oy),
						'.' => {},
						_ => bail!(ErrorKind::MalformedLine(line_num))
					}
				}
				line_in_block += 1;
			}
		}

		Ok(Box::new(ret))
	}
}

fn parse_rules(
	line_num: usize,
	line: &str,
	gd: &mut DefaultGameDescriptor
) -> errors::Result<()> {
	use regex::Regex;

	let regex = Regex::new("#R\\s*(\\d+)\\s*/\\s*(\\d+)\\s*")
		.expect("invalid regex!");

	if let Some(captures) = regex.captures(line) {
		let survival = captures.get(1)
			.expect("Failed to get regex group")
			.as_str();
		let birth = captures.get(2)
			.expect("Failed to get regex group")
			.as_str();

		for char in survival.chars() {
			let digit = char.to_digit(10)
				.expect("Failed to parse u8") as u8;
			gd.add_survival(digit);
		}

		for char in birth.chars() {
			let digit = char.to_digit(10)
				.expect("Failed to parse u8") as u8;
			gd.add_birth(digit);
		}

		Ok(())
	} else {
		bail!(ErrorKind::MalformedLine(line_num))
	}
}

fn parse_offset(
	line_num: usize,
	line: &str,
) -> errors::Result<(i16, i16)> {
	use regex::Regex;

	let regex = Regex::new("#P\\s*([+-]?\\d+)\\s*([+-]?\\d+)\\s*").expect("Invalid regex");
	if let Some(captures) = regex.captures(line) {
		let x = captures.get(1).unwrap().as_str();
		let y = captures.get(2).unwrap().as_str();

		let x = x.parse::<i16>()
			.map_err(|_| Error::from(ErrorKind::CoordinateOutOfRange(line_num)))?;
		let y = y.parse::<i16>()
			.map_err(|_| Error::from(ErrorKind::CoordinateOutOfRange(line_num)))?;

		Ok((x, y))
	} else {
		bail!(errors::ErrorKind::MalformedLine(line_num))
	}
}

fn check_file_format(line: &str) -> errors::Result<()> {
	use regex::Regex;

	let regex = Regex::new("#Life\\s+1.05").expect("Invalid regex");
	if regex.is_match(line) {
		Ok(())
	} else {
		bail!(ErrorKind::InvalidFileFormat)
	}
}

#[cfg(test)]
mod test {
	extern crate io_test_util;

	use super::*;
	use errors::Error;
	use errors::ErrorKind::*;
	use std::io;

	#[test]
	fn parse_rules_should_err() {
		let mut gd = DefaultGameDescriptor::new();
		match parse_rules(5, "#R 23", &mut gd) {
			Err(Error(MalformedLine(5), _)) => {},
			Err(_) => panic!("Wrong error thrown!"),
			_ => panic!("No error thrown!")
		}
	}

	#[test]
	fn parse_rules_should_parse_custom_rules() {
		let mut gd = DefaultGameDescriptor::new();
		parse_rules(1, "#R24 / 1", &mut gd).unwrap();
		assert_eq!(&[2, 4], gd.survival());
		assert_eq!(&[1], gd.birth());
	}

	#[test]
	fn parser_should_understand_default_rules() {
		let mut parser = Life105Parser::new();
		let gd = parser.parse(Box::new("#N".as_bytes())).unwrap();
		assert_eq!(&[2, 3], gd.survival());
		assert_eq!(&[3], gd.birth());
	}

	#[test]
	fn should_correctly_handle_io_errors() {
		use self::io_test_util;

		let mut parser = Life105Parser::new();
		let reader = io_test_util::ErrReader::new(io::ErrorKind::BrokenPipe);

		match parser.parse(Box::new(reader)) {
			Err(Error(IOError(io::ErrorKind::BrokenPipe), _)) => {},
			Err(_) => panic!("Wrong error returned!"),
			_ => panic!("No error returned!")
		}
	}

	#[test]
	fn should_throw_error_on_wrong_format_annotation() {
		let mut parser = Life105Parser::new();
		let input = Box::new("#Life 1.06\n0 0\n1 2".as_bytes());
		let res = parser.parse(input);
		match res {
			Err(Error(InvalidFileFormat, _)) => {},
			Err(Error(x, _)) => panic!("Unexpected error {}", x),
			_ => panic!("No error thrown!"),

		}
	}

	#[test]
	fn should_raise_error_on_invalid_block_header() {
		let mut parser = Life105Parser::new();
		let input = "#P 0 a".as_bytes();
		match parser.parse(Box::new(input)) {
			Err(Error(MalformedLine(1), _)) => {},
			Err(_) => panic!("Wrong error thrown!"),
			_ => panic!("No error thrown!")
		}
	}

	#[test]
	fn parse_offset_should_handle_too_big_coords() {
		match parse_offset(1, "#P 0 32768") {
			Err(Error(CoordinateOutOfRange(1), _)) => {},
			Err(_) => panic!("Wrong error thrown!"),
			Ok(_) => panic!("No error thrown!")
		}
	}

	#[test]
	fn should_raise_error_on_unexpected_character_in_block() {
		let input = Box::new("#P -1 -1\n..*#".as_bytes());
		let mut parser = Life105Parser::new();
		match parser.parse(input) {
			Err(Error(MalformedLine(2), _)) => {},
			_ => panic!("Expected MalformedLine")
		}
	}

	#[test]
	fn should_handle_too_big_horizontal_coords() {
		let input = Box::new("#P 32767 0\n**".as_bytes());

		let mut parser = Life105Parser::new();
		let result = parser.parse(input);
		match result {
			Err(Error(CoordinateOutOfRange(2), _)) => {},
			_ => panic!("Expected CoordinateOutOfRange")
		}
	}
}
<commit_msg>now correctly handling too big y coordinates in 1.05 parser<commit_after>use std::io::{BufRead, BufReader, Read};
use super::Parser;
use ::errors::{self, Error, ErrorKind};
use ::GameDescriptor;
use ::default_game_descriptor::DefaultGameDescriptor;
use std::i16;

/// Parser for files in the life 1.05 format.
pub struct Life105Parser {}

impl Life105Parser {
	/// Construct a new instance.
	pub fn new() -> Self {
		Life105Parser{}
	}
}

impl Parser for Life105Parser {
	fn parse<'a>(&mut self, input: Box<Read + 'a>) -> errors::Result<Box<GameDescriptor>> {
		let mut ret = DefaultGameDescriptor::new();

		let mut offset = None;
		let mut line_in_block: i16 = 0;
		for (line_num, line) in BufReader::new(input).lines().enumerate() {
			let line_num = line_num + 1; // line numbers don't start at 0
			let line = line
				.map_err(|err| errors::ErrorKind::IOError(err.kind()))?;
			let line = line.trim();

			if line.starts_with("#R") {
				ret.clear_rules();
				parse_rules(line_num, &line, &mut ret)?;
			} else if line.starts_with("#Life") {
				check_file_format(line)?;
			} else if line.starts_with("#N") {
				ret.clear_rules();
				ret.add_survival(2);
				ret.add_survival(3);
				ret.add_birth(3);
			} else if line.starts_with("#P") {
				offset = Some(parse_offset(line_num, &line)?);
				line_in_block = 0;
			} else if let Some((ox, oy)) = offset {
				for (index, char) in line.chars().enumerate() {
					let index_with_offset = index as i32 + ox as i32;
					if index_with_offset > i16::MAX as i32 {
						bail!(ErrorKind::CoordinateOutOfRange(line_num));
					}
					let line_in_block_with_offset = line_in_block as i32 + oy as i32;
					if line_in_block_with_offset > i16::MAX as i32 {
						bail!(ErrorKind::CoordinateOutOfRange(line_num));
					}
					match char {
						'*' => ret.add_live_cell(index as i16 + ox, line_in_block + oy),
						'.' => {},
						_ => bail!(ErrorKind::MalformedLine(line_num))
					}
				}
				line_in_block += 1;
			}
		}

		Ok(Box::new(ret))
	}
}

fn parse_rules(
	line_num: usize,
	line: &str,
	gd: &mut DefaultGameDescriptor
) -> errors::Result<()> {
	use regex::Regex;

	let regex = Regex::new("#R\\s*(\\d+)\\s*/\\s*(\\d+)\\s*")
		.expect("invalid regex!");

	if let Some(captures) = regex.captures(line) {
		let survival = captures.get(1)
			.expect("Failed to get regex group")
			.as_str();
		let birth = captures.get(2)
			.expect("Failed to get regex group")
			.as_str();

		for char in survival.chars() {
			let digit = char.to_digit(10)
				.expect("Failed to parse u8") as u8;
			gd.add_survival(digit);
		}

		for char in birth.chars() {
			let digit = char.to_digit(10)
				.expect("Failed to parse u8") as u8;
			gd.add_birth(digit);
		}

		Ok(())
	} else {
		bail!(ErrorKind::MalformedLine(line_num))
	}
}

fn parse_offset(
	line_num: usize,
	line: &str,
) -> errors::Result<(i16, i16)> {
	use regex::Regex;

	let regex = Regex::new("#P\\s*([+-]?\\d+)\\s*([+-]?\\d+)\\s*").expect("Invalid regex");
	if let Some(captures) = regex.captures(line) {
		let x = captures.get(1).unwrap().as_str();
		let y = captures.get(2).unwrap().as_str();

		let x = x.parse::<i16>()
			.map_err(|_| Error::from(ErrorKind::CoordinateOutOfRange(line_num)))?;
		let y = y.parse::<i16>()
			.map_err(|_| Error::from(ErrorKind::CoordinateOutOfRange(line_num)))?;

		Ok((x, y))
	} else {
		bail!(errors::ErrorKind::MalformedLine(line_num))
	}
}

fn check_file_format(line: &str) -> errors::Result<()> {
	use regex::Regex;

	let regex = Regex::new("#Life\\s+1.05").expect("Invalid regex");
	if regex.is_match(line) {
		Ok(())
	} else {
		bail!(ErrorKind::InvalidFileFormat)
	}
}

#[cfg(test)]
mod test {
	extern crate io_test_util;

	use super::*;
	use errors::Error;
	use errors::ErrorKind::*;
	use std::io;

	#[test]
	fn parse_rules_should_err() {
		let mut gd = DefaultGameDescriptor::new();
		match parse_rules(5, "#R 23", &mut gd) {
			Err(Error(MalformedLine(5), _)) => {},
			Err(_) => panic!("Wrong error thrown!"),
			_ => panic!("No error thrown!")
		}
	}

	#[test]
	fn parse_rules_should_parse_custom_rules() {
		let mut gd = DefaultGameDescriptor::new();
		parse_rules(1, "#R24 / 1", &mut gd).unwrap();
		assert_eq!(&[2, 4], gd.survival());
		assert_eq!(&[1], gd.birth());
	}

	#[test]
	fn parser_should_understand_default_rules() {
		let mut parser = Life105Parser::new();
		let gd = parser.parse(Box::new("#N".as_bytes())).unwrap();
		assert_eq!(&[2, 3], gd.survival());
		assert_eq!(&[3], gd.birth());
	}

	#[test]
	fn should_correctly_handle_io_errors() {
		use self::io_test_util;

		let mut parser = Life105Parser::new();
		let reader = io_test_util::ErrReader::new(io::ErrorKind::BrokenPipe);

		match parser.parse(Box::new(reader)) {
			Err(Error(IOError(io::ErrorKind::BrokenPipe), _)) => {},
			Err(_) => panic!("Wrong error returned!"),
			_ => panic!("No error returned!")
		}
	}

	#[test]
	fn should_throw_error_on_wrong_format_annotation() {
		let mut parser = Life105Parser::new();
		let input = Box::new("#Life 1.06\n0 0\n1 2".as_bytes());
		let res = parser.parse(input);
		match res {
			Err(Error(InvalidFileFormat, _)) => {},
			Err(Error(x, _)) => panic!("Unexpected error {}", x),
			_ => panic!("No error thrown!"),

		}
	}

	#[test]
	fn should_raise_error_on_invalid_block_header() {
		let mut parser = Life105Parser::new();
		let input = "#P 0 a".as_bytes();
		match parser.parse(Box::new(input)) {
			Err(Error(MalformedLine(1), _)) => {},
			Err(_) => panic!("Wrong error thrown!"),
			_ => panic!("No error thrown!")
		}
	}

	#[test]
	fn parse_offset_should_handle_too_big_coords() {
		match parse_offset(1, "#P 0 32768") {
			Err(Error(CoordinateOutOfRange(1), _)) => {},
			Err(_) => panic!("Wrong error thrown!"),
			Ok(_) => panic!("No error thrown!")
		}
	}

	#[test]
	fn should_raise_error_on_unexpected_character_in_block() {
		let input = Box::new("#P -1 -1\n..*#".as_bytes());
		let mut parser = Life105Parser::new();
		match parser.parse(input) {
			Err(Error(MalformedLine(2), _)) => {},
			_ => panic!("Expected MalformedLine")
		}
	}

	#[test]
	fn should_handle_too_big_horizontal_coords() {
		let input = Box::new("#P 32767 0\n**".as_bytes());

		let mut parser = Life105Parser::new();
		let result = parser.parse(input);
		match result {
			Err(Error(CoordinateOutOfRange(2), _)) => {},
			_ => panic!("Expected CoordinateOutOfRange")
		}
	}

	#[test]
	fn should_handle_too_big_vertical_coords() {
		let input = Box::new("#P 0 32767\n.\n*".as_bytes());

		let mut parser = Life105Parser::new();
		let result = parser.parse(input);
		match result {
			Err(Error(CoordinateOutOfRange(2), _)) => {},
			Err(x) => println!("XXX {:?}", x),
			_ => panic!("Expected CoordinateOutOfRange")
		}
	}
}
<|endoftext|>


<commit_before>//! The main service handler
//!
//! Parses incoming messages and delegates them to the appropriate individual message handlers,
//! passing on the results to the [`main_loop`](../main_loop/index.html)

use jsonrpc;
use jsonrpc::{OkResponse, ErrResponse};

use std::io::{Read, Write};
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Sender;
use std::thread;
use std::thread::sleep_ms;

use time;
use hyper::server::{Handler, Request, Response};
use rustc_serialize::{json, Decodable};
use rustc_serialize::json::Json;

use rvi::{Message, ServiceEdge};

use message::{BackendServices, Notification};
use handler::{NotifyParams, StartParams, ChunkParams, FinishParams};
use handler::{ReportParams, AbortParams, HandleMessageParams};
use persistence::Transfers;
use configuration::Configuration;

/// Encodes the list of service URLs the client registered.
///
/// Needs to be extended to introduce new services.
#[derive(RustcEncodable, Clone)]
pub struct LocalServices {
    /// "Start Download" URL.
    pub start: String,
    /// "Chunk" URL.
    pub chunk: String,
    /// "Abort Download" URL.
    pub abort: String,
    /// "Finish Download" URL.
    pub finish: String,
    /// "Get All Packages" URL.
    pub getpackages: String,
}

impl LocalServices {
    /// Returns the VIN of this device.
    ///
    /// # Arguments
    /// * `vin_match`: The index, where to look for the VIN in the service URL.
    pub fn get_vin(&self, vin_match: i32) -> String {
        self.start.split("/").nth(vin_match as usize).unwrap().to_string()
    }
}

/// Type that encodes a single service handler.
///
/// Holds the necessary state, like in-progress transfers, that are needed for handling incoming
/// messages and sending replies to RVI. Needs to be thread safe as
/// [`hyper`](../../../hyper/index.html) handles requests asynchronously.
pub struct ServiceHandler {
    /// The full URL, where RVI can be reached.
    rvi_url: String,
    /// A `Sender` that connects the handlers with the `main_loop`.
    sender: Mutex<Sender<Notification>>,
    /// The service URLs that the SOTA server advertised.
    services: Mutex<BackendServices>,
    /// The currently in-progress `Transfer`s.
    transfers: Arc<Mutex<Transfers>>,
    /// The full `Configuration` of sota_client.
    conf: Configuration,
    /// The VIN of this device, as returned by RVI.
    vin: String
}

impl ServiceHandler {
    /// Create a new `ServiceHandler`.
    ///
    /// # Arguments
    /// * `transfers`: A `Transfers` object to store the in-progress `Transfer`s.
    /// * `sender`: A `Sender` to call back into the `main_loop`.
    /// * `url`: The full URL, where RVI can be reached.
    /// * `c`: The full `Configuration` of sota_client.
    pub fn new(sender: Sender<Notification>,
               url: String,
               c: Configuration) -> ServiceHandler {
        let services = BackendServices {
            start: String::new(),
            ack: String::new(),
            report: String::new(),
            packages: String::new()
        };
        let transfers = Arc::new(Mutex::new(Transfers::new(c.client.storage_dir.clone())));
        let tc = transfers.clone();
        c.client.timeout
            .map(|t| {
                let _ = thread::spawn(move || ServiceHandler::start_timer(tc.deref(), t));
                info!("Transfers timeout after {}", t)})
            .unwrap_or(info!("No timeout configured, transfers will never time out."));

        ServiceHandler {
            rvi_url: url,
            sender: Mutex::new(sender),
            services: Mutex::new(services),
            transfers: transfers,
            vin: String::new(),
            conf: c
        }
    }

    pub fn start(mut self, edge: ServiceEdge) -> LocalServices {
        edge.register_service("/sota/notify");
        let svcs = LocalServices {
            start: edge.register_service("/sota/start"),
            chunk: edge.register_service("/sota/chunk"),
            abort: edge.register_service("/sota/abort"),
            finish: edge.register_service("/sota/finish"),
            getpackages: edge.register_service("/sota/getpackages")
        };
        self.vin = svcs.get_vin(self.conf.client.vin_match);
        thread::spawn(move || edge.start(self));
        svcs
    }

    /// Starts a infinite loop to expire timed out transfers. Checks once a second for timed out
    /// transfers.
    ///
    /// # Arguments
    /// * `transfers`: Pointer to a `Transfers` object, that stores the transfers to be checked for
    ///   expired timeouts.
    /// * `timeout`: The timeout in seconds.
    pub fn start_timer(transfers: &Mutex<Transfers>,
                       timeout: i64) {
        loop {
            sleep_ms(1000);
            let mut transfers = transfers.lock().unwrap();
            transfers.prune(time::get_time().sec, timeout);
        }
    }

    /// Helper function to send a `Notification` to the `main_loop`.
    ///
    /// # Arguments
    /// * `m`: `Notification` to send.
    fn push_notify(&self, m: Notification) {
        try_or!(self.sender.lock().unwrap().send(m), return);
    }

    /// Create a message handler `D`, and let it process the `message`. If it returns a
    /// Notification, forward it to the `main_loop`. Returns a `jsonrpc` response indicating
    /// success or failure.
    ///
    /// # Arguments
    /// * `message`: The message, that should be handled.
    fn handle_message_params<D>(&self, message: &str)
        -> Option<Result<OkResponse<i32>, ErrResponse>>
        where D: Decodable + HandleMessageParams {
        json::decode::<jsonrpc::Request<Message<D>>>(&message).map(|p| {
            let handler = &p.params.parameters[0];
            handler.handle(&self.services,
                           &self.transfers,
                           &self.rvi_url,
                           &self.vin).map(|r| {
                r.map(|m| { self.push_notify(m); });
                OkResponse::new(p.id, None)
            }).map_err(|_| ErrResponse::unspecified(p.id))
        }).ok()
    }

    /// Try to parse the type of a message and forward it to the appropriate message handler.
    /// Returns the result of the message handling or a `jsonrpc` result indicating a parser error.
    ///
    /// Needs to be extended to support new services.
    ///
    /// # Arguments
    /// * `message`: The message that will be parsed.
    fn handle_message(&self, message: &str)
        -> Result<OkResponse<i32>, ErrResponse> {
        macro_rules! handle_params {
            ($handler:ident, $message:ident, $service:ident, $id:ident,
             $( $x:ty, $i:expr), *) => {{
                $(
                    if $i == $service {
                        match $handler.handle_message_params::<$x>($message) {
                            Some(r) => return r,
                            None => return Err(ErrResponse::invalid_params($id))
                        }
                    }
                )*
            }}
        }

        let data = try!(Json::from_str(message)
                        .map_err(|_| ErrResponse::parse_error()));
        let obj = try!(data.as_object().ok_or(ErrResponse::parse_error()));
        let rpc_id = try!(obj.get("id").and_then(|x| x.as_u64())
                          .ok_or(ErrResponse::parse_error()));

        let method = try!(obj.get("method").and_then(|x| x.as_string())
                          .ok_or(ErrResponse::invalid_request(rpc_id)));

        if method == "services_available" {
            Ok(OkResponse::new(rpc_id, None))
        }
        else if method != "message" {
            Err(ErrResponse::method_not_found(rpc_id))
        } else {
            let service = try!(obj.get("params")
                               .and_then(|x| x.as_object())
                               .and_then(|x| x.get("service_name"))
                               .and_then(|x| x.as_string())
                               .ok_or(ErrResponse::invalid_request(rpc_id)));

            handle_params!(self, message, service, rpc_id,
                           NotifyParams, "/sota/notify",
                           StartParams,  "/sota/start",
                           ChunkParams,  "/sota/chunk",
                           FinishParams, "/sota/finish",
                           ReportParams, "/sota/getpackages",
                           AbortParams,  "/sota/abort");

            Err(ErrResponse::invalid_request(rpc_id))
        }
    }
}

impl Handler for ServiceHandler {
    fn handle(&self, mut req: Request, resp: Response) {
        let mut rbody = String::new();
        try_or!(req.read_to_string(&mut rbody), return);
        debug!(">>> Received Message: {}", rbody);
        let mut resp = try_or!(resp.start(), return);

        macro_rules! send_response {
            ($rtype:ty, $resp:ident) => {
                match json::encode::<$rtype>(&$resp) {
                    Ok(decoded_msg) => {
                        try_or!(resp.write_all(decoded_msg.as_bytes()), return);
                        debug!("<<< Sent Response: {}", decoded_msg);
                    },
                    Err(p) => { error!("{}", p); }
                }
            };
        }

        match self.handle_message(&rbody) {
            Ok(msg) => { send_response!(OkResponse<i32>, msg) },
            Err(msg) => { send_response!(ErrResponse, msg) }
        }

        try_or!(resp.end(), return);
    }
}
<commit_msg>Redo handle_message_params in ServiceHandler<commit_after>//! The main service handler
//!
//! Parses incoming messages and delegates them to the appropriate individual message handlers,
//! passing on the results to the [`main_loop`](../main_loop/index.html)

use jsonrpc;
use jsonrpc::{OkResponse, ErrResponse};

use std::io::{Read, Write};
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Sender;
use std::thread;
use std::thread::sleep_ms;

use time;
use hyper::server::{Handler, Request, Response};
use rustc_serialize::{json, Decodable};
use rustc_serialize::json::Json;

use rvi::{Message, ServiceEdge};

use message::{BackendServices, Notification};
use handler::{NotifyParams, StartParams, ChunkParams, FinishParams};
use handler::{ReportParams, AbortParams, HandleMessageParams};
use persistence::Transfers;
use configuration::Configuration;

/// Encodes the list of service URLs the client registered.
///
/// Needs to be extended to introduce new services.
#[derive(RustcEncodable, Clone)]
pub struct LocalServices {
    /// "Start Download" URL.
    pub start: String,
    /// "Chunk" URL.
    pub chunk: String,
    /// "Abort Download" URL.
    pub abort: String,
    /// "Finish Download" URL.
    pub finish: String,
    /// "Get All Packages" URL.
    pub getpackages: String,
}

impl LocalServices {
    /// Returns the VIN of this device.
    ///
    /// # Arguments
    /// * `vin_match`: The index, where to look for the VIN in the service URL.
    pub fn get_vin(&self, vin_match: i32) -> String {
        self.start.split("/").nth(vin_match as usize).unwrap().to_string()
    }
}

/// Type that encodes a single service handler.
///
/// Holds the necessary state, like in-progress transfers, that are needed for handling incoming
/// messages and sending replies to RVI. Needs to be thread safe as
/// [`hyper`](../../../hyper/index.html) handles requests asynchronously.
pub struct ServiceHandler {
    /// The full URL, where RVI can be reached.
    rvi_url: String,
    /// A `Sender` that connects the handlers with the `main_loop`.
    sender: Mutex<Sender<Notification>>,
    /// The service URLs that the SOTA server advertised.
    services: Mutex<BackendServices>,
    /// The currently in-progress `Transfer`s.
    transfers: Arc<Mutex<Transfers>>,
    /// The full `Configuration` of sota_client.
    conf: Configuration,
    /// The VIN of this device, as returned by RVI.
    vin: String
}

impl ServiceHandler {
    /// Create a new `ServiceHandler`.
    ///
    /// # Arguments
    /// * `transfers`: A `Transfers` object to store the in-progress `Transfer`s.
    /// * `sender`: A `Sender` to call back into the `main_loop`.
    /// * `url`: The full URL, where RVI can be reached.
    /// * `c`: The full `Configuration` of sota_client.
    pub fn new(sender: Sender<Notification>,
               url: String,
               c: Configuration) -> ServiceHandler {
        let services = BackendServices {
            start: String::new(),
            ack: String::new(),
            report: String::new(),
            packages: String::new()
        };
        let transfers = Arc::new(Mutex::new(Transfers::new(c.client.storage_dir.clone())));
        let tc = transfers.clone();
        c.client.timeout
            .map(|t| {
                let _ = thread::spawn(move || ServiceHandler::start_timer(tc.deref(), t));
                info!("Transfers timeout after {}", t)})
            .unwrap_or(info!("No timeout configured, transfers will never time out."));

        ServiceHandler {
            rvi_url: url,
            sender: Mutex::new(sender),
            services: Mutex::new(services),
            transfers: transfers,
            vin: String::new(),
            conf: c
        }
    }

    pub fn start(mut self, edge: ServiceEdge) -> LocalServices {
        edge.register_service("/sota/notify");
        let svcs = LocalServices {
            start: edge.register_service("/sota/start"),
            chunk: edge.register_service("/sota/chunk"),
            abort: edge.register_service("/sota/abort"),
            finish: edge.register_service("/sota/finish"),
            getpackages: edge.register_service("/sota/getpackages")
        };
        self.vin = svcs.get_vin(self.conf.client.vin_match);
        thread::spawn(move || edge.start(self));
        svcs
    }

    /// Starts a infinite loop to expire timed out transfers. Checks once a second for timed out
    /// transfers.
    ///
    /// # Arguments
    /// * `transfers`: Pointer to a `Transfers` object, that stores the transfers to be checked for
    ///   expired timeouts.
    /// * `timeout`: The timeout in seconds.
    pub fn start_timer(transfers: &Mutex<Transfers>,
                       timeout: i64) {
        loop {
            sleep_ms(1000);
            let mut transfers = transfers.lock().unwrap();
            transfers.prune(time::get_time().sec, timeout);
        }
    }

    /// Helper function to send a `Notification` to the `main_loop`.
    ///
    /// # Arguments
    /// * `m`: `Notification` to send.
    fn push_notify(&self, m: Notification) {
        try_or!(self.sender.lock().unwrap().send(m), return);
    }

    /// Create a message handler `D`, and let it process the `message`. If it returns a
    /// Notification, forward it to the `main_loop`. Returns a `jsonrpc` response indicating
    /// success or failure.
    ///
    /// # Arguments
    /// * `message`: The message, that should be handled.
    fn handle_message_params<D>(&self, id: u64, message: &str)
        -> Result<OkResponse<i32>, ErrResponse>
        where D: Decodable + HandleMessageParams {
        json::decode::<jsonrpc::Request<Message<D>>>(&message)
            .map_err(|_| ErrResponse::invalid_params(id))
            .and_then(|p| {
                let handler = &p.params.parameters[0];
                handler.handle(&self.services, &self.transfers, &self.rvi_url, &self.vin)
                    .map_err(|_| ErrResponse::unspecified(p.id))
                    .map(|r| {
                        r.map(|m| self.push_notify(m));
                        OkResponse::new(p.id, None) })
            })
        }

    /// Try to parse the type of a message and forward it to the appropriate message handler.
    /// Returns the result of the message handling or a `jsonrpc` result indicating a parser error.
    ///
    /// Needs to be extended to support new services.
    ///
    /// # Arguments
    /// * `message`: The message that will be parsed.
    fn handle_message(&self, message: &str)
        -> Result<OkResponse<i32>, ErrResponse> {
        macro_rules! handle_params {
            ($handler:ident, $message:ident, $service:ident, $id:ident,
             $( $x:ty, $i:expr), *) => {{
                $(
                    if $i == $service {
                        return $handler.handle_message_params::<$x>($id, $message)
                    }
                )*
            }}
        }

        let data = try!(Json::from_str(message)
                        .map_err(|_| ErrResponse::parse_error()));
        let obj = try!(data.as_object().ok_or(ErrResponse::parse_error()));
        let rpc_id = try!(obj.get("id").and_then(|x| x.as_u64())
                          .ok_or(ErrResponse::parse_error()));

        let method = try!(obj.get("method").and_then(|x| x.as_string())
                          .ok_or(ErrResponse::invalid_request(rpc_id)));

        if method == "services_available" {
            Ok(OkResponse::new(rpc_id, None))
        }
        else if method != "message" {
            Err(ErrResponse::method_not_found(rpc_id))
        } else {
            let service = try!(obj.get("params")
                               .and_then(|x| x.as_object())
                               .and_then(|x| x.get("service_name"))
                               .and_then(|x| x.as_string())
                               .ok_or(ErrResponse::invalid_request(rpc_id)));

            handle_params!(self, message, service, rpc_id,
                           NotifyParams, "/sota/notify",
                           StartParams,  "/sota/start",
                           ChunkParams,  "/sota/chunk",
                           FinishParams, "/sota/finish",
                           ReportParams, "/sota/getpackages",
                           AbortParams,  "/sota/abort");

            Err(ErrResponse::invalid_request(rpc_id))
        }
    }
}

impl Handler for ServiceHandler {
    fn handle(&self, mut req: Request, resp: Response) {
        let mut rbody = String::new();
        try_or!(req.read_to_string(&mut rbody), return);
        debug!(">>> Received Message: {}", rbody);
        let mut resp = try_or!(resp.start(), return);

        macro_rules! send_response {
            ($rtype:ty, $resp:ident) => {
                match json::encode::<$rtype>(&$resp) {
                    Ok(decoded_msg) => {
                        try_or!(resp.write_all(decoded_msg.as_bytes()), return);
                        debug!("<<< Sent Response: {}", decoded_msg);
                    },
                    Err(p) => { error!("{}", p); }
                }
            };
        }

        match self.handle_message(&rbody) {
            Ok(msg) => { send_response!(OkResponse<i32>, msg) },
            Err(msg) => { send_response!(ErrResponse, msg) }
        }

        try_or!(resp.end(), return);
    }
}
<|endoftext|>


<commit_before>use color::Colorf32;
use fastup::{self, Node, parse_for_first_node, parse_color};
use stats_once::{MEM_TOTAL, MEM_USED};
use super::error_node;
use std::ops::{Add, Sub, Mul, Div};

#[derive(Debug, Copy, Clone, Default)]
pub struct Widget;

impl super::Widget for Widget {
    fn expand(&self, args: Vec<String>) -> Node {
        match args.len() {
            2 => node_from_args(args),
            3 => node_from_args(args),  // debug only
            _ => error_node("(ccdd44: mem) takes 2 arguments: color-cold\\|color-hot"),
        }
    }
}

fn node_from_args(args: Vec<String>) -> Node {
    try_node_from_args(args).unwrap_or_else(|e| error_node(&e))
}

fn try_node_from_args(args: Vec<String>) -> Result<Node, String> {
    assert!(args.len() == 2 || args.len() == 3);

    let cold = parse_color(&args[0]).map_err(escape_fastup)?;
    let hot = parse_color(&args[1]).map_err(escape_fastup)?;
    let mem_total = *MEM_TOTAL;
    let mem_used = {
        if args.len() == 3 {
            args[2].parse().map_err(escape_fastup)?
        } else {
            *MEM_USED
        }
    };

    Ok(mem_node(cold.into(), hot.into(), mem_used, mem_total))
}

fn mem_node(cold: Colorf32, hot: Colorf32, mem_used: i32, mem_total: i32) -> Node {
    const NONE_LIGHTNESS: f32 = 0.15;
    const FULL_LIGHTNESS: f32 = 0.7;
    const TEXT_LIGHTNESS_BOOST_NONE: f32 = 0.15;
    const TEXT_LIGHTNESS_BOOST_FULL: f32 = 0.25;

    let mem_usage = (mem_used as f32) / (mem_total as f32);

    let none_cold = cold.set_lightness(NONE_LIGHTNESS);
    let none_hot = hot.set_lightness(NONE_LIGHTNESS);
    let none = none_cold.mix(none_hot, mem_usage);

    let full_lightness = remap(mem_usage, 0.0, 1.0, NONE_LIGHTNESS, FULL_LIGHTNESS);
    let full_cold = cold.set_lightness(full_lightness);
    let full_hot = hot.set_lightness(full_lightness);
    let full = full_cold.mix(full_hot, mem_usage);

    let text_lightness_boost = remap(mem_usage,
                                     0.0,
                                     1.0,
                                     TEXT_LIGHTNESS_BOOST_NONE,
                                     TEXT_LIGHTNESS_BOOST_FULL);
    let text_lightness = full_lightness + text_lightness_boost;
    let text_cold = cold.set_lightness(text_lightness);
    let text_hot = hot.set_lightness(text_lightness);
    let text = text_cold.mix(text_hot, mem_usage);

    let percent = (100.0 * mem_usage) as i32;
    let usage = format!(" {:>4}M{:>3}% ", mem_used, percent);
    let width = usage.len() as i32;

    let (fully_filled_cells, partial_fill_rate) = quantize(mem_usage, width);
    let partial = none.mix(full, partial_fill_rate);

    let none = none.clamp_to_888();
    let full = full.clamp_to_888();
    let text = text.clamp_to_888();
    let partial = partial.clamp_to_888();

    let partition = zipper_split(&usage, fully_filled_cells as usize);
    let (full_cells, partial_cell, none_cells) = partition;
    let usage = format!("[{}:{}][{}:{}][{}:{}]",
                        full,
                        escape_fastup(full_cells),
                        partial,
                        escape_fastup(partial_cell),
                        none,
                        escape_fastup(none_cells));

    let node = format!("({}:{})", text, usage);
    parse_for_first_node(&node).unwrap()
}

fn escape_fastup<T>(input: T) -> String
    where T: ToString
{
    fastup::escape_for_text(&input.to_string())
}

/// Linearly remap `x` from inclusive range [`xa`, `xb`] to
/// inclusive range [`ra`, `rb`]. `x` must fall inside [`xa`, `xb`],
/// or panic will be issued.
fn remap<T>(x: T, xa: T, xb: T, ra: T, rb: T) -> T
    where T: PartialOrd + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Copy
{
    assert!(xa <= x && x <= xb);
    (x - xa) * (rb - ra) / (xb - xa) + ra
}

/// Returns (quantized, remaining)
fn quantize(x: f32, steps: i32) -> (i32, f32) {
    let x = x * (steps as f32);
    let quantized = x.floor();
    let remaining = x - quantized;
    let quantized = quantized as i32;
    (quantized, remaining)
}

fn byte_index_from_char_index(s: &str, nchar: usize) -> usize {
    s.chars().take(nchar).map(|ch| ch.len_utf8()).sum()
}

fn split_at_char_index(s: &str, at: usize) -> (&str, &str) {
    let at = byte_index_from_char_index(s, at);
    s.split_at(at)
}

/// ```text
/// zipper_split("hello world", 3)
///                  ^--------- at = 3
///
/// Returns ("hel", "l", "o world")
/// ```
fn zipper_split(s: &str, at: usize) -> (&str, &str, &str) {
    let (first, rest) = split_at_char_index(s, at);
    let (elem, last) = split_at_char_index(rest, 1);
    (first, elem, last)
}

<commit_msg>widget: <mem> total mem usage also can be overriden<commit_after>use color::Colorf32;
use fastup::{self, Node, parse_for_first_node, parse_color};
use stats_once::{MEM_TOTAL, MEM_USED};
use super::error_node;
use std::ops::{Add, Sub, Mul, Div};

#[derive(Debug, Copy, Clone, Default)]
pub struct Widget;

impl super::Widget for Widget {
    fn expand(&self, args: Vec<String>) -> Node {
        match args.len() {
            2 => node_from_args(args),
            3 | 4 => node_from_args(args),  // debug only
            _ => error_node("(ccdd44: mem) takes 2 arguments: color-cold\\|color-hot"),
        }
    }
}

fn node_from_args(args: Vec<String>) -> Node {
    try_node_from_args(args).unwrap_or_else(|e| error_node(&e))
}

fn try_node_from_args(args: Vec<String>) -> Result<Node, String> {
    assert!(args.len() == 2 || (args.len() == 3 || args.len() == 4));

    let cold = parse_color(&args[0]).map_err(escape_fastup)?;
    let hot = parse_color(&args[1]).map_err(escape_fastup)?;
    let mem_total = {
        if args.len() >= 4 {
            args[3].parse().map_err(escape_fastup)?
        } else {
            *MEM_TOTAL
        }
    };
    let mem_used = {
        if args.len() >= 3 {
            args[2].parse().map_err(escape_fastup)?
        } else {
            *MEM_USED
        }
    };

    Ok(mem_node(cold.into(), hot.into(), mem_used, mem_total))
}

fn mem_node(cold: Colorf32, hot: Colorf32, mem_used: i32, mem_total: i32) -> Node {
    const NONE_LIGHTNESS: f32 = 0.15;
    const FULL_LIGHTNESS: f32 = 0.7;
    const TEXT_LIGHTNESS_BOOST_NONE: f32 = 0.15;
    const TEXT_LIGHTNESS_BOOST_FULL: f32 = 0.25;

    let mem_usage = (mem_used as f32) / (mem_total as f32);

    let none_cold = cold.set_lightness(NONE_LIGHTNESS);
    let none_hot = hot.set_lightness(NONE_LIGHTNESS);
    let none = none_cold.mix(none_hot, mem_usage);

    let full_lightness = remap(mem_usage, 0.0, 1.0, NONE_LIGHTNESS, FULL_LIGHTNESS);
    let full_cold = cold.set_lightness(full_lightness);
    let full_hot = hot.set_lightness(full_lightness);
    let full = full_cold.mix(full_hot, mem_usage);

    let text_lightness_boost = remap(mem_usage,
                                     0.0,
                                     1.0,
                                     TEXT_LIGHTNESS_BOOST_NONE,
                                     TEXT_LIGHTNESS_BOOST_FULL);
    let text_lightness = full_lightness + text_lightness_boost;
    let text_cold = cold.set_lightness(text_lightness);
    let text_hot = hot.set_lightness(text_lightness);
    let text = text_cold.mix(text_hot, mem_usage);

    let percent = (100.0 * mem_usage) as i32;
    let usage = format!(" {:>4}M{:>3}% ", mem_used, percent);
    let width = usage.len() as i32;

    let (fully_filled_cells, partial_fill_rate) = quantize(mem_usage, width);
    let partial = none.mix(full, partial_fill_rate);

    let none = none.clamp_to_888();
    let full = full.clamp_to_888();
    let text = text.clamp_to_888();
    let partial = partial.clamp_to_888();

    let partition = zipper_split(&usage, fully_filled_cells as usize);
    let (full_cells, partial_cell, none_cells) = partition;
    let usage = format!("[{}:{}][{}:{}][{}:{}]",
                        full,
                        escape_fastup(full_cells),
                        partial,
                        escape_fastup(partial_cell),
                        none,
                        escape_fastup(none_cells));

    let node = format!("({}:{})", text, usage);
    parse_for_first_node(&node).unwrap()
}

fn escape_fastup<T>(input: T) -> String
    where T: ToString
{
    fastup::escape_for_text(&input.to_string())
}

/// Linearly remap `x` from inclusive range [`xa`, `xb`] to
/// inclusive range [`ra`, `rb`]. `x` must fall inside [`xa`, `xb`],
/// or panic will be issued.
fn remap<T>(x: T, xa: T, xb: T, ra: T, rb: T) -> T
    where T: PartialOrd + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Copy
{
    assert!(xa <= x && x <= xb);
    (x - xa) * (rb - ra) / (xb - xa) + ra
}

/// Returns (quantized, remaining)
fn quantize(x: f32, steps: i32) -> (i32, f32) {
    let x = x * (steps as f32);
    let quantized = x.floor();
    let remaining = x - quantized;
    let quantized = quantized as i32;
    (quantized, remaining)
}

fn byte_index_from_char_index(s: &str, nchar: usize) -> usize {
    s.chars().take(nchar).map(|ch| ch.len_utf8()).sum()
}

fn split_at_char_index(s: &str, at: usize) -> (&str, &str) {
    let at = byte_index_from_char_index(s, at);
    s.split_at(at)
}

/// ```text
/// zipper_split("hello world", 3)
///                  ^--------- at = 3
///
/// Returns ("hel", "l", "o world")
/// ```
fn zipper_split(s: &str, at: usize) -> (&str, &str, &str) {
    let (first, rest) = split_at_char_index(s, at);
    let (elem, last) = split_at_char_index(rest, 1);
    (first, elem, last)
}

<|endoftext|>


<commit_before>//! Linear operator algebra

use ndarray::*;

pub trait LinearOperator {
    /// Apply operator out-place
    fn apply<S: Data>(&self, a: &ArrayBase<S, Ix1>) -> Array1<S::Elem> {
        self.apply_tensor(a, 0)
    }
    /// Apply operator in-place
    fn apply_mut<S: DataMut>(&self, a: &mut ArrayBase<S, Ix1>) {
        self.apply_tensor_mut(a, 0)
    }
    /// Apply operator with move
    fn apply_into<S: DataOwned + DataMut>(&self, a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix1> {
        self.apply_tensor_into(a, 0)
    }

    /// Apply operator to matrix out-place
    fn apply2<S: Data>(&self, a: &ArrayBase<S, Ix2>) -> Array2<S::Elem> {
        self.apply_tensor(a, 0)
    }
    /// Apply operator to matrix in-place
    fn apply2_mut<S: DataMut>(&self, a: &mut ArrayBase<S, Ix2>) {
        self.apply_tensor_mut(a, 0)
    }
    /// Apply operator to matrix with move
    fn apply2_into<S: DataOwned + DataMut>(&self, a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2> {
        self.apply_tensor_into(a, 0)
    }

    /// Apply operator to the n-th index of the tensor (out-place)
    fn apply_tensor<S, D>(&self, a: &ArrayBase<S, D>, n: usize) -> Array<S::Elem, D>
    where
        S: Data,
        D: Dimension;
    /// Apply operator to the n-th index of the tensor (in-place)
    fn apply_tensor_mut<S, D>(&self, a: &mut ArrayBase<S, D>, n: usize)
    where
        S: DataMut,
        D: Dimension;
    /// Apply operator to the n-th index of the tensor (with move)
    fn apply_tensor_into<S, D>(&self, a: ArrayBase<S, D>, n: usize) -> ArrayBase<S, D>
    where
        S: DataOwned + DataMut,
        D: Dimension;
}
<commit_msg>Remove apply_tensor*<commit_after>//! Linear operator algebra

use crate::generate::hstack;
use crate::types::*;
use ndarray::*;

pub trait LinearOperator {
    /// Apply operator out-place
    fn apply<S>(&self, a: &ArrayBase<S, Ix1>) -> Array1<S::Elem>
    where
        S: Data,
        S::Elem: Scalar,
    {
        let mut a = a.to_owned();
        self.apply_mut(&mut a);
        a
    }
    /// Apply operator in-place
    fn apply_mut<S>(&self, a: &mut ArrayBase<S, Ix1>)
    where
        S: DataMut,
        S::Elem: Scalar;
    /// Apply operator with move
    fn apply_into<S>(&self, mut a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix1>
    where
        S: DataOwned + DataMut,
        S::Elem: Scalar,
    {
        self.apply_mut(&mut a);
        a
    }

    /// Apply operator to matrix out-place
    fn apply2<S>(&self, a: &ArrayBase<S, Ix2>) -> Array2<S::Elem>
    where
        S: Data,
        S::Elem: Scalar,
    {
        let cols: Vec<_> = a.axis_iter(Axis(0)).map(|col| self.apply(&col)).collect();
        hstack(&cols).unwrap()
    }
    /// Apply operator to matrix in-place
    fn apply2_mut<S>(&self, a: &mut ArrayBase<S, Ix2>)
    where
        S: DataMut,
        S::Elem: Scalar,
    {
        for mut col in a.axis_iter_mut(Axis(0)) {
            self.apply_mut(&mut col)
        }
    }
    /// Apply operator to matrix with move
    fn apply2_into<S>(&self, mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where
        S: DataOwned + DataMut,
        S::Elem: Scalar,
    {
        self.apply2_mut(&mut a);
        a
    }
}
<|endoftext|>