<commit_before>use std::cmp::min;

use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, Element, ElementResult, SetAttributes};
use crate::error::*;
use crate::node::{CascadedValues, Node, NodeBorrow};
use crate::parsers::{NumberList, NumberListLength, Parse, ParseValue};
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::{
    iterators::Pixels, shared_surface::ExclusiveImageSurface, ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;
use crate::xml::Attributes;

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

/// The `feComponentTransfer` filter primitive.
pub struct FeComponentTransfer {
    base: Primitive,
    in1: Input,
}

/// Resolved `feComponentTransfer` primitive for rendering.
pub struct ComponentTransfer {
    in1: Input,
    functions: Functions,
    color_interpolation_filters: ColorInterpolationFilters,
}

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

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

/// Pixel components that can be influenced by `feComponentTransfer`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Channel {
    R,
    G,
    B,
    A,
}

/// Component transfer function types.
#[derive(Clone, Debug, PartialEq)]
enum FunctionType {
    Identity,
    Table,
    Discrete,
    Linear,
    Gamma,
}

impl Parse for FunctionType {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "identity" => FunctionType::Identity,
            "table" => FunctionType::Table,
            "discrete" => FunctionType::Discrete,
            "linear" => FunctionType::Linear,
            "gamma" => FunctionType::Gamma,
        )?)
    }
}

/// The compute function parameters.
struct FunctionParameters {
    table_values: Vec<f64>,
    slope: f64,
    intercept: f64,
    amplitude: f64,
    exponent: f64,
    offset: f64,
}

#[derive(Debug, PartialEq)]
struct Functions {
    r: FeFuncR,
    g: FeFuncG,
    b: FeFuncB,
    a: FeFuncA,
}

/// The compute function type.
type Function = fn(&FunctionParameters, f64) -> f64;

/// The identity component transfer function.
fn identity(_: &FunctionParameters, value: f64) -> f64 {
    value
}

/// The table component transfer function.
fn table(params: &FunctionParameters, value: f64) -> f64 {
    let n = params.table_values.len() - 1;
    let k = (value * (n as f64)).floor() as usize;

    let k = min(k, n); // Just in case.

    if k == n {
        return params.table_values[k];
    }

    let vk = params.table_values[k];
    let vk1 = params.table_values[k + 1];
    let k = k as f64;
    let n = n as f64;

    vk + (value - k / n) * n * (vk1 - vk)
}

/// The discrete component transfer function.
fn discrete(params: &FunctionParameters, value: f64) -> f64 {
    let n = params.table_values.len();
    let k = (value * (n as f64)).floor() as usize;

    params.table_values[min(k, n - 1)]
}

/// The linear component transfer function.
fn linear(params: &FunctionParameters, value: f64) -> f64 {
    params.slope * value + params.intercept
}

/// The gamma component transfer function.
fn gamma(params: &FunctionParameters, value: f64) -> f64 {
    params.amplitude * value.powf(params.exponent) + params.offset
}

trait FeComponentTransferFunc {
    /// Returns the component transfer function.
    fn function(&self) -> Function;

    /// Returns the component transfer function parameters.
    fn function_parameters(&self) -> FunctionParameters;

    /// Returns the channel.
    fn channel(&self) -> Channel;
}

macro_rules! func_x {
    ($func_name:ident, $channel:expr) => {
        #[derive(Clone, Debug, PartialEq)]
        pub struct $func_name {
            channel: Channel,
            function_type: FunctionType,
            table_values: Vec<f64>,
            slope: f64,
            intercept: f64,
            amplitude: f64,
            exponent: f64,
            offset: f64,
        }

        impl Default for $func_name {
            #[inline]
            fn default() -> Self {
                Self {
                    channel: $channel,
                    function_type: FunctionType::Identity,
                    table_values: Vec::new(),
                    slope: 1.0,
                    intercept: 0.0,
                    amplitude: 1.0,
                    exponent: 1.0,
                    offset: 0.0,
                }
            }
        }

        impl FeComponentTransferFunc for $func_name {
            #[inline]
            fn function_parameters(&self) -> FunctionParameters {
                FunctionParameters {
                    table_values: self.table_values.clone(),
                    slope: self.slope,
                    intercept: self.intercept,
                    amplitude: self.amplitude,
                    exponent: self.exponent,
                    offset: self.offset,
                }
            }

            #[inline]
            fn function(&self) -> Function {
                match self.function_type {
                    FunctionType::Identity => identity,
                    FunctionType::Table => table,
                    FunctionType::Discrete => discrete,
                    FunctionType::Linear => linear,
                    FunctionType::Gamma => gamma,
                }
            }

            #[inline]
            fn channel(&self) -> Channel {
                self.channel
            }
        }

        impl SetAttributes for $func_name {
            #[inline]
            fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
                for (attr, value) in attrs.iter() {
                    match attr.expanded() {
                        expanded_name!("", "type") => self.function_type = attr.parse(value)?,
                        expanded_name!("", "tableValues") => {
                            let NumberList(v) =
                                NumberList::parse_str(value, NumberListLength::Unbounded)
                                    .attribute(attr)?;
                            self.table_values = v;
                        }
                        expanded_name!("", "slope") => self.slope = attr.parse(value)?,
                        expanded_name!("", "intercept") => self.intercept = attr.parse(value)?,
                        expanded_name!("", "amplitude") => self.amplitude = attr.parse(value)?,
                        expanded_name!("", "exponent") => self.exponent = attr.parse(value)?,
                        expanded_name!("", "offset") => self.offset = attr.parse(value)?,

                        _ => (),
                    }
                }

                // The table function type with empty table_values is considered
                // an identity function.
                match self.function_type {
                    FunctionType::Table | FunctionType::Discrete => {
                        if self.table_values.is_empty() {
                            self.function_type = FunctionType::Identity;
                        }
                    }
                    _ => (),
                }

                Ok(())
            }
        }

        impl Draw for $func_name {}
    };
}

// The `<feFuncR>` element
func_x!(FeFuncR, Channel::R);

// The `<feFuncG>` element
func_x!(FeFuncG, Channel::G);

// The `<feFuncB>` element
func_x!(FeFuncB, Channel::B);

// The `<feFuncA>` element
func_x!(FeFuncA, Channel::A);

macro_rules! func_or_default {
    ($func_node:ident, $func_type:ident) => {
        match $func_node {
            Some(ref f) => match *f.borrow_element() {
                Element::$func_type(ref e) => e.element_impl.clone(),
                _ => unreachable!(),
            },
            _ => $func_type::default(),
        };
    };
}

macro_rules! get_func_x_node {
    ($func_node:ident, $func_type:ident, $channel:expr) => {
        $func_node
            .children()
            .rev()
            .filter(|c| c.is_element())
            .find(|c| match *c.borrow_element() {
                Element::$func_type(ref f) => f.channel() == $channel,
                _ => false,
            })
    };
}

impl ComponentTransfer {
    pub fn render(
        &self,
        primitive: &ResolvedPrimitive,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            self.color_interpolation_filters,
        )?;
        let bounds = primitive
            .get_bounds(ctx)?
            .add_input(&input_1)
            .into_irect(ctx, draw_ctx);

        // Create the output surface.
        let mut surface = ExclusiveImageSurface::new(
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
            input_1.surface().surface_type(),
        )?;

        #[inline]
        fn compute_func<F>(func: &F) -> impl Fn(u8, f64, f64) -> u8
        where
            F: FeComponentTransferFunc,
        {
            let compute = func.function();
            let params = func.function_parameters();

            move |value, alpha, new_alpha| {
                let value = f64::from(value) / 255f64;

                let unpremultiplied = if alpha == 0f64 { 0f64 } else { value / alpha };

                let new_value = compute(&params, unpremultiplied);
                let new_value = clamp(new_value, 0f64, 1f64);

                ((new_value * new_alpha * 255f64) + 0.5) as u8
            }
        }

        let compute_r = compute_func::<FeFuncR>(&self.functions.r);
        let compute_g = compute_func::<FeFuncG>(&self.functions.g);
        let compute_b = compute_func::<FeFuncB>(&self.functions.b);

        // Alpha gets special handling since everything else depends on it.
        let compute_a = self.functions.a.function();
        let params_a = self.functions.a.function_parameters();
        let compute_a = |alpha| compute_a(&params_a, alpha);

        // Do the actual processing.
        surface.modify(&mut |data, stride| {
            for (x, y, pixel) in Pixels::within(input_1.surface(), bounds) {
                let alpha = f64::from(pixel.a) / 255f64;
                let new_alpha = compute_a(alpha);

                let output_pixel = Pixel {
                    r: compute_r(pixel.r, alpha, new_alpha),
                    g: compute_g(pixel.g, alpha, new_alpha),
                    b: compute_b(pixel.b, alpha, new_alpha),
                    a: ((new_alpha * 255f64) + 0.5) as u8,
                };

                data.set_pixel(stride, output_pixel, x, y);
            }
        });

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

impl FilterEffect for FeComponentTransfer {
    fn resolve(&self, node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError> {
        let cascaded = CascadedValues::new_from_node(node);
        let values = cascaded.get();

        Ok((
            self.base.clone(),
            PrimitiveParams::ComponentTransfer(ComponentTransfer {
                in1: self.in1.clone(),
                functions: get_functions(node)?,
                color_interpolation_filters: values.color_interpolation_filters(),
            }),
        ))
    }
}

/// Takes a feComponentTransfer and walks its children to produce the feFuncX arguments.
fn get_functions(node: &Node) -> Result<Functions, FilterError> {
    let func_r_node = get_func_x_node!(node, FeFuncR, Channel::R);
    let func_g_node = get_func_x_node!(node, FeFuncG, Channel::G);
    let func_b_node = get_func_x_node!(node, FeFuncB, Channel::B);
    let func_a_node = get_func_x_node!(node, FeFuncA, Channel::A);

    for node in [&func_r_node, &func_g_node, &func_b_node, &func_a_node]
        .iter()
        .filter_map(|x| x.as_ref())
    {
        if node.borrow_element().is_in_error() {
            return Err(FilterError::ChildNodeInError);
        }
    }

    let r = func_or_default!(func_r_node, FeFuncR);
    let g = func_or_default!(func_g_node, FeFuncG);
    let b = func_or_default!(func_b_node, FeFuncB);
    let a = func_or_default!(func_a_node, FeFuncA);

    Ok(Functions { r, g, b, a })
}

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

    #[test]
    fn extracts_functions() {
        let document = Document::load_from_bytes(
            br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <filter id="filter">
    <feComponentTransfer id="component_transfer">
      <!-- no feFuncR so it should get the defaults -->

      <feFuncG type="table" tableValues="0.0 1.0 2.0"/>

      <feFuncB type="table"/>
      <!-- duplicate this to test that last-one-wins -->
      <feFuncB type="discrete" tableValues="0.0, 1.0" slope="1.0" intercept="2.0" amplitude="3.0" exponent="4.0" offset="5.0"/>

      <!-- no feFuncA so it should get the defaults -->
    </feComponentTransfer>
  </filter>
</svg>
"#
        );

        let component_transfer = document.lookup_internal_node("component_transfer").unwrap();
        let functions = get_functions(&component_transfer).unwrap();

        assert_eq!(
            functions,
            Functions {
                r: FeFuncR::default(),

                g: FeFuncG {
                    function_type: FunctionType::Table,
                    table_values: vec![0.0, 1.0, 2.0],
                    ..FeFuncG::default()
                },

                b: FeFuncB {
                    function_type: FunctionType::Discrete,
                    table_values: vec![0.0, 1.0],
                    slope: 1.0,
                    intercept: 2.0,
                    amplitude: 3.0,
                    exponent: 4.0,
                    offset: 5.0,
                    ..FeFuncB::default()
                },

                a: FeFuncA::default(),
            }
        );
    }
}
<commit_msg>feComponentTransfer: shorten code by implementing Default and Clone for its parameters<commit_after>use std::cmp::min;

use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, Element, ElementResult, SetAttributes};
use crate::error::*;
use crate::node::{CascadedValues, Node, NodeBorrow};
use crate::parsers::{NumberList, NumberListLength, Parse, ParseValue};
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::{
    iterators::Pixels, shared_surface::ExclusiveImageSurface, ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;
use crate::xml::Attributes;

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

/// The `feComponentTransfer` filter primitive.
#[derive(Default)]
pub struct FeComponentTransfer {
    base: Primitive,
    params: ComponentTransfer,
}

/// Resolved `feComponentTransfer` primitive for rendering.
#[derive(Clone, Default)]
pub struct ComponentTransfer {
    in1: Input,
    functions: Functions,
    color_interpolation_filters: ColorInterpolationFilters,
}

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

/// Pixel components that can be influenced by `feComponentTransfer`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Channel {
    R,
    G,
    B,
    A,
}

/// Component transfer function types.
#[derive(Clone, Debug, PartialEq)]
enum FunctionType {
    Identity,
    Table,
    Discrete,
    Linear,
    Gamma,
}

impl Parse for FunctionType {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "identity" => FunctionType::Identity,
            "table" => FunctionType::Table,
            "discrete" => FunctionType::Discrete,
            "linear" => FunctionType::Linear,
            "gamma" => FunctionType::Gamma,
        )?)
    }
}

/// The compute function parameters.
struct FunctionParameters {
    table_values: Vec<f64>,
    slope: f64,
    intercept: f64,
    amplitude: f64,
    exponent: f64,
    offset: f64,
}

#[derive(Clone, Debug, Default, PartialEq)]
struct Functions {
    r: FeFuncR,
    g: FeFuncG,
    b: FeFuncB,
    a: FeFuncA,
}

/// The compute function type.
type Function = fn(&FunctionParameters, f64) -> f64;

/// The identity component transfer function.
fn identity(_: &FunctionParameters, value: f64) -> f64 {
    value
}

/// The table component transfer function.
fn table(params: &FunctionParameters, value: f64) -> f64 {
    let n = params.table_values.len() - 1;
    let k = (value * (n as f64)).floor() as usize;

    let k = min(k, n); // Just in case.

    if k == n {
        return params.table_values[k];
    }

    let vk = params.table_values[k];
    let vk1 = params.table_values[k + 1];
    let k = k as f64;
    let n = n as f64;

    vk + (value - k / n) * n * (vk1 - vk)
}

/// The discrete component transfer function.
fn discrete(params: &FunctionParameters, value: f64) -> f64 {
    let n = params.table_values.len();
    let k = (value * (n as f64)).floor() as usize;

    params.table_values[min(k, n - 1)]
}

/// The linear component transfer function.
fn linear(params: &FunctionParameters, value: f64) -> f64 {
    params.slope * value + params.intercept
}

/// The gamma component transfer function.
fn gamma(params: &FunctionParameters, value: f64) -> f64 {
    params.amplitude * value.powf(params.exponent) + params.offset
}

trait FeComponentTransferFunc {
    /// Returns the component transfer function.
    fn function(&self) -> Function;

    /// Returns the component transfer function parameters.
    fn function_parameters(&self) -> FunctionParameters;

    /// Returns the channel.
    fn channel(&self) -> Channel;
}

macro_rules! func_x {
    ($func_name:ident, $channel:expr) => {
        #[derive(Clone, Debug, PartialEq)]
        pub struct $func_name {
            channel: Channel,
            function_type: FunctionType,
            table_values: Vec<f64>,
            slope: f64,
            intercept: f64,
            amplitude: f64,
            exponent: f64,
            offset: f64,
        }

        impl Default for $func_name {
            #[inline]
            fn default() -> Self {
                Self {
                    channel: $channel,
                    function_type: FunctionType::Identity,
                    table_values: Vec::new(),
                    slope: 1.0,
                    intercept: 0.0,
                    amplitude: 1.0,
                    exponent: 1.0,
                    offset: 0.0,
                }
            }
        }

        impl FeComponentTransferFunc for $func_name {
            #[inline]
            fn function_parameters(&self) -> FunctionParameters {
                FunctionParameters {
                    table_values: self.table_values.clone(),
                    slope: self.slope,
                    intercept: self.intercept,
                    amplitude: self.amplitude,
                    exponent: self.exponent,
                    offset: self.offset,
                }
            }

            #[inline]
            fn function(&self) -> Function {
                match self.function_type {
                    FunctionType::Identity => identity,
                    FunctionType::Table => table,
                    FunctionType::Discrete => discrete,
                    FunctionType::Linear => linear,
                    FunctionType::Gamma => gamma,
                }
            }

            #[inline]
            fn channel(&self) -> Channel {
                self.channel
            }
        }

        impl SetAttributes for $func_name {
            #[inline]
            fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
                for (attr, value) in attrs.iter() {
                    match attr.expanded() {
                        expanded_name!("", "type") => self.function_type = attr.parse(value)?,
                        expanded_name!("", "tableValues") => {
                            let NumberList(v) =
                                NumberList::parse_str(value, NumberListLength::Unbounded)
                                    .attribute(attr)?;
                            self.table_values = v;
                        }
                        expanded_name!("", "slope") => self.slope = attr.parse(value)?,
                        expanded_name!("", "intercept") => self.intercept = attr.parse(value)?,
                        expanded_name!("", "amplitude") => self.amplitude = attr.parse(value)?,
                        expanded_name!("", "exponent") => self.exponent = attr.parse(value)?,
                        expanded_name!("", "offset") => self.offset = attr.parse(value)?,

                        _ => (),
                    }
                }

                // The table function type with empty table_values is considered
                // an identity function.
                match self.function_type {
                    FunctionType::Table | FunctionType::Discrete => {
                        if self.table_values.is_empty() {
                            self.function_type = FunctionType::Identity;
                        }
                    }
                    _ => (),
                }

                Ok(())
            }
        }

        impl Draw for $func_name {}
    };
}

// The `<feFuncR>` element
func_x!(FeFuncR, Channel::R);

// The `<feFuncG>` element
func_x!(FeFuncG, Channel::G);

// The `<feFuncB>` element
func_x!(FeFuncB, Channel::B);

// The `<feFuncA>` element
func_x!(FeFuncA, Channel::A);

macro_rules! func_or_default {
    ($func_node:ident, $func_type:ident) => {
        match $func_node {
            Some(ref f) => match *f.borrow_element() {
                Element::$func_type(ref e) => e.element_impl.clone(),
                _ => unreachable!(),
            },
            _ => $func_type::default(),
        };
    };
}

macro_rules! get_func_x_node {
    ($func_node:ident, $func_type:ident, $channel:expr) => {
        $func_node
            .children()
            .rev()
            .filter(|c| c.is_element())
            .find(|c| match *c.borrow_element() {
                Element::$func_type(ref f) => f.channel() == $channel,
                _ => false,
            })
    };
}

impl ComponentTransfer {
    pub fn render(
        &self,
        primitive: &ResolvedPrimitive,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            self.color_interpolation_filters,
        )?;
        let bounds = primitive
            .get_bounds(ctx)?
            .add_input(&input_1)
            .into_irect(ctx, draw_ctx);

        // Create the output surface.
        let mut surface = ExclusiveImageSurface::new(
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
            input_1.surface().surface_type(),
        )?;

        #[inline]
        fn compute_func<F>(func: &F) -> impl Fn(u8, f64, f64) -> u8
        where
            F: FeComponentTransferFunc,
        {
            let compute = func.function();
            let params = func.function_parameters();

            move |value, alpha, new_alpha| {
                let value = f64::from(value) / 255f64;

                let unpremultiplied = if alpha == 0f64 { 0f64 } else { value / alpha };

                let new_value = compute(&params, unpremultiplied);
                let new_value = clamp(new_value, 0f64, 1f64);

                ((new_value * new_alpha * 255f64) + 0.5) as u8
            }
        }

        let compute_r = compute_func::<FeFuncR>(&self.functions.r);
        let compute_g = compute_func::<FeFuncG>(&self.functions.g);
        let compute_b = compute_func::<FeFuncB>(&self.functions.b);

        // Alpha gets special handling since everything else depends on it.
        let compute_a = self.functions.a.function();
        let params_a = self.functions.a.function_parameters();
        let compute_a = |alpha| compute_a(&params_a, alpha);

        // Do the actual processing.
        surface.modify(&mut |data, stride| {
            for (x, y, pixel) in Pixels::within(input_1.surface(), bounds) {
                let alpha = f64::from(pixel.a) / 255f64;
                let new_alpha = compute_a(alpha);

                let output_pixel = Pixel {
                    r: compute_r(pixel.r, alpha, new_alpha),
                    g: compute_g(pixel.g, alpha, new_alpha),
                    b: compute_b(pixel.b, alpha, new_alpha),
                    a: ((new_alpha * 255f64) + 0.5) as u8,
                };

                data.set_pixel(stride, output_pixel, x, y);
            }
        });

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

impl FilterEffect for FeComponentTransfer {
    fn resolve(&self, node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError> {
        let cascaded = CascadedValues::new_from_node(node);
        let values = cascaded.get();

        let mut params = self.params.clone();
        params.functions = get_functions(node)?;
        params.color_interpolation_filters = values.color_interpolation_filters();

        Ok((
            self.base.clone(),
            PrimitiveParams::ComponentTransfer(params),
        ))
    }
}

/// Takes a feComponentTransfer and walks its children to produce the feFuncX arguments.
fn get_functions(node: &Node) -> Result<Functions, FilterError> {
    let func_r_node = get_func_x_node!(node, FeFuncR, Channel::R);
    let func_g_node = get_func_x_node!(node, FeFuncG, Channel::G);
    let func_b_node = get_func_x_node!(node, FeFuncB, Channel::B);
    let func_a_node = get_func_x_node!(node, FeFuncA, Channel::A);

    for node in [&func_r_node, &func_g_node, &func_b_node, &func_a_node]
        .iter()
        .filter_map(|x| x.as_ref())
    {
        if node.borrow_element().is_in_error() {
            return Err(FilterError::ChildNodeInError);
        }
    }

    let r = func_or_default!(func_r_node, FeFuncR);
    let g = func_or_default!(func_g_node, FeFuncG);
    let b = func_or_default!(func_b_node, FeFuncB);
    let a = func_or_default!(func_a_node, FeFuncA);

    Ok(Functions { r, g, b, a })
}

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

    #[test]
    fn extracts_functions() {
        let document = Document::load_from_bytes(
            br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <filter id="filter">
    <feComponentTransfer id="component_transfer">
      <!-- no feFuncR so it should get the defaults -->

      <feFuncG type="table" tableValues="0.0 1.0 2.0"/>

      <feFuncB type="table"/>
      <!-- duplicate this to test that last-one-wins -->
      <feFuncB type="discrete" tableValues="0.0, 1.0" slope="1.0" intercept="2.0" amplitude="3.0" exponent="4.0" offset="5.0"/>

      <!-- no feFuncA so it should get the defaults -->
    </feComponentTransfer>
  </filter>
</svg>
"#
        );

        let component_transfer = document.lookup_internal_node("component_transfer").unwrap();
        let functions = get_functions(&component_transfer).unwrap();

        assert_eq!(
            functions,
            Functions {
                r: FeFuncR::default(),

                g: FeFuncG {
                    function_type: FunctionType::Table,
                    table_values: vec![0.0, 1.0, 2.0],
                    ..FeFuncG::default()
                },

                b: FeFuncB {
                    function_type: FunctionType::Discrete,
                    table_values: vec![0.0, 1.0],
                    slope: 1.0,
                    intercept: 2.0,
                    amplitude: 3.0,
                    exponent: 4.0,
                    offset: 5.0,
                    ..FeFuncB::default()
                },

                a: FeFuncA::default(),
            }
        );
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate vst2;

use vst2::buffer::AudioBuffer;
use vst2::plugin::{Category, Plugin, Info};
use vst2::event::{Event};

use std::f64::consts::PI;

fn midi_note_to_hz(note: u8) -> f64 {
    let a = 440.0; // a0 is 440 hz...
    (a / 32.0) * ((note as f64 - 9.0) / 12.0).exp2()
}

fn sample_count<'a>(buff: &Vec<&'a mut [f32]>) -> Option<usize> {
    buff.first().map(|b| b.len() )
}

struct SineSynth {
    sample_rate: f64,
    time: f64,
    note_duration: f64,
    note: Option<u8>,
}

impl SineSynth {
    fn time_per_sample(&self) -> f64 {
        1.0 / self.sample_rate
    }

    // midiData[0] : Contains the status and the channel http://www.midimountain.com/midi/midi_status.htm
    // midiData[1] : Contains the supplemental data for the message - so, if this was a NoteOn then this would contain the note.
    // midiData[2] : Further supplemental data. Would be velocity in the case of a NoteOn message.
    // midiData[3] : Reserved.
    fn process_midi_event(&mut self, data: [u8; 3]) {
        match data[0] {
            128 => self.note_off(data[1]),
            144 => self.note_on(data[1]),
            _ => ()
        }
    }

    fn note_on(&mut self, note: u8) {
        self.note_duration = 0.0;
        self.note = Some(note)
    }

    fn note_off(&mut self, note: u8) {
        if self.note == Some(note) {
            self.note = None
        }
    }
}

pub const TAU : f64 = PI * 2.0;

impl Default for SineSynth {
    fn default() -> SineSynth {
        SineSynth {
            sample_rate: 44100.0,
            note_duration: 0.0,
            time: 0.0,
            note: None,
        }
    }
}

impl Plugin for SineSynth {

    fn get_info(&self) -> Info {
        Info {
            name: "SineSynth".to_string(),
            vendor: "DeathDisco".to_string(),
            unique_id: 6667,
            category: Category::Synth,
            inputs: 2,
            outputs: 2,
            parameters: 0,
            initial_delay: 0,
            ..Info::default()
        }
    }

    #[allow(unused_variables)]
    fn process_events(&mut self, events: Vec<Event>) {
        for event in events {
            match event {
                Event::Midi { data, delta_frames, live,
                          note_length, note_offset,
                          detune, note_off_velocity } => self.process_midi_event(data),
                _ => ()
            }
        }
    }

    fn set_sample_rate(&mut self, rate: f32) {
        self.sample_rate = rate as f64;
    }

    fn process(&mut self, buffer: AudioBuffer<f32>) {
        let (inputs, outputs) = buffer.split();

        let samples = sample_count(&inputs).expect("some damn samples once in a while");
        let per_sample = self.time_per_sample();

        for (input_buffer, output_buffer) in inputs.iter().zip(outputs) {
            let mut t = self.time;
            for (_, output_sample) in input_buffer.iter().zip(output_buffer) {

                if let Some(current_note) = self.note {
                    let signal = (t * midi_note_to_hz(current_note) * TAU).sin();

                    // apply a quick envelope to the attack of the signal to avoid popping.
                    let attack = 0.5;
                    let alpha = if self.note_duration < attack {
                        self.note_duration / attack
                    } else {
                        1.0
                    };

                    *output_sample = (signal * alpha) as f32;

                    t += per_sample;
                } else {
                    *output_sample = 0.0;
                }
            }
        }

        self.time += samples as f64 * per_sample;
        self.note_duration += samples as f64 * per_sample;
    }
}

plugin_main!(SineSynth);
<commit_msg>Clean up sine_synth example<commit_after>#[macro_use] extern crate vst2;

use vst2::buffer::AudioBuffer;
use vst2::plugin::{Category, Plugin, Info};
use vst2::event::{Event};

use std::f64::consts::PI;

/// Convert the midi note into the equivalent frequency.
///
/// This function assumes A4 is 440hz.
fn midi_note_to_hz(note: u8) -> f64 {
    const A4: f64 = 440.0;

    (A4 / 32.0) * ((note as f64 - 9.0) / 12.0).exp2()
}

struct SineSynth {
    sample_rate: f64,
    time: f64,
    note_duration: f64,
    note: Option<u8>,
}

impl SineSynth {
    fn time_per_sample(&self) -> f64 {
        1.0 / self.sample_rate
    }

    /// Process an incoming midi event.
    ///
    /// The midi data is split up like so:
    ///
    /// `data[0]`: Contains the status and the channel. Source: [source]
    /// `data[1]`: Contains the supplemental data for the message - so, if this was a NoteOn then
    ///            this would contain the note.
    /// `data[2]`: Further supplemental data. Would be velocity in the case of a NoteOn message.
    ///
    /// [source]: http://www.midimountain.com/midi/midi_status.htm
    fn process_midi_event(&mut self, data: [u8; 3]) {
        match data[0] {
            128 => self.note_off(data[1]),
            144 => self.note_on(data[1]),
            _ => ()
        }
    }

    fn note_on(&mut self, note: u8) {
        self.note_duration = 0.0;
        self.note = Some(note)
    }

    fn note_off(&mut self, note: u8) {
        if self.note == Some(note) {
            self.note = None
        }
    }
}

pub const TAU : f64 = PI * 2.0;

impl Default for SineSynth {
    fn default() -> SineSynth {
        SineSynth {
            sample_rate: 44100.0,
            note_duration: 0.0,
            time: 0.0,
            note: None,
        }
    }
}

impl Plugin for SineSynth {
    fn get_info(&self) -> Info {
        Info {
            name: "SineSynth".to_string(),
            vendor: "DeathDisco".to_string(),
            unique_id: 6667,
            category: Category::Synth,
            inputs: 2,
            outputs: 2,
            parameters: 0,
            initial_delay: 0,
            ..Info::default()
        }
    }

    #[allow(unused_variables)]
    fn process_events(&mut self, events: Vec<Event>) {
        for event in events {
            match event {
                Event::Midi { data, ..  } => self.process_midi_event(data),
                // More events can be handled here.
                _ => {}
            }
        }
    }

    fn set_sample_rate(&mut self, rate: f32) {
        self.sample_rate = rate as f64;
    }

    fn process(&mut self, buffer: AudioBuffer<f32>) {
        let (inputs, outputs) = buffer.split();

        let samples = inputs
            .first()
            .map(|channel| channel.len())
            .unwrap_or(0);

        let per_sample = self.time_per_sample();

        for (input_buffer, output_buffer) in inputs.iter().zip(outputs) {
            let mut t = self.time;

            for (_, output_sample) in input_buffer.iter().zip(output_buffer) {
                if let Some(current_note) = self.note {
                    let signal = (t * midi_note_to_hz(current_note) * TAU).sin();

                    // Apply a quick envelope to the attack of the signal to avoid popping.
                    let attack = 0.5;
                    let alpha = if self.note_duration < attack {
                        self.note_duration / attack
                    } else {
                        1.0
                    };

                    *output_sample = (signal * alpha) as f32;

                    t += per_sample;
                } else {
                    *output_sample = 0.0;
                }
            }
        }

        self.time += samples as f64 * per_sample;
        self.note_duration += samples as f64 * per_sample;
    }
}

plugin_main!(SineSynth);
<|endoftext|>


<commit_before>#![feature(phase)]

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

use std::os;
use std::io::{BufferedStream, File, IoResult};
use std::from_str::FromStr;
use regex::Regex;

static SPACES: Regex = regex!("[ \t]+");

#[deriving(Show)]
enum Month {
    January = 1,
    February = 2,
    March = 3,
    April = 4,
    May = 5,
    June = 6,
    July = 7,
    August = 8,
    September = 9,
    October = 10,
    November = 11,
    December = 12,
}

#[deriving(Show)]
enum DayOfWeek {
    Sunday = 0,
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
}

#[deriving(Show)]
enum Period {
    Reboot,
    Daily,
    Weekly,
    Monthly,
    Yearly,
}

impl FromStr for Period {
    fn from_str(s: &str) -> Option<Period> {
        match s {
            "@reboot"  => Some(Reboot),
            "@daily"   => Some(Daily),
            "@weekly"  => Some(Weekly),
            "@monthly" => Some(Monthly),
            "@yearly"  => Some(Yearly),
            _ => None,
        }
    }
}

#[deriving(Show)]
struct Minute(uint);

#[deriving(Show)]
struct Hour(uint);

#[deriving(Show)]
struct Day(uint);

#[deriving(Show)]
enum CrontabEntry {
    Periodic(Vec<Minute>, Vec<Hour>, Vec<Day>, Vec<Month>, Vec<DayOfWeek>, String),
    Monotonic(Period, String),
}

impl CrontabEntry {
    fn new(parts: Vec<String>) -> Option<CrontabEntry> {
        match parts.len() {
            6 => {
                Some(Periodic(
                    vec![Minute(0)],
                    vec![Hour(0)],
                    vec![Day(0)],
                    vec![January],
                    vec![Sunday],
                    "command".into_string(),
                ))
            }
            _ => None
        }
    }
}

struct CrontabIterator<'i> {
    lines: &'i mut Iterator<IoResult<String>>,
}

impl<'i> CrontabIterator<'i> {
    fn new(iter: &'i mut Iterator<IoResult<String>>) -> CrontabIterator<'i> {
        CrontabIterator {
            lines: iter
        }
    }
}

impl<'i> Iterator<CrontabEntry> for CrontabIterator<'i> {
    fn next(&mut self) -> Option<CrontabEntry> {
        loop {
            match self.lines.next() {
                None => return None,
                Some(Err(_)) => return None,

                Some(Ok(line)) => {
                    let line = line.as_slice().trim();

                    if line.starts_with("#") {
                        continue;
                    }

                    let parts = SPACES.splitn(line, 6).map(|p| p.into_string()).collect();

                    return Some(CrontabEntry::new(parts).unwrap());
                }
            }
        }
    }
}

fn main() {
    let args: Vec<String> = os::args();

    let file = File::open(&Path::new("/var/spool/cron/kstep")).unwrap();
    let mut buffer = BufferedStream::new(file);
    let mut lines = buffer.lines();
    let mut crontab = CrontabIterator::new(&mut lines);

    println!("target dir: {}", args.get(1));

    for line in crontab {
        println!("line: {}", line);
    }
}
<commit_msg>WIP: rust step 4<commit_after>#![feature(phase)]

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

use std::os;
use std::io::{BufferedStream, File, IoResult};
use std::from_str::FromStr;
use regex::Regex;
use std::num::from_int;

static SPACES: Regex = regex!("[ \t]+");

#[deriving(Show)]
enum Month {
    January = 1,
    February = 2,
    March = 3,
    April = 4,
    May = 5,
    June = 6,
    July = 7,
    August = 8,
    September = 9,
    October = 10,
    November = 11,
    December = 12,
}

#[deriving(Show, FromPrimitive)]
enum DayOfWeek {
    Sunday = 0,
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
}

#[deriving(Show)]
enum Period {
    Reboot,
    Daily,
    Weekly,
    Monthly,
    Yearly,
}

impl FromStr for Period {
    fn from_str(s: &str) -> Option<Period> {
        match s {
            "@reboot"  => Some(Reboot),
            "@daily"   => Some(Daily),
            "@weekly"  => Some(Weekly),
            "@monthly" => Some(Monthly),
            "@yearly"  => Some(Yearly),
            "@midnight" => Some(Daily),
            "@annually" => Some(Yearly),
            "1" => Some(Daily),
            "7" => Some(Weekly),
            _ => None,
        }
    }
}

impl FromStr for DayOfWeek {
    fn from_str(s: &str) -> Option<DayOfWeek> {
        match s.slice(0, 3).chars().map(|c| c.to_lowercase()).collect::<String>().as_slice() {
            "sun" => Some(Sunday),
            "mon" => Some(Monday),
            "tue" => Some(Tuesday),
            "wed" => Some(Wednesday),
            "thu" => Some(Thursday),
            "fri" => Some(Friday),
            "sat" => Some(Saturday),
            v => match from_str::<int>(v) {
                Some(n) => from_int::<DayOfWeek>(n % 7),
                None => None,
            },
        }
    }
}

#[deriving(Show)]
struct Minute(uint);

#[deriving(Show)]
struct Hour(uint);

#[deriving(Show)]
struct Day(uint);

#[deriving(Show)]
struct User(String);

#[deriving(Show)]
struct Command(String);

#[deriving(Show)]
enum CrontabEntry {
    Periodic(Vec<Minute>, Vec<Hour>, Vec<Day>, Vec<Month>, Vec<DayOfWeek>, User, Command),
    Monotonic(Period, User, Command),
}

trait RangeEntry<T> {
    fn everything(&self) -> Vec<T>;

    fn to_range(&self, s: &str) -> Vec<T> {
        let all = self.everything();
        if s == "*" {
            return all;
        }

        // TODO: split `s` by comma, detect and exapnd ranges, map to all
    }
}

impl CrontabEntry {
    fn new(parts: Vec<String>) -> Option<CrontabEntry> {
        match parts.len() {
            6 => {
                Some(Periodic(
                    vec![Minute(0)],
                    vec![Hour(0)],
                    vec![Day(0)],
                    vec![January],
                    vec![Sunday],
                    User("root".into_string()),
                    Command("command".into_string()),
                ))
            },
            7 => {
                Some(Periodic(
                    vec![Minute(0)],
                    vec![Hour(0)],
                    vec![Day(0)],
                    vec![January],
                    vec![Sunday],
                    User("root".into_string()),
                    Command("command".into_string()),
                ))
            }
            _ => None
        }
    }
}

struct CrontabIterator<'i> {
    lines: &'i mut Iterator<IoResult<String>>,
}

impl<'i> CrontabIterator<'i> {
    fn new(iter: &'i mut Iterator<IoResult<String>>) -> CrontabIterator<'i> {
        CrontabIterator {
            lines: iter
        }
    }
}

impl<'i> Iterator<CrontabEntry> for CrontabIterator<'i> {
    fn next(&mut self) -> Option<CrontabEntry> {
        loop {
            match self.lines.next() {
                None => return None,
                Some(Err(_)) => return None,

                Some(Ok(line)) => {
                    let line = line.as_slice().trim();

                    if line.starts_with("#") {
                        continue;
                    }

                    let parts = SPACES.splitn(line, 6).map(|p| p.into_string()).collect();

                    return Some(CrontabEntry::new(parts).unwrap());
                }
            }
        }
    }
}

fn main() {
    let args: Vec<String> = os::args();

    let file = File::open(&Path::new("/var/spool/cron/kstep")).unwrap();
    let mut buffer = BufferedStream::new(file);
    let mut lines = buffer.lines();
    let mut crontab = CrontabIterator::new(&mut lines);

    println!("target dir: {}", args.get(1));

    for line in crontab {
        println!("line: {}", line);
    }
}
<|endoftext|>


<commit_before>/// Maximum order of the fixed predictors permitted by the format.
pub const MAX_FIXED_ORDER: usize = 4;

/// Maximum LPC order permitted by the format.
pub const MAX_LPC_ORDER: usize   = 32;

/// A single channel of audio data.
pub struct SubFrame {
  pub data: Data,
  pub wasted_bits: u32,
}

/// General enum that holds all the different subframe data types.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  Constant(i32),
  Verbatim(Vec<i32>),
  Fixed(Fixed),
  LPC(LPC),
}

#[derive(Debug, PartialEq, Eq)]
pub struct Fixed {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub warmup: [i32; MAX_FIXED_ORDER],
  pub residual: Vec<i32>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct LPC {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub qlp_coeff_precision: u8,
  pub quantization_level: i8,
  pub qlp_coefficients: [i32; MAX_LPC_ORDER],
  pub warmup: [i32; MAX_LPC_ORDER],
  pub residual: Vec<i32>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct EntropyCodingMethod {
  pub method_type: CodingMethod,
  pub data: PartitionedRice,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  PartitionedRice,
  PartitionedRice2,
}

#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRice {
  pub order: u32,
  pub contents: PartitionedRiceContents,
}

#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRiceContents {
  pub parameters: Vec<u32>,
  pub raw_bits: Vec<u32>,
  pub capacity_by_order: u32,
}

impl PartitionedRiceContents {
  pub fn new(capacity_by_order: u32) -> PartitionedRiceContents {
    let capacity       = 2_usize.pow(capacity_by_order);
    let mut parameters = Vec::with_capacity(capacity);
    let mut raw_bits   = Vec::with_capacity(capacity);

    unsafe {
      parameters.set_len(capacity);
      raw_bits.set_len(capacity);
    }

    PartitionedRiceContents {
      parameters: parameters,
      raw_bits: raw_bits,
      capacity_by_order: capacity_by_order,
    }
  }
}
<commit_msg>Add documentation for subframe prediction types<commit_after>/// Maximum order of the fixed predictors permitted by the format.
pub const MAX_FIXED_ORDER: usize = 4;

/// Maximum LPC order permitted by the format.
pub const MAX_LPC_ORDER: usize   = 32;

/// A single channel of audio data.
pub struct SubFrame {
  pub data: Data,
  pub wasted_bits: u32,
}

/// General enum that holds all the different subframe data types.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  Constant(i32),
  Verbatim(Vec<i32>),
  Fixed(Fixed),
  LPC(LPC),
}

/// Fixed linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct Fixed {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub warmup: [i32; MAX_FIXED_ORDER],
  pub residual: Vec<i32>,
}

/// Finite Impulse Response (FIR) linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct LPC {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub qlp_coeff_precision: u8,
  pub quantization_level: i8,
  pub qlp_coefficients: [i32; MAX_LPC_ORDER],
  pub warmup: [i32; MAX_LPC_ORDER],
  pub residual: Vec<i32>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct EntropyCodingMethod {
  pub method_type: CodingMethod,
  pub data: PartitionedRice,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  PartitionedRice,
  PartitionedRice2,
}

#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRice {
  pub order: u32,
  pub contents: PartitionedRiceContents,
}

#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRiceContents {
  pub parameters: Vec<u32>,
  pub raw_bits: Vec<u32>,
  pub capacity_by_order: u32,
}

impl PartitionedRiceContents {
  pub fn new(capacity_by_order: u32) -> PartitionedRiceContents {
    let capacity       = 2_usize.pow(capacity_by_order);
    let mut parameters = Vec::with_capacity(capacity);
    let mut raw_bits   = Vec::with_capacity(capacity);

    unsafe {
      parameters.set_len(capacity);
      raw_bits.set_len(capacity);
    }

    PartitionedRiceContents {
      parameters: parameters,
      raw_bits: raw_bits,
      capacity_by_order: capacity_by_order,
    }
  }
}
<|endoftext|>


<commit_before>use shell::{flags::UNTERMINATED, status::*, Binary, FlowLogic, Shell};
use parser::Terminator;

pub(crate) fn terminate_script_quotes<I: Iterator<Item = String>>(
    shell: &mut Shell,
    mut lines: I,
) -> i32 {
    while let Some(command) = lines.next() {
        let mut buffer = Terminator::new(command);
        while !buffer.is_terminated() {
            loop {
                if let Some(command) = lines.next() {
                    if !command.starts_with('#') {
                        let mut start = 0;
                        let cmd: &str = loop {
                            if start >= command.len() {
                                break &command;
                            }

                            match command[start..].find('#').map(|x| x + start) {
                                Some(pos) if command.as_bytes()[pos - 1] != b' ' => {
                                    start = pos + 1;
                                }
                                Some(pos) => break &command[..pos],
                                None => break &command,
                            }
                        };
                        buffer.append(cmd);
                        break;
                    }
                } else {
                    eprintln!("ion: unterminated quote in script");
                    return FAILURE;
                }
            }
        }
        shell.on_command(&buffer.consume());
    }

    if shell.flow_control.unclosed_block() {
        let open_block = shell.flow_control.block.last().unwrap();
        eprintln!(
            "ion: unexpected end of script: expected end block for `{}`",
            open_block.short(),
        );
        return FAILURE;
    }

    SUCCESS
}

pub(crate) fn terminate_quotes(shell: &mut Shell, command: String) -> Result<String, ()> {
    let mut buffer = Terminator::new(command);
    shell.flags |= UNTERMINATED;
    while ! buffer.is_terminated() {
        if let Some(command) = shell.readln() {
            if ! command.starts_with('#') {
                buffer.append(&command);
            }
        } else {
            return Err(());
        }
    }

    shell.flags ^= UNTERMINATED;
    let terminated = buffer.consume();
    Ok(terminated)
}
<commit_msg>Fix Ctrl-C while entering multi-line quoted strings.<commit_after>use shell::{flags::UNTERMINATED, status::*, Binary, FlowLogic, Shell};
use parser::Terminator;

pub(crate) fn terminate_script_quotes<I: Iterator<Item = String>>(
    shell: &mut Shell,
    mut lines: I,
) -> i32 {
    while let Some(command) = lines.next() {
        let mut buffer = Terminator::new(command);
        while !buffer.is_terminated() {
            loop {
                if let Some(command) = lines.next() {
                    if !command.starts_with('#') {
                        let mut start = 0;
                        let cmd: &str = loop {
                            if start >= command.len() {
                                break &command;
                            }

                            match command[start..].find('#').map(|x| x + start) {
                                Some(pos) if command.as_bytes()[pos - 1] != b' ' => {
                                    start = pos + 1;
                                }
                                Some(pos) => break &command[..pos],
                                None => break &command,
                            }
                        };
                        buffer.append(cmd);
                        break;
                    }
                } else {
                    eprintln!("ion: unterminated quote in script");
                    return FAILURE;
                }
            }
        }
        shell.on_command(&buffer.consume());
    }

    if shell.flow_control.unclosed_block() {
        let open_block = shell.flow_control.block.last().unwrap();
        eprintln!(
            "ion: unexpected end of script: expected end block for `{}`",
            open_block.short(),
        );
        return FAILURE;
    }

    SUCCESS
}

pub(crate) fn terminate_quotes(shell: &mut Shell, command: String) -> Result<String, ()> {
    let mut buffer = Terminator::new(command);
    shell.flags |= UNTERMINATED;
    while ! buffer.is_terminated() {
        if let Some(command) = shell.readln() {
            if ! command.starts_with('#') {
                buffer.append(&command);
            }
        } else {
            shell.flags ^= UNTERMINATED;
            return Err(());
        }
    }

    shell.flags ^= UNTERMINATED;
    let terminated = buffer.consume();
    Ok(terminated)
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;

use rand::{thread_rng, Rng};
use test::Bencher;

fn random(n: usize) -> BTreeSet<usize> {
    let mut rng = thread_rng();
    let mut set = BTreeSet::new();
    while set.len() < n {
        set.insert(rng.gen());
    }
    assert_eq!(set.len(), n);
    set
}

fn neg(n: usize) -> BTreeSet<i32> {
    let set: BTreeSet<i32> = (-(n as i32)..=-1).collect();
    assert_eq!(set.len(), n);
    set
}

fn pos(n: usize) -> BTreeSet<i32> {
    let set: BTreeSet<i32> = (1..=(n as i32)).collect();
    assert_eq!(set.len(), n);
    set
}

fn stagger(n1: usize, factor: usize) -> [BTreeSet<u32>; 2] {
    let n2 = n1 * factor;
    let mut sets = [BTreeSet::new(), BTreeSet::new()];
    for i in 0..(n1 + n2) {
        let b = i % (factor + 1) != 0;
        sets[b as usize].insert(i as u32);
    }
    assert_eq!(sets[0].len(), n1);
    assert_eq!(sets[1].len(), n2);
    sets
}

macro_rules! set_bench {
    ($name: ident, $set_func: ident, $result_func: ident, $sets: expr) => {
        #[bench]
        pub fn $name(b: &mut Bencher) {
            // setup
            let sets = $sets;

            // measure
            b.iter(|| sets[0].$set_func(&sets[1]).$result_func())
        }
    };
}

#[bench]
pub fn clone_100(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| src.clone())
}

#[bench]
pub fn clone_100_and_clear(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| src.clone().clear())
}

#[bench]
pub fn clone_100_and_into_iter(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| src.clone().into_iter().count())
}

#[bench]
pub fn clone_100_and_pop_all(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| {
        let mut set = src.clone();
        while set.pop_first().is_some() {}
        set
    });
}

#[bench]
pub fn clone_100_and_remove_all(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| {
        let mut set = src.clone();
        while let Some(elt) = set.iter().copied().next() {
            set.remove(&elt);
        }
        set
    });
}

#[bench]
pub fn clone_100_and_remove_half(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| {
        let mut set = src.clone();
        for i in (2..=100 as i32).step_by(2) {
            set.remove(&i);
        }
        assert_eq!(set.len(), 100 / 2);
        set
    })
}

#[bench]
pub fn clone_10k(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| src.clone())
}

#[bench]
pub fn clone_10k_and_clear(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| src.clone().clear())
}

#[bench]
pub fn clone_10k_and_into_iter(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| src.clone().into_iter().count())
}

#[bench]
pub fn clone_10k_and_pop_all(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| {
        let mut set = src.clone();
        while set.pop_first().is_some() {}
        set
    });
}

#[bench]
pub fn clone_10k_and_remove_all(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| {
        let mut set = src.clone();
        while let Some(elt) = set.iter().copied().next() {
            set.remove(&elt);
        }
        set
    });
}

#[bench]
pub fn clone_10k_and_remove_half(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| {
        let mut set = src.clone();
        for i in (2..=10_000 as i32).step_by(2) {
            set.remove(&i);
        }
        assert_eq!(set.len(), 10_000 / 2);
        set
    })
}

set_bench! {intersection_100_neg_vs_100_pos, intersection, count, [neg(100), pos(100)]}
set_bench! {intersection_100_neg_vs_10k_pos, intersection, count, [neg(100), pos(10_000)]}
set_bench! {intersection_100_pos_vs_100_neg, intersection, count, [pos(100), neg(100)]}
set_bench! {intersection_100_pos_vs_10k_neg, intersection, count, [pos(100), neg(10_000)]}
set_bench! {intersection_10k_neg_vs_100_pos, intersection, count, [neg(10_000), pos(100)]}
set_bench! {intersection_10k_neg_vs_10k_pos, intersection, count, [neg(10_000), pos(10_000)]}
set_bench! {intersection_10k_pos_vs_100_neg, intersection, count, [pos(10_000), neg(100)]}
set_bench! {intersection_10k_pos_vs_10k_neg, intersection, count, [pos(10_000), neg(10_000)]}
set_bench! {intersection_random_100_vs_100, intersection, count, [random(100), random(100)]}
set_bench! {intersection_random_100_vs_10k, intersection, count, [random(100), random(10_000)]}
set_bench! {intersection_random_10k_vs_100, intersection, count, [random(10_000), random(100)]}
set_bench! {intersection_random_10k_vs_10k, intersection, count, [random(10_000), random(10_000)]}
set_bench! {intersection_staggered_100_vs_100, intersection, count, stagger(100, 1)}
set_bench! {intersection_staggered_10k_vs_10k, intersection, count, stagger(10_000, 1)}
set_bench! {intersection_staggered_100_vs_10k, intersection, count, stagger(100, 100)}
set_bench! {difference_random_100_vs_100, difference, count, [random(100), random(100)]}
set_bench! {difference_random_100_vs_10k, difference, count, [random(100), random(10_000)]}
set_bench! {difference_random_10k_vs_100, difference, count, [random(10_000), random(100)]}
set_bench! {difference_random_10k_vs_10k, difference, count, [random(10_000), random(10_000)]}
set_bench! {difference_staggered_100_vs_100, difference, count, stagger(100, 1)}
set_bench! {difference_staggered_10k_vs_10k, difference, count, stagger(10_000, 1)}
set_bench! {difference_staggered_100_vs_10k, difference, count, stagger(100, 100)}
set_bench! {is_subset_100_vs_100, is_subset, clone, [pos(100), pos(100)]}
set_bench! {is_subset_100_vs_10k, is_subset, clone, [pos(100), pos(10_000)]}
set_bench! {is_subset_10k_vs_100, is_subset, clone, [pos(10_000), pos(100)]}
set_bench! {is_subset_10k_vs_10k, is_subset, clone, [pos(10_000), pos(10_000)]}
<commit_msg>Add benchmarks of drain_filter-like behaviour<commit_after>use std::collections::BTreeSet;

use rand::{thread_rng, Rng};
use test::Bencher;

fn random(n: usize) -> BTreeSet<usize> {
    let mut rng = thread_rng();
    let mut set = BTreeSet::new();
    while set.len() < n {
        set.insert(rng.gen());
    }
    assert_eq!(set.len(), n);
    set
}

fn neg(n: usize) -> BTreeSet<i32> {
    let set: BTreeSet<i32> = (-(n as i32)..=-1).collect();
    assert_eq!(set.len(), n);
    set
}

fn pos(n: usize) -> BTreeSet<i32> {
    let set: BTreeSet<i32> = (1..=(n as i32)).collect();
    assert_eq!(set.len(), n);
    set
}

fn stagger(n1: usize, factor: usize) -> [BTreeSet<u32>; 2] {
    let n2 = n1 * factor;
    let mut sets = [BTreeSet::new(), BTreeSet::new()];
    for i in 0..(n1 + n2) {
        let b = i % (factor + 1) != 0;
        sets[b as usize].insert(i as u32);
    }
    assert_eq!(sets[0].len(), n1);
    assert_eq!(sets[1].len(), n2);
    sets
}

macro_rules! set_bench {
    ($name: ident, $set_func: ident, $result_func: ident, $sets: expr) => {
        #[bench]
        pub fn $name(b: &mut Bencher) {
            // setup
            let sets = $sets;

            // measure
            b.iter(|| sets[0].$set_func(&sets[1]).$result_func())
        }
    };
}

#[bench]
pub fn clone_100(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| src.clone())
}

#[bench]
pub fn clone_100_and_clear(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| src.clone().clear())
}

#[bench]
pub fn clone_100_and_drain_half(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| {
        let mut set = src.clone();
        for i in set.iter().copied().filter(|i| i % 2 == 0).collect::<Vec<_>>() {
            set.remove(&i);
        }
        assert_eq!(set.len(), 100 / 2);
    })
}

#[bench]
pub fn clone_100_and_into_iter(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| src.clone().into_iter().count())
}

#[bench]
pub fn clone_100_and_pop_all(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| {
        let mut set = src.clone();
        while set.pop_first().is_some() {}
        set
    });
}

#[bench]
pub fn clone_100_and_remove_all(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| {
        let mut set = src.clone();
        while let Some(elt) = set.iter().copied().next() {
            set.remove(&elt);
        }
        set
    });
}

#[bench]
pub fn clone_100_and_remove_half(b: &mut Bencher) {
    let src = pos(100);
    b.iter(|| {
        let mut set = src.clone();
        for i in (2..=100 as i32).step_by(2) {
            set.remove(&i);
        }
        assert_eq!(set.len(), 100 / 2);
        set
    })
}

#[bench]
pub fn clone_10k(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| src.clone())
}

#[bench]
pub fn clone_10k_and_clear(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| src.clone().clear())
}

#[bench]
pub fn clone_10k_and_drain_half(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| {
        let mut set = src.clone();
        for i in set.iter().copied().filter(|i| i % 2 == 0).collect::<Vec<_>>() {
            set.remove(&i);
        }
        assert_eq!(set.len(), 10_000 / 2);
    })
}

#[bench]
pub fn clone_10k_and_into_iter(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| src.clone().into_iter().count())
}

#[bench]
pub fn clone_10k_and_pop_all(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| {
        let mut set = src.clone();
        while set.pop_first().is_some() {}
        set
    });
}

#[bench]
pub fn clone_10k_and_remove_all(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| {
        let mut set = src.clone();
        while let Some(elt) = set.iter().copied().next() {
            set.remove(&elt);
        }
        set
    });
}

#[bench]
pub fn clone_10k_and_remove_half(b: &mut Bencher) {
    let src = pos(10_000);
    b.iter(|| {
        let mut set = src.clone();
        for i in (2..=10_000 as i32).step_by(2) {
            set.remove(&i);
        }
        assert_eq!(set.len(), 10_000 / 2);
        set
    })
}

set_bench! {intersection_100_neg_vs_100_pos, intersection, count, [neg(100), pos(100)]}
set_bench! {intersection_100_neg_vs_10k_pos, intersection, count, [neg(100), pos(10_000)]}
set_bench! {intersection_100_pos_vs_100_neg, intersection, count, [pos(100), neg(100)]}
set_bench! {intersection_100_pos_vs_10k_neg, intersection, count, [pos(100), neg(10_000)]}
set_bench! {intersection_10k_neg_vs_100_pos, intersection, count, [neg(10_000), pos(100)]}
set_bench! {intersection_10k_neg_vs_10k_pos, intersection, count, [neg(10_000), pos(10_000)]}
set_bench! {intersection_10k_pos_vs_100_neg, intersection, count, [pos(10_000), neg(100)]}
set_bench! {intersection_10k_pos_vs_10k_neg, intersection, count, [pos(10_000), neg(10_000)]}
set_bench! {intersection_random_100_vs_100, intersection, count, [random(100), random(100)]}
set_bench! {intersection_random_100_vs_10k, intersection, count, [random(100), random(10_000)]}
set_bench! {intersection_random_10k_vs_100, intersection, count, [random(10_000), random(100)]}
set_bench! {intersection_random_10k_vs_10k, intersection, count, [random(10_000), random(10_000)]}
set_bench! {intersection_staggered_100_vs_100, intersection, count, stagger(100, 1)}
set_bench! {intersection_staggered_10k_vs_10k, intersection, count, stagger(10_000, 1)}
set_bench! {intersection_staggered_100_vs_10k, intersection, count, stagger(100, 100)}
set_bench! {difference_random_100_vs_100, difference, count, [random(100), random(100)]}
set_bench! {difference_random_100_vs_10k, difference, count, [random(100), random(10_000)]}
set_bench! {difference_random_10k_vs_100, difference, count, [random(10_000), random(100)]}
set_bench! {difference_random_10k_vs_10k, difference, count, [random(10_000), random(10_000)]}
set_bench! {difference_staggered_100_vs_100, difference, count, stagger(100, 1)}
set_bench! {difference_staggered_10k_vs_10k, difference, count, stagger(10_000, 1)}
set_bench! {difference_staggered_100_vs_10k, difference, count, stagger(100, 100)}
set_bench! {is_subset_100_vs_100, is_subset, clone, [pos(100), pos(100)]}
set_bench! {is_subset_100_vs_10k, is_subset, clone, [pos(100), pos(10_000)]}
set_bench! {is_subset_10k_vs_100, is_subset, clone, [pos(10_000), pos(100)]}
set_bench! {is_subset_10k_vs_10k, is_subset, clone, [pos(10_000), pos(10_000)]}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use build;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::mir::Mir;
use rustc::mir::transform::{MirPassIndex, MirSuite, MirSource,
                            MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED};
use rustc::ty::{self, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::steal::Steal;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::util::nodemap::DefIdSet;
use std::rc::Rc;
use syntax::ast;
use syntax_pos::{DUMMY_SP, Span};
use transform;

pub mod add_validation;
pub mod clean_end_regions;
pub mod simplify_branches;
pub mod simplify;
pub mod erase_regions;
pub mod no_landing_pads;
pub mod type_check;
pub mod rustc_peek;
pub mod elaborate_drops;
pub mod add_call_guards;
pub mod promote_consts;
pub mod qualify_consts;
pub mod dump_mir;
pub mod deaggregator;
pub mod instcombine;
pub mod copy_prop;
pub mod inline;
pub mod nll;

pub(crate) fn provide(providers: &mut Providers) {
    self::qualify_consts::provide(providers);
    *providers = Providers {
        mir_keys,
        mir_const,
        mir_validated,
        optimized_mir,
        is_mir_available,
        ..*providers
    };
}

fn is_mir_available<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
    tcx.mir_keys(def_id.krate).contains(&def_id)
}

/// Finds the full set of def-ids within the current crate that have
/// MIR associated with them.
fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
                      -> Rc<DefIdSet> {
    assert_eq!(krate, LOCAL_CRATE);

    let mut set = DefIdSet();

    // All body-owners have MIR associated with them.
    set.extend(tcx.body_owners());

    // Additionally, tuple struct/variant constructors have MIR, but
    // they don't have a BodyId, so we need to build them separately.
    struct GatherCtors<'a, 'tcx: 'a> {
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        set: &'a mut DefIdSet,
    }
    impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
        fn visit_variant_data(&mut self,
                              v: &'tcx hir::VariantData,
                              _: ast::Name,
                              _: &'tcx hir::Generics,
                              _: ast::NodeId,
                              _: Span) {
            if let hir::VariantData::Tuple(_, node_id) = *v {
                self.set.insert(self.tcx.hir.local_def_id(node_id));
            }
            intravisit::walk_struct_def(self, v)
        }
        fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
            NestedVisitorMap::None
        }
    }
    tcx.hir.krate().visit_all_item_likes(&mut GatherCtors {
        tcx,
        set: &mut set,
    }.as_deep_visitor());

    Rc::new(set)
}

fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
    let mut mir = build::mir_build(tcx, def_id);
    let source = MirSource::from_local_def_id(tcx, def_id);
    transform::run_suite(tcx, source, MIR_CONST, &mut mir);
    tcx.alloc_steal_mir(mir)
}

fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
    let source = MirSource::from_local_def_id(tcx, def_id);
    if let MirSource::Const(_) = source {
        // Ensure that we compute the `mir_const_qualif` for constants at
        // this point, before we steal the mir-const result. We don't
        // directly need the result or `mir_const_qualif`, so we can just force it.
        ty::queries::mir_const_qualif::force(tcx, DUMMY_SP, def_id);
    }

    let mut mir = tcx.mir_const(def_id).steal();
    transform::run_suite(tcx, source, MIR_VALIDATED, &mut mir);
    tcx.alloc_steal_mir(mir)
}

fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> {
    // Borrowck uses `mir_validated`, so we have to force it to
    // execute before we can steal.
    ty::queries::borrowck::force(tcx, DUMMY_SP, def_id);

    let mut mir = tcx.mir_validated(def_id).steal();
    let source = MirSource::from_local_def_id(tcx, def_id);
    transform::run_suite(tcx, source, MIR_OPTIMIZED, &mut mir);
    tcx.alloc_mir(mir)
}

fn run_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                       source: MirSource,
                       suite: MirSuite,
                       mir: &mut Mir<'tcx>)
{
    let passes = tcx.mir_passes.passes(suite);

    for (pass, index) in passes.iter().zip(0..) {
        let pass_num = MirPassIndex(index);

        for hook in tcx.mir_passes.hooks() {
            hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, false);
        }

        pass.run_pass(tcx, source, mir);

        for hook in tcx.mir_passes.hooks() {
            hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, true);
        }
    }
}
<commit_msg>Run MIR passes on promoted temporaries again.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use build;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::mir::Mir;
use rustc::mir::transform::{MirPassIndex, MirSuite, MirSource,
                            MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED};
use rustc::ty::{self, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::steal::Steal;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::util::nodemap::DefIdSet;
use std::rc::Rc;
use syntax::ast;
use syntax_pos::{DUMMY_SP, Span};
use transform;

pub mod add_validation;
pub mod clean_end_regions;
pub mod simplify_branches;
pub mod simplify;
pub mod erase_regions;
pub mod no_landing_pads;
pub mod type_check;
pub mod rustc_peek;
pub mod elaborate_drops;
pub mod add_call_guards;
pub mod promote_consts;
pub mod qualify_consts;
pub mod dump_mir;
pub mod deaggregator;
pub mod instcombine;
pub mod copy_prop;
pub mod inline;
pub mod nll;

pub(crate) fn provide(providers: &mut Providers) {
    self::qualify_consts::provide(providers);
    *providers = Providers {
        mir_keys,
        mir_const,
        mir_validated,
        optimized_mir,
        is_mir_available,
        ..*providers
    };
}

fn is_mir_available<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
    tcx.mir_keys(def_id.krate).contains(&def_id)
}

/// Finds the full set of def-ids within the current crate that have
/// MIR associated with them.
fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
                      -> Rc<DefIdSet> {
    assert_eq!(krate, LOCAL_CRATE);

    let mut set = DefIdSet();

    // All body-owners have MIR associated with them.
    set.extend(tcx.body_owners());

    // Additionally, tuple struct/variant constructors have MIR, but
    // they don't have a BodyId, so we need to build them separately.
    struct GatherCtors<'a, 'tcx: 'a> {
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        set: &'a mut DefIdSet,
    }
    impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
        fn visit_variant_data(&mut self,
                              v: &'tcx hir::VariantData,
                              _: ast::Name,
                              _: &'tcx hir::Generics,
                              _: ast::NodeId,
                              _: Span) {
            if let hir::VariantData::Tuple(_, node_id) = *v {
                self.set.insert(self.tcx.hir.local_def_id(node_id));
            }
            intravisit::walk_struct_def(self, v)
        }
        fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
            NestedVisitorMap::None
        }
    }
    tcx.hir.krate().visit_all_item_likes(&mut GatherCtors {
        tcx,
        set: &mut set,
    }.as_deep_visitor());

    Rc::new(set)
}

fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
    let mut mir = build::mir_build(tcx, def_id);
    let source = MirSource::from_local_def_id(tcx, def_id);
    transform::run_suite(tcx, source, MIR_CONST, &mut mir);
    tcx.alloc_steal_mir(mir)
}

fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
    let source = MirSource::from_local_def_id(tcx, def_id);
    if let MirSource::Const(_) = source {
        // Ensure that we compute the `mir_const_qualif` for constants at
        // this point, before we steal the mir-const result. We don't
        // directly need the result or `mir_const_qualif`, so we can just force it.
        ty::queries::mir_const_qualif::force(tcx, DUMMY_SP, def_id);
    }

    let mut mir = tcx.mir_const(def_id).steal();
    transform::run_suite(tcx, source, MIR_VALIDATED, &mut mir);
    tcx.alloc_steal_mir(mir)
}

fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> {
    // Borrowck uses `mir_validated`, so we have to force it to
    // execute before we can steal.
    ty::queries::borrowck::force(tcx, DUMMY_SP, def_id);

    let mut mir = tcx.mir_validated(def_id).steal();
    let source = MirSource::from_local_def_id(tcx, def_id);
    transform::run_suite(tcx, source, MIR_OPTIMIZED, &mut mir);
    tcx.alloc_mir(mir)
}

fn run_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                       source: MirSource,
                       suite: MirSuite,
                       mir: &mut Mir<'tcx>)
{
    let passes = tcx.mir_passes.passes(suite);

    for (pass, index) in passes.iter().zip(0..) {
        let pass_num = MirPassIndex(index);

        for hook in tcx.mir_passes.hooks() {
            hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, false);
        }

        pass.run_pass(tcx, source, mir);

        for (index, promoted_mir) in mir.promoted.iter_enumerated_mut() {
            let promoted_source = MirSource::Promoted(source.item_id(), index);
            pass.run_pass(tcx, promoted_source, promoted_mir);

            // Let's make sure we don't miss any nested instances
            assert!(promoted_mir.promoted.is_empty());
        }

        for hook in tcx.mir_passes.hooks() {
            hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, true);
        }
    }
}
<|endoftext|>


<commit_before>//! The [glyph-definition table][1].
//!
//! [1]: https://www.microsoft.com/typography/otspec/GDEF.htm

use truetype::{Result, Tape, Value};

/// A glyph-definition table.
pub struct GlyphDefinition;

/// The reader of a glyph-definition table.
pub enum Header {
    /// Version 0x00010000.
    Version1(Header1),
    /// Version 0x00010002.
    Version12(Header12),
}

table! {
    #[doc = "The reader of a glyph-definition table of version 0x00010000."]
    pub Header1 {
        version (u32) = { 0x00010000 },
    }
}

table! {
    #[doc = "The reader of a glyph-definition table of version 0x00010002."]
    pub Header12 {
        version (u32) = { 0x00010002 },
    }
}

impl Value for Header {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u32>()) {
            0x00010000 => Header::Version1(try!(tape.take())),
            0x00010002 => Header::Version12(try!(tape.take())),
            _ => raise!("found an unknown format of the glyph-definition table"),
        })
    }
}
<commit_msg>Flesh out GDEF’s header<commit_after>//! The [glyph-definition table][1].
//!
//! [1]: https://www.microsoft.com/typography/otspec/GDEF.htm

use truetype::{Result, Tape, Value};

table! {
    #[doc = "A glyph-definition table."]
    pub GlyphDefinition {
        header (Header),
    }
}

/// The header of a glyph-definition table.
#[derive(Clone, Debug)]
pub enum Header {
    /// Version 0x00010000.
    Version1(Header1),
    /// Version 0x00010002.
    Version12(Header12),
}

table! {
    #[doc = "The header of a glyph-definition table of version 0x00010000."]
    pub Header1 {
        version                 (u32) = { 0x00010000 }, // Version
        glyph_class_offset      (u16), // GlyphClassDef
        attachment_point_offset (u16), // AttachList
        ligature_caret_offset   (u16), // LigCaretList
        mark_class_offset       (u16), // MarkAttachClassDef
    }
}

table! {
    #[doc = "The header of a glyph-definition table of version 0x00010002."]
    pub Header12 {
        version                 (u32) = { 0x00010002 },
        glyph_class_offset      (u16), // GlyphClassDef
        attachment_point_offset (u16), // AttachList
        ligature_caret_offset   (u16), // LigCaretList
        mark_class_offset       (u16), // MarkAttachClassDef
        mark_set_offset         (u16), // MarkGlyphSetsDef
    }
}

impl Value for Header {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u32>()) {
            0x00010000 => Header::Version1(try!(tape.take())),
            0x00010002 => Header::Version12(try!(tape.take())),
            _ => raise!("found an unknown format of the glyph-definition table"),
        })
    }
}
<|endoftext|>


<commit_before>use core::ops;
use vmx;
use cpu;
use core::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, Ordering};

lazy_static! {
    static ref CLI_COUNT: cpu::PerCoreVariable<AtomicUsize> = Default::default();
}

pub fn are_interrupts_enabled() -> bool {
    (vmx::read_flags() & 0x200) != 0
}

#[cfg(not(test))]
pub fn cli() {
    info!("Clearing interrupts!");
    unsafe {
        asm!("cli" : : :);
    }
}

#[cfg(test)]
pub fn cli() { }

#[cfg(not(test))]
pub fn sti() {
    info!("Restoring interrupts!");
    unsafe {
        asm!("sti" : : :);
    }
}

#[cfg(test)]
pub fn sti() { }

#[derive(Default)]
pub struct ClearLocalInterrupts<T> {
    guarded: T,
}

pub struct ClearLocalInterruptsGuard<'a, T: 'a> {
    guarded: &'a T,
    acquired: AtomicBool,
}

pub struct ClearLocalInterruptsGuardMut<'a, T: 'a> {
    guarded: &'a mut T,
    acquired: AtomicBool,
}

impl<T> ClearLocalInterrupts<T> {
    pub fn new(guarded: T) -> Self {
        ClearLocalInterrupts {
            guarded: guarded,
        }
    }

    pub fn cli_mut(&mut self) -> ClearLocalInterruptsGuardMut<T> {
        info!("new mut!");
        ClearLocalInterruptsGuardMut { guarded: &mut self.guarded, acquired: ATOMIC_BOOL_INIT }
    }

    pub fn cli(&self) -> ClearLocalInterruptsGuard<T> {
        info!("new!");
        ClearLocalInterruptsGuard { guarded: &self.guarded, acquired: ATOMIC_BOOL_INIT }
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuardMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::DerefMut for ClearLocalInterruptsGuardMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuard<'a, T> {
    fn drop(&mut self) {
        info!("Drop! {}", CLI_COUNT.get().load(Ordering::Relaxed));
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuardMut<'a, T> {
    fn drop(&mut self) {
        info!("Drop! {}", CLI_COUNT.get().load(Ordering::Relaxed));
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {
    use super::are_interrupts_enabled;
    use super::ClearLocalInterrupts;

    struct Guardee {
        data: u16,
    }

    lazy_static! {
        static ref STATIC_GUARDEE: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
    }

    impl Guardee {
        fn do_work(&self) {}
    }

    pub fn run() {
        info!("Running CLI tests...");
        test_clear_local_interrupts_guard_borrow();
        test_clear_local_interrupts_guard_mut_borrow();
        test_clear_local_interrupts_guard_static_borrow();
        info!("CLI tests succeeded");
    }

    fn test_clear_local_interrupts_guard_mut_borrow() {
        assert!(are_interrupts_enabled());
        {
            let mut g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            g.cli_mut().data += 1;
            assert!(are_interrupts_enabled());
            assert_eq!(g.cli().data, 1);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_borrow() {
        assert!(are_interrupts_enabled());
        {
            let g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            let borrowed = &g.cli();
            assert!(are_interrupts_enabled());
            borrowed.do_work();
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_static_borrow() {
        assert!(are_interrupts_enabled());
        {
            assert!(are_interrupts_enabled());
            STATIC_GUARDEE.cli().do_work();
            assert!(are_interrupts_enabled());
            assert_eq!(STATIC_GUARDEE.cli().data, 0);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }
}
<commit_msg>Remove debug statements<commit_after>use core::ops;
use vmx;
use cpu;
use core::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, Ordering};

lazy_static! {
    static ref CLI_COUNT: cpu::PerCoreVariable<AtomicUsize> = Default::default();
}

pub fn are_interrupts_enabled() -> bool {
    (vmx::read_flags() & 0x200) != 0
}

#[cfg(not(test))]
pub fn cli() {
    unsafe {
        asm!("cli" : : :);
    }
}

#[cfg(test)]
pub fn cli() { }

#[cfg(not(test))]
pub fn sti() {
    unsafe {
        asm!("sti" : : :);
    }
}

#[cfg(test)]
pub fn sti() { }

#[derive(Default)]
pub struct ClearLocalInterrupts<T> {
    guarded: T,
}

pub struct ClearLocalInterruptsGuard<'a, T: 'a> {
    guarded: &'a T,
    acquired: AtomicBool,
}

pub struct ClearLocalInterruptsGuardMut<'a, T: 'a> {
    guarded: &'a mut T,
    acquired: AtomicBool,
}

impl<T> ClearLocalInterrupts<T> {
    pub fn new(guarded: T) -> Self {
        ClearLocalInterrupts {
            guarded: guarded,
        }
    }

    pub fn cli_mut(&mut self) -> ClearLocalInterruptsGuardMut<T> {
        ClearLocalInterruptsGuardMut { guarded: &mut self.guarded, acquired: ATOMIC_BOOL_INIT }
    }

    pub fn cli(&self) -> ClearLocalInterruptsGuard<T> {
        ClearLocalInterruptsGuard { guarded: &self.guarded, acquired: ATOMIC_BOOL_INIT }
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuardMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::DerefMut for ClearLocalInterruptsGuardMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuard<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuardMut<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {
    use super::are_interrupts_enabled;
    use super::ClearLocalInterrupts;

    struct Guardee {
        data: u16,
    }

    lazy_static! {
        static ref STATIC_GUARDEE: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
    }

    impl Guardee {
        fn do_work(&self) {}
    }

    pub fn run() {
        info!("Running CLI tests...");
        test_clear_local_interrupts_guard_borrow();
        test_clear_local_interrupts_guard_mut_borrow();
        test_clear_local_interrupts_guard_static_borrow();
        info!("CLI tests succeeded");
    }

    fn test_clear_local_interrupts_guard_mut_borrow() {
        assert!(are_interrupts_enabled());
        {
            let mut g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            g.cli_mut().data += 1;
            assert!(are_interrupts_enabled());
            assert_eq!(g.cli().data, 1);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_borrow() {
        assert!(are_interrupts_enabled());
        {
            let g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            let borrowed = &g.cli();
            assert!(are_interrupts_enabled());
            borrowed.do_work();
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_static_borrow() {
        assert!(are_interrupts_enabled());
        {
            assert!(are_interrupts_enabled());
            STATIC_GUARDEE.cli().do_work();
            assert!(are_interrupts_enabled());
            assert_eq!(STATIC_GUARDEE.cli().data, 0);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }
}
<|endoftext|>