<commit_before>// Find Cargo's source cache directory for a crate
use super::es;
use es::traits::*;
use std::env;
use std::path;

pub fn rustup_lib() -> String {
    es::shell("rustc --print sysroot") + "/lib"
}
pub fn proper_crate_name(crate_name: &str) -> String {
    crate_name.replace('-',"_")
}

pub fn path_file_name(p: &path::Path) -> String {
    if let Some(file_name) = p.file_name() {
        file_name.to_string_lossy().to_string()
    } else
    if let Ok(full_path) = p.canonicalize() {
        path_file_name(&full_path)
    } else {
        p.to_string_lossy().to_string()
    }
}

// there's a Crate for This...
fn semver_i (s: &str) -> u64 {
    let v = s.split('.').filter_map(|s| s.parse::<u64>().ok()).to_vec();
    (((v[0] << 8) + v[1]) << 8) + v[2]
}

pub fn cargo_home() -> path::PathBuf {
    env::var("CARGO_HOME") // set in cargo runs
        .unwrap_or(env::var("HOME").or_die("no home!") + "/.cargo").into()
}

pub fn cache_path(crate_name: &str) -> path::PathBuf {
    let home = cargo_home();
    let crate_root = path::PathBuf::from(home.join("registry/src"));
    // actual crate source is in some fairly arbitrary subdirectory of this
    let mut crate_dir = crate_root.clone();
    crate_dir.push(es::files(&crate_root).next().or_die("no crate cache directory"));

    let mut crates = Vec::new();
    for (p,d) in es::paths(&crate_dir) {
        if ! d.is_dir() { continue; }
        let filename = path_file_name(&p);
        if let Some(endc) = filename.rfind('-') {
            if &filename[0..endc] == crate_name {
                crates.push((p,semver_i(&filename[endc+1..])));
            }
        }
    }
    // crate versions in ascending order by semver rules
    crates.sort_by(|a,b| a.1.cmp(&b.1));
    crates.pop().or_die(&format!("no such crate: {}",crate_name)).0
}

// Very hacky stuff - we want the ACTUAL crate name, not the project name
// So look just past [package] and scrape the name...
fn crate_name(cargo_toml: &path::Path) -> String {
    let name_line = es::lines(es::open(cargo_toml))
        .skip_while(|line| line.trim() != "[package]")
        .skip(1)
        .skip_while(|line| ! line.starts_with("name "))
        .next().or_die("totally fked Cargo.toml");
    let idx = name_line.find('"').or_die("no name?");
    (&name_line[(idx+1)..(name_line.len()-1)]).into()

}

pub fn crate_path(file: &path::Path, first_arg: &str) -> Result<(path::PathBuf,String),String> {
    if file.exists() {
        //let filename = path_file_name(file);
        if file.is_dir() { // assumed to be Cargo directory
            let cargo_toml = file.join("Cargo.toml");
            if ! cargo_toml.exists() {
                return Err(format!("not a Cargo project directory: {}",file.display()));
            }
            Ok((file.join("src/lib.rs"), crate_name(&cargo_toml)))
        } else { // should be just a Rust source file
            if file.extension().or_die("expecting extension") != "rs" {
                return Err("expecting Rust source file".into());
            }
            let name = path_file_name(&file.with_extension(""));
            Ok((file.to_path_buf(), name))
        }
    } else {
        let project_dir = cache_path(first_arg);
        let cargo_toml = project_dir.join("Cargo.toml");
        Ok((project_dir.join("src/lib.rs"), crate_name(&cargo_toml)))
    }
}

pub fn full_crate_name(deps: &path::Path, crate_name: &str) -> Option<String> {
    let mut res = Vec::new();
    let patt = format!("lib{}-",crate_name);
    for (p,_) in es::paths(deps) {
        if let Some(f) = p.file_name() {
            let name = f.to_string_lossy();
            //println!("got {}",name);
            if name.starts_with(&patt) {
                let cname = &name[3..(name.len()-5) ];
                res.push(cname.to_string());
            }
        }
    }
    res.pop()
}
<commit_msg>always use home_dir() for cross-platform; no more use of es::paths()<commit_after>// Find Cargo's source cache directory for a crate
use super::es;
use std::fs;
use es::traits::*;
use std::env;
use std::path;

pub fn rustup_lib() -> String {
    es::shell("rustc --print sysroot") + "/lib"
}
pub fn proper_crate_name(crate_name: &str) -> String {
    crate_name.replace('-',"_")
}

pub fn path_file_name(p: &path::Path) -> String {
    if let Some(file_name) = p.file_name() {
        file_name.to_string_lossy().to_string()
    } else
    if let Ok(full_path) = p.canonicalize() {
        path_file_name(&full_path)
    } else {
        p.to_string_lossy().to_string()
    }
}

// there's a Crate for This...
fn semver_i (s: &str) -> u64 {
    let v = s.split('.').filter_map(|s| s.parse::<u64>().ok()).to_vec();
    (((v[0] << 8) + v[1]) << 8) + v[2]
}

pub fn cargo_home() -> path::PathBuf {
	if let Ok(home) = env::var("CARGO_HOME") { // set in cargo runs
		home.into()
	} else {
		env::home_dir().or_die("no home!").join(".cargo")
    }
}

pub fn cache_path(crate_name: &str) -> path::PathBuf {
    let home = cargo_home();
    let crate_root = path::PathBuf::from(home.join("registry/src"));
    // actual crate source is in some fairly arbitrary subdirectory of this
    let mut crate_dir = crate_root.clone();
    crate_dir.push(es::files(&crate_root).next().or_die("no crate cache directory"));

    let mut crates = Vec::new();
    for (p,d) in es::paths(&crate_dir) {
        if ! d.is_dir() { continue; }
        let filename = path_file_name(&p);
        if let Some(endc) = filename.rfind('-') {
            if &filename[0..endc] == crate_name {
                crates.push((p,semver_i(&filename[endc+1..])));
            }
        }
    }
    // crate versions in ascending order by semver rules
    crates.sort_by(|a,b| a.1.cmp(&b.1));
    crates.pop().or_die(&format!("no such crate: {}",crate_name)).0
}

// Very hacky stuff - we want the ACTUAL crate name, not the project name
// So look just past [package] and scrape the name...
fn crate_name(cargo_toml: &path::Path) -> String {
    let name_line = es::lines(es::open(cargo_toml))
        .skip_while(|line| line.trim() != "[package]")
        .skip(1)
        .skip_while(|line| ! line.starts_with("name "))
        .next().or_die("totally fked Cargo.toml");
    let idx = name_line.find('"').or_die("no name?");
    (&name_line[(idx+1)..(name_line.len()-1)]).into()

}

pub fn crate_path(file: &path::Path, first_arg: &str) -> Result<(path::PathBuf,String),String> {
    if file.exists() {
        //let filename = path_file_name(file);
        if file.is_dir() { // assumed to be Cargo directory
            let cargo_toml = file.join("Cargo.toml");
            if ! cargo_toml.exists() {
                return Err(format!("not a Cargo project directory: {}",file.display()));
            }
            Ok((file.join("src/lib.rs"), crate_name(&cargo_toml)))
        } else { // should be just a Rust source file
            if file.extension().or_die("expecting extension") != "rs" {
                return Err("expecting Rust source file".into());
            }
            let name = path_file_name(&file.with_extension(""));
            Ok((file.to_path_buf(), name))
        }
    } else {
        let project_dir = cache_path(first_arg);
        let cargo_toml = project_dir.join("Cargo.toml");
        Ok((project_dir.join("src/lib.rs"), crate_name(&cargo_toml)))
    }
}

pub fn full_crate_name(deps: &path::Path, crate_name: &str) -> Option<String> {
    let mut res = Vec::new();
    let patt = format!("lib{}-",crate_name);
    for entry in fs::read_dir(deps).expect("cannot access dependencies dir") {
		let entry = entry.expect("cannot access deps entry");
		let path = entry.path();
        if let Some(f) = path.file_name() {
            let name = f.to_string_lossy();
            //println!("got {}",name);
            if name.starts_with(&patt) {
                let cname = &name[3..(name.len()-5) ];
                res.push(cname.to_string());
            }
        }
    }
    res.pop()
}
<|endoftext|>


<commit_before><commit_msg>Dereference algorithm when generating cryptoapi hasher<commit_after><|endoftext|>


<commit_before>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ElementError, ParseError, RenderingError};
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterResult};

mod error;
use self::error::FilterError;

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw {
    fn resolve(&self, node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError>;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

/// Resolved parameters for each filter primitive.
///
/// These gather all the data that a primitive may need during rendering:
/// the `feFoo` element's attributes, any computed values from its properties,
/// and parameters extracted from the element's children (for example,
/// `feMerge` gathers info from its `feMergNode` children).
pub enum PrimitiveParams {
    Blend(blend::Blend),
    ColorMatrix(color_matrix::ColorMatrix),
    ComponentTransfer(component_transfer::ComponentTransfer),
    Composite(composite::Composite),
    ConvolveMatrix(convolve_matrix::ConvolveMatrix),
    DiffuseLighting(lighting::DiffuseLighting),
    DisplacementMap(displacement_map::DisplacementMap),
    Flood(flood::Flood),
    GaussianBlur(gaussian_blur::GaussianBlur),
    Image(image::Image),
    Merge(merge::Merge),
    Morphology(morphology::Morphology),
    Offset(offset::Offset),
    SpecularLighting(lighting::SpecularLighting),
    Tile(tile::Tile),
    Turbulence(turbulence::Turbulence),
}

/// The base filter primitive node containing common properties.
#[derive(Default, Clone)]
pub struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

pub struct ResolvedPrimitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Input {
    Unspecified,
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterOutput(CustomIdent),
}

impl Default for Input {
    fn default() -> Self {
        Input::Unspecified
    }
}

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                Ok(parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )?)
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

impl Primitive {
    fn resolve(&self) -> Result<ResolvedPrimitive, FilterError> {
        Ok(ResolvedPrimitive {
            x: self.x,
            y: self.y,
            width: self.width,
            height: self.height,
            result: self.result.clone(),
        })
    }
}

impl ResolvedPrimitive {
    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> Result<BoundsBuilder, FilterError> {
        // With ObjectBoundingBox, only fractions and percents are allowed.
        if ctx.primitive_units() == CoordUnits::ObjectBoundingBox {
            check_px_or_percent_units(self.x)?;
            check_px_or_percent_units(self.y)?;
            check_px_or_percent_units(self.width)?;
            check_px_or_percent_units(self.height)?;
        }

        let transform = ctx.paffine();
        if !transform.is_invertible() {
            return Err(FilterError::InvalidParameter(
                "transform is not invertible".to_string(),
            ));
        }

        Ok(BoundsBuilder::new(
            self.x,
            self.y,
            self.width,
            self.height,
            transform,
        ))
    }
}

fn check_px_or_percent_units<N: Normalize, V: Validate>(
    length: Option<CssLength<N, V>>,
) -> Result<(), FilterError> {
    match length {
        Some(l) if l.unit == LengthUnit::Px || l.unit == LengthUnit::Percent => Ok(()),
        Some(_) => Err(FilterError::InvalidUnits),
        None => Ok(()),
    }
}

impl Primitive {
    fn parse_standard_attributes(
        &mut self,
        attrs: &Attributes,
    ) -> Result<(Input, Input), ElementError> {
        let mut input_1 = Input::Unspecified;
        let mut input_2 = Input::Unspecified;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                expanded_name!("", "in") => input_1 = attr.parse(value)?,
                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                _ => (),
            }
        }

        Ok((input_1, input_2))
    }

    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
        let (_, _) = self.parse_standard_attributes(attrs)?;
        Ok(())
    }

    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
        let (input_1, _) = self.parse_standard_attributes(attrs)?;
        Ok(input_1)
    }

    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
        self.parse_standard_attributes(attrs)
    }
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    computed_from_node_being_filtered: &ComputedValues,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    if filter_node.borrow_element().is_in_error() {
        return Ok(source_surface);
    }

    let filter = borrow_element_as!(filter_node, Filter);

    let values = computed_from_node_being_filtered;

    let stroke_paint_source = values
        .stroke()
        .0
        .resolve(acquired_nodes, values.stroke_opacity().0, values.color().0)?
        .to_user_space(&node_bbox, draw_ctx, values);

    let fill_paint_source = values
        .fill()
        .0
        .resolve(acquired_nodes, values.fill_opacity().0, values.color().0)?
        .to_user_space(&node_bbox, draw_ctx, values);

    let mut filter_ctx = FilterContext::new(
        &filter,
        computed_from_node_being_filtered,
        stroke_paint_source,
        fill_paint_source,
        source_surface,
        draw_ctx,
        transform,
        node_bbox,
    );

    // If paffine is non-invertible, we won't draw anything. Also bbox combining in bounds
    // computations will panic due to non-invertible martrix.
    if !filter_ctx.paffine().is_invertible() {
        return Ok(filter_ctx.into_output()?);
    }

    let primitives = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some());

    for c in primitives {
        let elt = c.borrow_element();
        let filter = elt.as_filter_effect().unwrap();

        let start = Instant::now();

        if let Err(err) = filter
            .resolve(&c)
            .and_then(|(primitive, params)| {
                render_primitive(
                    &primitive.resolve()?,
                    &params,
                    &filter_ctx,
                    acquired_nodes,
                    draw_ctx,
                )
            })
            .and_then(|result| filter_ctx.store_result(result))
        {
            rsvg_log!("(filter primitive {} returned an error: {})", c, err);

            // Exit early on Cairo errors. Continue rendering otherwise.
            if let FilterError::CairoError(status) = err {
                return Err(RenderingError::from(status));
            }
        }

        let elapsed = start.elapsed();
        rsvg_log!(
            "(rendered filter primitive {} in\n    {} seconds)",
            c,
            elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
        );
    }

    Ok(filter_ctx.into_output()?)
}

#[rustfmt::skip]
fn render_primitive(
    primitive: &ResolvedPrimitive,
    params: &PrimitiveParams,
    ctx: &FilterContext,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
) -> Result<FilterResult, FilterError> {
    use PrimitiveParams::*;

    match params {
        Blend(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ColorMatrix(p)       => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ComponentTransfer(p) => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Composite(p)         => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ConvolveMatrix(p)    => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        DiffuseLighting(p)   => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        DisplacementMap(p)   => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Flood(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        GaussianBlur(p)      => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Image(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Merge(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Morphology(p)        => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Offset(p)            => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        SpecularLighting(p)  => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Tile(p)              => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Turbulence(p)        => p.render(primitive, ctx, acquired_nodes, draw_ctx),
    }
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<commit_msg>filters: use enum_default macro for Input<commit_after>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ElementError, ParseError, RenderingError};
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterResult};

mod error;
use self::error::FilterError;

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw {
    fn resolve(&self, node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError>;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

/// Resolved parameters for each filter primitive.
///
/// These gather all the data that a primitive may need during rendering:
/// the `feFoo` element's attributes, any computed values from its properties,
/// and parameters extracted from the element's children (for example,
/// `feMerge` gathers info from its `feMergNode` children).
pub enum PrimitiveParams {
    Blend(blend::Blend),
    ColorMatrix(color_matrix::ColorMatrix),
    ComponentTransfer(component_transfer::ComponentTransfer),
    Composite(composite::Composite),
    ConvolveMatrix(convolve_matrix::ConvolveMatrix),
    DiffuseLighting(lighting::DiffuseLighting),
    DisplacementMap(displacement_map::DisplacementMap),
    Flood(flood::Flood),
    GaussianBlur(gaussian_blur::GaussianBlur),
    Image(image::Image),
    Merge(merge::Merge),
    Morphology(morphology::Morphology),
    Offset(offset::Offset),
    SpecularLighting(lighting::SpecularLighting),
    Tile(tile::Tile),
    Turbulence(turbulence::Turbulence),
}

/// The base filter primitive node containing common properties.
#[derive(Default, Clone)]
pub struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

pub struct ResolvedPrimitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Input {
    Unspecified,
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterOutput(CustomIdent),
}

enum_default!(Input, Input::Unspecified);

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                Ok(parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )?)
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

impl Primitive {
    fn resolve(&self) -> Result<ResolvedPrimitive, FilterError> {
        Ok(ResolvedPrimitive {
            x: self.x,
            y: self.y,
            width: self.width,
            height: self.height,
            result: self.result.clone(),
        })
    }
}

impl ResolvedPrimitive {
    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> Result<BoundsBuilder, FilterError> {
        // With ObjectBoundingBox, only fractions and percents are allowed.
        if ctx.primitive_units() == CoordUnits::ObjectBoundingBox {
            check_px_or_percent_units(self.x)?;
            check_px_or_percent_units(self.y)?;
            check_px_or_percent_units(self.width)?;
            check_px_or_percent_units(self.height)?;
        }

        let transform = ctx.paffine();
        if !transform.is_invertible() {
            return Err(FilterError::InvalidParameter(
                "transform is not invertible".to_string(),
            ));
        }

        Ok(BoundsBuilder::new(
            self.x,
            self.y,
            self.width,
            self.height,
            transform,
        ))
    }
}

fn check_px_or_percent_units<N: Normalize, V: Validate>(
    length: Option<CssLength<N, V>>,
) -> Result<(), FilterError> {
    match length {
        Some(l) if l.unit == LengthUnit::Px || l.unit == LengthUnit::Percent => Ok(()),
        Some(_) => Err(FilterError::InvalidUnits),
        None => Ok(()),
    }
}

impl Primitive {
    fn parse_standard_attributes(
        &mut self,
        attrs: &Attributes,
    ) -> Result<(Input, Input), ElementError> {
        let mut input_1 = Input::Unspecified;
        let mut input_2 = Input::Unspecified;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                expanded_name!("", "in") => input_1 = attr.parse(value)?,
                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                _ => (),
            }
        }

        Ok((input_1, input_2))
    }

    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
        let (_, _) = self.parse_standard_attributes(attrs)?;
        Ok(())
    }

    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
        let (input_1, _) = self.parse_standard_attributes(attrs)?;
        Ok(input_1)
    }

    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
        self.parse_standard_attributes(attrs)
    }
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    computed_from_node_being_filtered: &ComputedValues,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    if filter_node.borrow_element().is_in_error() {
        return Ok(source_surface);
    }

    let filter = borrow_element_as!(filter_node, Filter);

    let values = computed_from_node_being_filtered;

    let stroke_paint_source = values
        .stroke()
        .0
        .resolve(acquired_nodes, values.stroke_opacity().0, values.color().0)?
        .to_user_space(&node_bbox, draw_ctx, values);

    let fill_paint_source = values
        .fill()
        .0
        .resolve(acquired_nodes, values.fill_opacity().0, values.color().0)?
        .to_user_space(&node_bbox, draw_ctx, values);

    let mut filter_ctx = FilterContext::new(
        &filter,
        computed_from_node_being_filtered,
        stroke_paint_source,
        fill_paint_source,
        source_surface,
        draw_ctx,
        transform,
        node_bbox,
    );

    // If paffine is non-invertible, we won't draw anything. Also bbox combining in bounds
    // computations will panic due to non-invertible martrix.
    if !filter_ctx.paffine().is_invertible() {
        return Ok(filter_ctx.into_output()?);
    }

    let primitives = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some());

    for c in primitives {
        let elt = c.borrow_element();
        let filter = elt.as_filter_effect().unwrap();

        let start = Instant::now();

        if let Err(err) = filter
            .resolve(&c)
            .and_then(|(primitive, params)| {
                render_primitive(
                    &primitive.resolve()?,
                    &params,
                    &filter_ctx,
                    acquired_nodes,
                    draw_ctx,
                )
            })
            .and_then(|result| filter_ctx.store_result(result))
        {
            rsvg_log!("(filter primitive {} returned an error: {})", c, err);

            // Exit early on Cairo errors. Continue rendering otherwise.
            if let FilterError::CairoError(status) = err {
                return Err(RenderingError::from(status));
            }
        }

        let elapsed = start.elapsed();
        rsvg_log!(
            "(rendered filter primitive {} in\n    {} seconds)",
            c,
            elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
        );
    }

    Ok(filter_ctx.into_output()?)
}

#[rustfmt::skip]
fn render_primitive(
    primitive: &ResolvedPrimitive,
    params: &PrimitiveParams,
    ctx: &FilterContext,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
) -> Result<FilterResult, FilterError> {
    use PrimitiveParams::*;

    match params {
        Blend(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ColorMatrix(p)       => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ComponentTransfer(p) => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Composite(p)         => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ConvolveMatrix(p)    => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        DiffuseLighting(p)   => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        DisplacementMap(p)   => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Flood(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        GaussianBlur(p)      => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Image(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Merge(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Morphology(p)        => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Offset(p)            => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        SpecularLighting(p)  => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Tile(p)              => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Turbulence(p)        => p.render(primitive, ctx, acquired_nodes, draw_ctx),
    }
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<|endoftext|>


<commit_before>use crate::AsArray1D;
use plotpy::{Curve, Plot, Shapes, Text};
use std::collections::HashMap;

/// Holds the id and coordinates of an item
#[derive(Clone)]
struct Item {
    id: usize,   // identification number
    x: [f64; 3], // coordinates
}

/// Holds items
#[derive(Clone)]
struct Container {
    items: Vec<Item>,
}

/// Implements a grid for fast searching entries by coordinates
///
/// # Reference
///
/// * Durand, Farias, and Pedroso (2015) Computing intersections between
///   non-compatible curves and finite elements, Computational Mechanics;
///   DOI=10.1007/s00466-015-1181-y
pub struct GridSearch {
    // constants
    ndim: usize,      // space dimension
    ndiv: [usize; 3], // number of divisions along each direction
    xmin: [f64; 3],   // min values
    xmax: [f64; 3],   // max values
    xdelta: [f64; 3], // difference between max and min
    size: [f64; 3],   // size of each cell
    cf: [usize; 3],   // coefficients [1, ndiv[0], ndiv[0]*ndiv[1]] (Eq. 8)

    // auxiliary variable
    ratio: [usize; 3], // ratio = trunc(δx[i]/Δx[i]) (Eq. 8)

    // holds non-empty cells. maps cell.id to container
    cells: HashMap<usize, Container>,
}

impl GridSearch {
    /// Creates a new GridSearch
    ///
    /// # Input
    ///
    /// * `xmin, xmax` -- min and max coordinates (len = 2 or 3 == ndim)
    /// * `ndiv` -- number of divisions along each dimension (len = 2 or 3 == ndim)
    pub fn new(xmin: &[f64], xmax: &[f64], ndiv: &[usize]) -> Result<Self, &'static str> {
        // check input
        let ndim = ndiv.len();
        if ndim < 2 || ndim > 3 {
            return Err("ndim must be 2 or 3");
        }
        if xmin.len() != ndim {
            return Err("size of xmin must equal ndim");
        }
        if xmax.len() != ndim {
            return Err("size of xmax must equal ndim");
        }

        // allocate gs
        let mut grid = GridSearch {
            ndim,
            ndiv: [0; 3],
            xmin: [0.0; 3],
            xmax: [0.0; 3],
            xdelta: [0.0; 3],
            size: [0.0; 3],
            ratio: [0; 3],
            cf: [0; 3],
            cells: HashMap::new(),
        };

        // check and compute sizes
        for i in 0..ndim {
            grid.ndiv[i] = ndiv[i];
            if ndiv[i] < 1 {
                return Err("ndiv must be at least 1");
            }
            grid.xmin[i] = xmin[i];
            grid.xmax[i] = xmax[i];
            grid.xdelta[i] = xmax[i] - xmin[i];
            if grid.xdelta[i] <= 0.0 {
                return Err("xmax must be greater than xmin");
            }
            grid.size[i] = grid.xdelta[i] / (ndiv[i] as f64);
        }

        // coefficient
        grid.cf[0] = 1;
        grid.cf[1] = grid.ndiv[0];
        grid.cf[2] = grid.ndiv[0] * grid.ndiv[1];

        // done
        Ok(grid)
    }

    /// Inserts a new item to some container in the grid
    ///
    /// # Input
    ///
    /// * `id` -- identification number for the item
    /// * `x` -- coordinates of the item (an 1D array with len = ndim)
    pub fn insert<'a, T, U>(&mut self, id: usize, x: &'a T) -> Result<(), &'static str>
    where
        T: AsArray1D<'a, U>,
        U: 'a + Into<f64>,
    {
        if x.size() != self.ndim {
            return Err("x must have len equal to ndim");
        }
        match self.container_index(x) {
            Some(index) => {
                // new item data
                let mut item = Item {
                    id,
                    x: [x.at(0).into(), x.at(1).into(), 0.0],
                };
                if self.ndim == 3 {
                    item.x[2] = x.at(2).into();
                }

                // update container
                if self.cells.contains_key(&index) {
                    let cell = self.cells.get_mut(&index).unwrap();
                    cell.items.push(item);

                // initialize container
                } else {
                    self.cells.insert(index, Container { items: vec![item] });
                }
            }
            None => return Err("point is outside the grid"),
        }
        Ok(())
    }

    /// Returns a drawing of this object
    pub fn plot(&self) -> Result<Plot, &'static str> {
        // create plot
        let mut plot = Plot::new();

        // draw grid
        let mut xmin = vec![0.0; self.ndim];
        let mut xmax = vec![0.0; self.ndim];
        let mut ndiv = vec![0; self.ndim];
        for i in 0..self.ndim {
            xmin[i] = self.xmin[i];
            xmax[i] = self.xmax[i];
            ndiv[i] = self.ndiv[i];
        }
        let mut shapes = Shapes::new();
        shapes
            .set_alt_text_color("#5d5d5d")
            .draw_grid(&xmin, &xmax, &ndiv, false, true)?;
        plot.add(&shapes);

        // draw items
        if self.ndim == 2 {
            let mut curve = Curve::new();
            let mut text = Text::new();
            curve
                .set_marker_style("o")
                .set_marker_color("#fab32faa")
                .set_marker_line_color("black")
                .set_marker_line_width(0.5);
            text.set_color("#cd0000");
            for container in self.cells.values() {
                for item in &container.items {
                    let txt = format!("{}", item.id);
                    curve.draw(&[item.x[0]], &[item.x[1]]);
                    text.draw(item.x[0], item.x[1], &txt);
                }
            }
            plot.add(&curve);
            plot.add(&text);
        }
        Ok(plot)
    }

    /// Calculates the container index where the point x should be located
    ///
    /// # Output
    ///
    /// * returns the index of the container or None if the point is out-of-range
    fn container_index<'a, T, U>(&mut self, x: &'a T) -> Option<usize>
    where
        T: AsArray1D<'a, U>,
        U: 'a + Into<f64>,
    {
        let mut index = 0;
        for i in 0..self.ndim {
            if x.at(i).into() < self.xmin[i] || x.at(i).into() > self.xmax[i] {
                return None;
            }
            self.ratio[i] = ((x.at(i).into() - self.xmin[i]) / self.size[i]) as usize;
            if self.ratio[i] == self.ndiv[i] {
                // the point is exactly on the max edge, thus select inner cell
                self.ratio[i] -= 1; // move to the inside
            }
            index += self.ratio[i] * self.cf[i];
        }
        Some(index)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    struct TestData {
        id: usize,
        x: Vec<f64>,
        container_index: usize,
    }

    fn get_test_data() -> Vec<TestData> {
        vec![
            TestData {
                id: 100,
                x: vec![0.0, 0.2],
                container_index: 6,
            },
            TestData {
                id: 200,
                x: vec![0.2, 0.6000000000000001],
                container_index: 12,
            },
            TestData {
                id: 300,
                x: vec![0.4, 1.0],
                // in this case, the ratio is:
                // 3.0000000000000004, 2.9999999999999996
                // thus, the point falls in #13 instead of #18
                container_index: 13,
            },
            TestData {
                id: 400,
                x: vec![0.6, 1.4],
                // in this case, the ratio is:
                // 4, 3.9999999999999996
                // thus, the point falls in #19 instead of #24
                container_index: 19,
            },
            TestData {
                id: 500,
                x: vec![0.8, 1.8],
                container_index: 24,
            },
        ]
    }

    #[test]
    fn new_works() -> Result<(), &'static str> {
        let grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        assert_eq!(grid.ndim, 2);
        assert_eq!(grid.ndiv, [5, 5, 0]);
        assert_eq!(grid.xmin, [-0.2, -0.2, 0.0]);
        assert_eq!(grid.xmax, [0.8, 1.8, 0.0]);
        assert_eq!(grid.xdelta, [1.0, 2.0, 0.0]);
        assert_eq!(grid.size, [0.2, 0.4, 0.0]);
        assert_eq!(grid.cf, [1, 5, 25]);
        assert_eq!(grid.ratio, [0, 0, 0]);
        assert_eq!(grid.cells.len(), 0);
        println!("{:.20}", grid.size[0]);
        assert_eq!(grid.size[0], 0.20000000000000001110); // TODO: check if this is a problem
        let b0 = 0.20000000000000001110_f64.to_bits();
        let b1 = 0.2_f64.to_bits();
        println!("{} =? {}", b0, b1);
        assert_eq!(b0, b1);
        Ok(())
    }

    #[test]
    fn container_index_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        for data in get_test_data() {
            let index = grid.container_index(&data.x).unwrap();
            assert_eq!(index, data.container_index);
        }
        Ok(())
    }

    #[test]
    fn insert_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        for data in get_test_data() {
            grid.insert(data.id, &data.x)?;
            // todo
        }
        Ok(())
    }

    #[test]
    fn plot_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        for data in get_test_data() {
            grid.insert(data.id, &data.x)?;
        }
        let plot = grid.plot()?;
        plot.save("/tmp/gemlab/search_grid_plot_works.svg")?;
        Ok(())
    }
}
<commit_msg>Improve tests<commit_after>use crate::AsArray1D;
use plotpy::{Curve, Plot, Shapes, Text};
use std::collections::HashMap;

/// Holds the id and coordinates of an item
#[derive(Clone, Debug)]
struct Item {
    id: usize,   // identification number
    x: [f64; 3], // coordinates
}

/// Holds items
#[derive(Clone, Debug)]
struct Container {
    items: Vec<Item>,
}

/// Implements a grid for fast searching entries by coordinates
///
/// # Reference
///
/// * Durand, Farias, and Pedroso (2015) Computing intersections between
///   non-compatible curves and finite elements, Computational Mechanics;
///   DOI=10.1007/s00466-015-1181-y
pub struct GridSearch {
    // constants
    ndim: usize,      // space dimension
    ndiv: [usize; 3], // number of divisions along each direction
    xmin: [f64; 3],   // min values
    xmax: [f64; 3],   // max values
    xdelta: [f64; 3], // difference between max and min
    size: [f64; 3],   // size of each container
    cf: [usize; 3],   // coefficients [1, ndiv[0], ndiv[0]*ndiv[1]] (Eq. 8)

    // auxiliary variable
    ratio: [usize; 3], // ratio = trunc(δx[i]/Δx[i]) (Eq. 8)

    // holds non-empty containers. maps container.index to container.data
    containers: HashMap<usize, Container>,
}

impl GridSearch {
    /// Creates a new GridSearch
    ///
    /// # Input
    ///
    /// * `xmin, xmax` -- min and max coordinates (len = 2 or 3 == ndim)
    /// * `ndiv` -- number of divisions along each dimension (len = 2 or 3 == ndim)
    pub fn new(xmin: &[f64], xmax: &[f64], ndiv: &[usize]) -> Result<Self, &'static str> {
        // check input
        let ndim = ndiv.len();
        if ndim < 2 || ndim > 3 {
            return Err("ndim must be 2 or 3");
        }
        if xmin.len() != ndim {
            return Err("size of xmin must equal ndim");
        }
        if xmax.len() != ndim {
            return Err("size of xmax must equal ndim");
        }

        // allocate gs
        let mut grid = GridSearch {
            ndim,
            ndiv: [0; 3],
            xmin: [0.0; 3],
            xmax: [0.0; 3],
            xdelta: [0.0; 3],
            size: [0.0; 3],
            ratio: [0; 3],
            cf: [0; 3],
            containers: HashMap::new(),
        };

        // check and compute sizes
        for i in 0..ndim {
            grid.ndiv[i] = ndiv[i];
            if ndiv[i] < 1 {
                return Err("ndiv must be at least 1");
            }
            grid.xmin[i] = xmin[i];
            grid.xmax[i] = xmax[i];
            grid.xdelta[i] = xmax[i] - xmin[i];
            if grid.xdelta[i] <= 0.0 {
                return Err("xmax must be greater than xmin");
            }
            grid.size[i] = grid.xdelta[i] / (ndiv[i] as f64);
        }

        // coefficient
        grid.cf[0] = 1;
        grid.cf[1] = grid.ndiv[0];
        grid.cf[2] = grid.ndiv[0] * grid.ndiv[1];

        // done
        Ok(grid)
    }

    /// Inserts a new item to some container in the grid
    ///
    /// # Input
    ///
    /// * `id` -- identification number for the item
    /// * `x` -- coordinates of the item (an 1D array with len = ndim)
    pub fn insert<'a, T, U>(&mut self, id: usize, x: &'a T) -> Result<(), &'static str>
    where
        T: AsArray1D<'a, U>,
        U: 'a + Into<f64>,
    {
        if x.size() != self.ndim {
            return Err("x must have len equal to ndim");
        }
        match self.container_index(x) {
            Some(index) => {
                // new item data
                let mut item = Item {
                    id,
                    x: [x.at(0).into(), x.at(1).into(), 0.0],
                };
                if self.ndim == 3 {
                    item.x[2] = x.at(2).into();
                }

                // update container
                if self.containers.contains_key(&index) {
                    let container = self.containers.get_mut(&index).unwrap();
                    container.items.push(item);

                // initialize container
                } else {
                    self.containers.insert(index, Container { items: vec![item] });
                }
            }
            None => return Err("point is outside the grid"),
        }
        Ok(())
    }

    /// Returns a drawing of this object
    pub fn plot(&self) -> Result<Plot, &'static str> {
        // create plot
        let mut plot = Plot::new();

        // draw grid
        let mut xmin = vec![0.0; self.ndim];
        let mut xmax = vec![0.0; self.ndim];
        let mut ndiv = vec![0; self.ndim];
        for i in 0..self.ndim {
            xmin[i] = self.xmin[i];
            xmax[i] = self.xmax[i];
            ndiv[i] = self.ndiv[i];
        }
        let mut shapes = Shapes::new();
        shapes
            .set_alt_text_color("#5d5d5d")
            .draw_grid(&xmin, &xmax, &ndiv, false, true)?;
        plot.add(&shapes);

        // draw items
        if self.ndim == 2 {
            let mut curve = Curve::new();
            let mut text = Text::new();
            curve
                .set_marker_style("o")
                .set_marker_color("#fab32faa")
                .set_marker_line_color("black")
                .set_marker_line_width(0.5);
            text.set_color("#cd0000");
            for container in self.containers.values() {
                for item in &container.items {
                    let txt = format!("{}", item.id);
                    curve.draw(&[item.x[0]], &[item.x[1]]);
                    text.draw(item.x[0], item.x[1], &txt);
                }
            }
            plot.add(&curve);
            plot.add(&text);
        }
        Ok(plot)
    }

    /// Calculates the container index where the point x should be located
    ///
    /// # Output
    ///
    /// * returns the index of the container or None if the point is out-of-range
    fn container_index<'a, T, U>(&mut self, x: &'a T) -> Option<usize>
    where
        T: AsArray1D<'a, U>,
        U: 'a + Into<f64>,
    {
        let mut index = 0;
        for i in 0..self.ndim {
            if x.at(i).into() < self.xmin[i] || x.at(i).into() > self.xmax[i] {
                return None;
            }
            self.ratio[i] = ((x.at(i).into() - self.xmin[i]) / self.size[i]) as usize;
            if self.ratio[i] == self.ndiv[i] {
                // the point is exactly on the max edge, thus select inner container
                self.ratio[i] -= 1; // move to the inside
            }
            index += self.ratio[i] * self.cf[i];
        }
        Some(index)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    struct TestData {
        id: usize,
        x: Vec<f64>,
        container_index: usize,
    }

    fn get_test_data() -> Vec<TestData> {
        vec![
            TestData {
                id: 100,
                x: vec![0.0, 0.2],
                container_index: 6,
            },
            TestData {
                id: 200,
                x: vec![0.2, 0.6000000000000001],
                container_index: 12,
            },
            TestData {
                id: 300,
                x: vec![0.4, 1.0],
                // in this case, the ratio is:
                // 3.0000000000000004, 2.9999999999999996
                // thus, the point falls in #13 instead of #18
                container_index: 13,
            },
            TestData {
                id: 400,
                x: vec![0.6, 1.4],
                // in this case, the ratio is:
                // 4, 3.9999999999999996
                // thus, the point falls in #19 instead of #24
                container_index: 19,
            },
            TestData {
                id: 500,
                x: vec![0.8, 1.8],
                container_index: 24,
            },
        ]
    }

    #[test]
    fn new_works() -> Result<(), &'static str> {
        let grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        assert_eq!(grid.ndim, 2);
        assert_eq!(grid.ndiv, [5, 5, 0]);
        assert_eq!(grid.xmin, [-0.2, -0.2, 0.0]);
        assert_eq!(grid.xmax, [0.8, 1.8, 0.0]);
        assert_eq!(grid.xdelta, [1.0, 2.0, 0.0]);
        assert_eq!(grid.size, [0.2, 0.4, 0.0]);
        assert_eq!(grid.cf, [1, 5, 25]);
        assert_eq!(grid.ratio, [0, 0, 0]);
        assert_eq!(grid.containers.len(), 0);
        println!("{:.20}", grid.size[0]);
        assert_eq!(grid.size[0], 0.20000000000000001110); // TODO: check if this is a problem
        let b0 = 0.20000000000000001110_f64.to_bits();
        let b1 = 0.2_f64.to_bits();
        println!("{} =? {}", b0, b1);
        assert_eq!(b0, b1);
        Ok(())
    }

    #[test]
    fn container_index_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        for data in get_test_data() {
            let index = grid.container_index(&data.x).unwrap();
            assert_eq!(index, data.container_index);
        }
        Ok(())
    }

    #[test]
    fn insert_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        for data in get_test_data() {
            grid.insert(data.id, &data.x)?;
            let container = grid.containers.get(&data.container_index).unwrap();
            let item = container.items.iter().find(|item| item.id == data.id).unwrap();
            assert_eq!(item.id, data.id);
        }
        assert_eq!(grid.containers.len(), 5);
        Ok(())
    }

    #[test]
    fn plot_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        for data in get_test_data() {
            grid.insert(data.id, &data.x)?;
        }
        let plot = grid.plot()?;
        plot.save("/tmp/gemlab/search_grid_plot_works.svg")?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Standardized isolation of logic as a `process` wrapper around a `thread`.
//!
//! Basic wrapper around threads to provide some standard API. All long-living Hat threads run
//! as a `process`. The main difference between a normal Rust `thread` and a Hat `process` is
//! currently that the `process` has a bounded input-channel and a standard implementation of a
//! synchronous `send_reply()`.

/// A long-living `thread` is promoted to a standard `process`.
///
/// To create a new `process`, simply define a `Msg` type, a `Reply` type and a state struct
/// that implements the `MsgHandler` trait. You can then create a new process with:
///
/// ```rust,ignore
/// enum Msg {Ping, Foo}
/// enum Reply {Pong, Bar}
///
/// struct MyHandler {
///   fn handle(&mut self, msg: Msg, reply: |Reply|) {
///     match Msg {
///       Ping => return reply(Pong),
///       Foo => return reply(Bar),
///     }
///   }
/// }
///
/// fn main() {
///   let p = Process::new(MyHandler::new());
///   let pong = p.send_reply(Ping);
/// }
/// ```
///
/// The handler must always call `reply()` to release any call to `send_reply()`. It is allowed to
/// call `reply()` "early" - before all work has been done - but calling `reply()` is usually the
/// last thing a handler does. The idiom `return reply(...)` is a simple way of guaranteeing this.
///
/// A handler is allowed to call `reply()` **exactly** once. Not calling it or calling it multiple
/// times will likely cause runtime panicure when using `send_reply()`.

use std::fmt;
use std::thread;
use std::sync::{mpsc, Arc, Mutex};

pub struct Process<Msg, Reply, E> {
    sender: mpsc::SyncSender<(Msg, mpsc::Sender<Result<Reply, E>>)>,
    poison_after: Option<i64>,
    poisoned: Arc<Mutex<bool>>,
}

/// When cloning a `process` we clone the input-channel, allowing multiple threads to share the same
/// `process`.
impl<Msg: Send, Reply: Send, E> Clone for Process<Msg, Reply, E> {
    fn clone(&self) -> Process<Msg, Reply, E> {
        Process {
            sender: self.sender.clone(),
            poison_after: None,
            poisoned: self.poisoned.clone(),
        }
    }
}

pub trait MsgHandler<Msg, Reply> {
    type Err;

    fn handle(&mut self,
              msg: Msg,
              callback: Box<Fn(Result<Reply, Self::Err>)>)
              -> Result<(), Self::Err>;
}

impl<Msg: 'static + Send, Reply: 'static + Send, E> Process<Msg, Reply, E> {
    /// Create and start a new process using `handler`.
    pub fn new<H, F>(handler_proc: F) -> Result<Process<Msg, Reply, E>, E>
        where H: 'static + MsgHandler<Msg, Reply, Err = E> + Send,
              E: 'static + From<mpsc::RecvError> + fmt::Debug + Send,
              F: FnOnce() -> Result<H, E>
    {
        Process::new_with_poison(handler_proc, None)
    }

    pub fn new_with_poison<H, F>(handler_proc: F,
                                 poison_after: Option<i64>)
                                 -> Result<Process<Msg, Reply, E>, E>
        where H: 'static + MsgHandler<Msg, Reply, Err = E> + Send,
              E: 'static + From<mpsc::RecvError> + fmt::Debug + Send,
              F: FnOnce() -> Result<H, E>
    {
        let (sender, receiver) = mpsc::sync_channel(10);
        let p = Process {
            sender: sender,
            poison_after: poison_after,
            poisoned: Arc::new(Mutex::new(false)),
        };

        try!(p.start(receiver, handler_proc));

        Ok(p)
    }

    fn start<H, F>(&self,
                   receiver: mpsc::Receiver<(Msg, mpsc::Sender<Result<Reply, E>>)>,
                   handler_proc: F)
                   -> Result<(), E>
        where H: 'static + MsgHandler<Msg, Reply, Err = E> + Send,
              E: 'static + From<mpsc::RecvError> + fmt::Debug + Send,
              F: FnOnce() -> Result<H, E>
    {
        let poison_after = self.poison_after;
        let mut my_handler = try!(handler_proc());

        let poisoned = self.poisoned.clone();

        thread::spawn(move || {
            // fork handler
            let mut handle_msg = |msg, rep: mpsc::Sender<Result<Reply, E>>| {
                let did_reply = Arc::new(Mutex::new(false));
                let local_did_reply = did_reply.clone();
                let local_rep = rep.clone();
                let ret = my_handler.handle(msg,
                                            Box::new(move |r| {
                                                *local_did_reply.lock().unwrap() = true;
                                                local_rep.send(r)
                                                    .expect("Message reply ignored");
                                            }));
                match ret {
                    Ok(()) => assert_eq!(*did_reply.lock().unwrap(), true),
                    Err(e) => {
                        if *did_reply.lock().expect("Message reply ignored") {
                            return Err(format!("Encountered unrecoverable error: {:?}", e));
                        } else {
                            rep.send(Err(e)).expect("Message reply ignored");
                        }
                    }
                }

                Ok(())
            };
            let mut do_loop = || {
                match poison_after {
                    Some(msg_count) => {
                        for _ in 0..msg_count {
                            if let Ok((msg, rep)) = receiver.recv() {
                                try!(handle_msg(msg, rep))
                            } else {
                                return Ok(());  // Clean shutdown.
                            }
                        }
                        return Err("Process has reached message limit".to_string());
                    }
                    None => {
                        while let Ok((msg, rep)) = receiver.recv() {
                            try!(handle_msg(msg, rep))
                        }
                    }
                };
                Ok(())
            };
            while let Err(e) = do_loop() {
                *poisoned.lock().unwrap() = true;  // This process is in a polluted state.
                error!("Poisoned process: {:?}", e);
            }
        });

        Ok(())
    }

    /// Synchronous send.
    ///
    /// Will always wait for a reply from the receiving `process`.
    pub fn send_reply(&self, msg: Msg) -> Result<Reply, E>
        where E: From<String>
    {
        let (sender, receiver) = mpsc::channel();

        if *self.poisoned.lock().unwrap() {
            return Err(From::from("Refusing to forward message to poisoned process".to_string()));
        }

        if let Err(e) = self.sender.send((msg, sender)) {
            return Err(From::from("Could not send message: process is dead".to_string()));
        }

        match receiver.recv() {
            Err(e) => Err(From::from("Could not read reply".to_string())),
            Ok(reply) => reply,
        }
    }
}
<commit_msg>Downgrade from error! to warn!.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Standardized isolation of logic as a `process` wrapper around a `thread`.
//!
//! Basic wrapper around threads to provide some standard API. All long-living Hat threads run
//! as a `process`. The main difference between a normal Rust `thread` and a Hat `process` is
//! currently that the `process` has a bounded input-channel and a standard implementation of a
//! synchronous `send_reply()`.

/// A long-living `thread` is promoted to a standard `process`.
///
/// To create a new `process`, simply define a `Msg` type, a `Reply` type and a state struct
/// that implements the `MsgHandler` trait. You can then create a new process with:
///
/// ```rust,ignore
/// enum Msg {Ping, Foo}
/// enum Reply {Pong, Bar}
///
/// struct MyHandler {
///   fn handle(&mut self, msg: Msg, reply: |Reply|) {
///     match Msg {
///       Ping => return reply(Pong),
///       Foo => return reply(Bar),
///     }
///   }
/// }
///
/// fn main() {
///   let p = Process::new(MyHandler::new());
///   let pong = p.send_reply(Ping);
/// }
/// ```
///
/// The handler must always call `reply()` to release any call to `send_reply()`. It is allowed to
/// call `reply()` "early" - before all work has been done - but calling `reply()` is usually the
/// last thing a handler does. The idiom `return reply(...)` is a simple way of guaranteeing this.
///
/// A handler is allowed to call `reply()` **exactly** once. Not calling it or calling it multiple
/// times will likely cause runtime panicure when using `send_reply()`.

use std::fmt;
use std::thread;
use std::sync::{mpsc, Arc, Mutex};

pub struct Process<Msg, Reply, E> {
    sender: mpsc::SyncSender<(Msg, mpsc::Sender<Result<Reply, E>>)>,
    poison_after: Option<i64>,
    poisoned: Arc<Mutex<bool>>,
}

/// When cloning a `process` we clone the input-channel, allowing multiple threads to share the same
/// `process`.
impl<Msg: Send, Reply: Send, E> Clone for Process<Msg, Reply, E> {
    fn clone(&self) -> Process<Msg, Reply, E> {
        Process {
            sender: self.sender.clone(),
            poison_after: None,
            poisoned: self.poisoned.clone(),
        }
    }
}

pub trait MsgHandler<Msg, Reply> {
    type Err;

    fn handle(&mut self,
              msg: Msg,
              callback: Box<Fn(Result<Reply, Self::Err>)>)
              -> Result<(), Self::Err>;
}

impl<Msg: 'static + Send, Reply: 'static + Send, E> Process<Msg, Reply, E> {
    /// Create and start a new process using `handler`.
    pub fn new<H, F>(handler_proc: F) -> Result<Process<Msg, Reply, E>, E>
        where H: 'static + MsgHandler<Msg, Reply, Err = E> + Send,
              E: 'static + From<mpsc::RecvError> + fmt::Debug + Send,
              F: FnOnce() -> Result<H, E>
    {
        Process::new_with_poison(handler_proc, None)
    }

    pub fn new_with_poison<H, F>(handler_proc: F,
                                 poison_after: Option<i64>)
                                 -> Result<Process<Msg, Reply, E>, E>
        where H: 'static + MsgHandler<Msg, Reply, Err = E> + Send,
              E: 'static + From<mpsc::RecvError> + fmt::Debug + Send,
              F: FnOnce() -> Result<H, E>
    {
        let (sender, receiver) = mpsc::sync_channel(10);
        let p = Process {
            sender: sender,
            poison_after: poison_after,
            poisoned: Arc::new(Mutex::new(false)),
        };

        try!(p.start(receiver, handler_proc));

        Ok(p)
    }

    fn start<H, F>(&self,
                   receiver: mpsc::Receiver<(Msg, mpsc::Sender<Result<Reply, E>>)>,
                   handler_proc: F)
                   -> Result<(), E>
        where H: 'static + MsgHandler<Msg, Reply, Err = E> + Send,
              E: 'static + From<mpsc::RecvError> + fmt::Debug + Send,
              F: FnOnce() -> Result<H, E>
    {
        let poison_after = self.poison_after;
        let mut my_handler = try!(handler_proc());

        let poisoned = self.poisoned.clone();

        thread::spawn(move || {
            // fork handler
            let mut handle_msg = |msg, rep: mpsc::Sender<Result<Reply, E>>| {
                let did_reply = Arc::new(Mutex::new(false));
                let local_did_reply = did_reply.clone();
                let local_rep = rep.clone();
                let ret = my_handler.handle(msg,
                                            Box::new(move |r| {
                                                *local_did_reply.lock().unwrap() = true;
                                                local_rep.send(r)
                                                    .expect("Message reply ignored");
                                            }));
                match ret {
                    Ok(()) => assert_eq!(*did_reply.lock().unwrap(), true),
                    Err(e) => {
                        if *did_reply.lock().expect("Message reply ignored") {
                            return Err(format!("Encountered unrecoverable error: {:?}", e));
                        } else {
                            rep.send(Err(e)).expect("Message reply ignored");
                        }
                    }
                }

                Ok(())
            };
            let mut do_loop = || {
                match poison_after {
                    Some(msg_count) => {
                        for _ in 0..msg_count {
                            if let Ok((msg, rep)) = receiver.recv() {
                                try!(handle_msg(msg, rep))
                            } else {
                                return Ok(());  // Clean shutdown.
                            }
                        }
                        return Err("Process has reached message limit".to_string());
                    }
                    None => {
                        while let Ok((msg, rep)) = receiver.recv() {
                            try!(handle_msg(msg, rep))
                        }
                    }
                };
                Ok(())
            };
            while let Err(e) = do_loop() {
                *poisoned.lock().unwrap() = true;  // This process is in a polluted state.
                warn!("Poisoned process: {:?}", e);
            }
        });

        Ok(())
    }

    /// Synchronous send.
    ///
    /// Will always wait for a reply from the receiving `process`.
    pub fn send_reply(&self, msg: Msg) -> Result<Reply, E>
        where E: From<String>
    {
        let (sender, receiver) = mpsc::channel();

        if *self.poisoned.lock().unwrap() {
            return Err(From::from("Refusing to forward message to poisoned process".to_string()));
        }

        if let Err(e) = self.sender.send((msg, sender)) {
            return Err(From::from("Could not send message: process is dead".to_string()));
        }

        match receiver.recv() {
            Err(e) => Err(From::from("Could not read reply".to_string())),
            Ok(reply) => reply,
        }
    }
}
<|endoftext|>


<commit_before>use bracket_lib::prelude::*;

enum GameMode {
    Menu,
    Playing,
    End,
}

struct Player {
    x: i32,
    y: i32,
    velocity: f32,
}

impl Player {
    fn new(x: i32, y: i32) -> Self {
        Player {
            x,
            y,
            velocity: 0.0,
        }
    }

    fn render(&mut self, ctx: &mut BTerm) {
        ctx.set(
            0,
            self.y,
            YELLOW,
            BLACK,
            to_cp437('@')
        );
    }

    fn gravity_and_move(&mut self) {
        if self.velocity < 2.0 {
            self.velocity += 0.2;
        }
        self.y += self.velocity as i32;
        self.x += 1;
        if self.y < 0 {
            self.y = 0;
        }
    }

    fn flap(&mut self) {
        self.velocity = -2.0;
    }
}

struct State {
    player: Player,
    frame_time: f32,
    mode: GameMode,
}

impl State {
    fn new() -> Self {
        State {
            player: Player::new(5, 25),
            frame_time: 0.0,
            mode: GameMode::Menu,
        }
    }

    fn play(&mut self, ctx: &mut BTerm) {
        ctx.cls_bg(NAVY);
        self.frame_time += ctx.frame_time_ms;
        if self.frame_time > FRAME_DURATION {
            self.frame_time = 0.0;
            self.player.gravity_and_move();
        }
        if let Some(VirtualKeyCode::Space) = ctx.key {
            self.player.flap();
        }
        self.player.render(ctx);
        ctx.print(0,0, "Press SPACE to flap.");
        if self.player.y > SCREEN_HEIGHT {
            self.mode = GameMode::End;
        }
    }

    fn main_menu(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "Welcome to Flappy Dragon");
        ctx.print_centered(8, "(P) Play Game");
        ctx.print_centered(9, "(Q) Quit Game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }

    }

    fn dead(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "You are dead!");
        ctx.print_centered(8, "(P) Play Game");
        ctx.print_centered(9, "(Q) Quit Game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }
    }

    fn restart(&mut self) {
        self.player = Player::new(5, 25);
        self.frame_time = 0.0;
        self.mode = GameMode::Playing;
    }
}

impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        match self.mode {
            GameMode::Menu => self.main_menu(ctx),
            GameMode::End => self.dead(ctx),
            GameMode::Playing => self.play(ctx),
        }
    }
}

const SCREEN_WIDTH : i32 = 80;
const SCREEN_HEIGHT : i32 = 50;
const FRAME_DURATION : f32 = 75.0;

fn main() -> BError {
    let context = BTermBuilder::simple80x50()
        .with_title("Flappy Dragon")
        .build()?;
    main_loop(context, State::new())
}
<commit_msg>render obstacle<commit_after>use bracket_lib::prelude::*;

enum GameMode {
    Menu,
    Playing,
    End,
}

struct Player {
    x: i32,
    y: i32,
    velocity: f32,
}

impl Player {
    fn new(x: i32, y: i32) -> Self {
        Player {
            x,
            y,
            velocity: 0.0,
        }
    }

    fn render(&mut self, ctx: &mut BTerm) {
        ctx.set(
            0,
            self.y,
            YELLOW,
            BLACK,
            to_cp437('@')
        );
    }

    fn gravity_and_move(&mut self) {
        if self.velocity < 2.0 {
            self.velocity += 0.2;
        }
        self.y += self.velocity as i32;
        self.x += 1;
        if self.y < 0 {
            self.y = 0;
        }
    }

    fn flap(&mut self) {
        self.velocity = -2.0;
    }
}

struct State {
    player: Player,
    frame_time: f32,
    obstacle: Obstacle,
    mode: GameMode,
}

impl State {
    fn new() -> Self {
        State {
            player: Player::new(5, 25),
            frame_time: 0.0,
            obstacle: Obstacle::new(SCREEN_WIDTH, 0),
            mode: GameMode::Menu,
        }
    }

    fn play(&mut self, ctx: &mut BTerm) {
        ctx.cls_bg(NAVY);
        self.frame_time += ctx.frame_time_ms;
        if self.frame_time > FRAME_DURATION {
            self.frame_time = 0.0;
            self.player.gravity_and_move();
        }
        if let Some(VirtualKeyCode::Space) = ctx.key {
            self.player.flap();
        }
        self.player.render(ctx);
        ctx.print(0,0, "Press SPACE to flap.");

        self.obstacle.render(ctx, self.player.x);
        if self.player.y > SCREEN_HEIGHT {
            self.mode = GameMode::End;
        }
    }

    fn main_menu(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "Welcome to Flappy Dragon");
        ctx.print_centered(8, "(P) Play Game");
        ctx.print_centered(9, "(Q) Quit Game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }

    }

    fn dead(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(5, "You are dead!");
        ctx.print_centered(8, "(P) Play Game");
        ctx.print_centered(9, "(Q) Quit Game");

        if let Some(key) = ctx.key {
            match key {
                VirtualKeyCode::P => self.restart(),
                VirtualKeyCode::Q => ctx.quitting = true,
                _ => {}
            }
        }
    }

    fn restart(&mut self) {
        self.player = Player::new(5, 25);
        self.frame_time = 0.0;
        self.mode = GameMode::Playing;
    }
}

impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        match self.mode {
            GameMode::Menu => self.main_menu(ctx),
            GameMode::End => self.dead(ctx),
            GameMode::Playing => self.play(ctx),
        }
    }
}

struct Obstacle {
    x: i32,
    /// Defines the size of the gap for the dragon to pass
    gap_y: i32,
    /// Defines the length of the gap for the dragon to pass
    size: i32
}

impl Obstacle {
    fn new(x: i32, score: i32) -> Self {
        let mut random = RandomNumberGenerator::new();
        Obstacle {
            x,
            gap_y: random.range(10, 40),
            size: i32::max(2, 20 - score)
        }

    }

    fn render(&mut self, ctx: &mut BTerm, player_x: i32) {
        let screen_x = self.x - player_x;
        let half_size = self.size / 2;

        // Draw the top half of the ovstacle
        for y in 0..self.gap_y - half_size {
            ctx.set(
                screen_x,
                y,
                RED,
                BLACK,
                to_cp437('|'),
            );
        }

        // Draw the bottom half of the Obstacle
        for y in self.gap_y + half_size..SCREEN_HEIGHT {
            ctx.set(
                screen_x,
                y,
                RED,
                BLACK,
                to_cp437('|'),
            );
        }
    }
}

// CONST

const SCREEN_WIDTH : i32 = 80;
const SCREEN_HEIGHT : i32 = 50;
const FRAME_DURATION : f32 = 75.0;

// END CONST

fn main() -> BError {
    let context = BTermBuilder::simple80x50()
        .with_title("Flappy Dragon")
        .build()?;
    main_loop(context, State::new())
}
<|endoftext|>


<commit_before>use std::char;

use super::unicode;

/// Takes a stringly description of a character (the character itself,
/// or a unicode code point name) and returns a Vec of Describable
/// elements that hold the corresponding character. The elements of
/// the vector are sorted by descending numeric code point.
pub fn from_arg(spec: &str) -> Vec<char> {
    let mut chars: Vec<char> = Vec::new();
    let mut try_names = true;

    // match the character itself, or any of its names:
    if spec.chars().count() == 1 {
        spec.chars().next().map(|c| chars.push(c));
        try_names = false;
    } else if spec.starts_with("0x") || spec.starts_with("U+") {
        let _ = u32::from_str_radix(&spec[2..], 16).ok().
            map(|num| char::from_u32(num).map(|c| chars.push(c)));
    }

    // Match plain numbers in all bases:
    for base in vec![16, 10, 8, 2] {
        let _ = u32::from_str_radix(spec, base.clone()).ok().
            map(|num| char::from_u32(num).map(|c| chars.push(c)));
    }

    // Match ^-escapes as control characters
    if spec.len() == 2 && spec.starts_with("^") {
        let control = spec.as_bytes()[1];
        match control {
            0x3f => chars.push(0x7f as char), // ^? is DEL
            _ => chars.push((spec.as_bytes()[1] & 0x1f) as char)
        }
        try_names = false;
    }

    // Match characters from all our name tables:
    if try_names {
        chars.append(unicode::lookup_by_query(spec).as_mut());
    }

    chars.sort_by(|a, b| b.cmp(a));
    chars.dedup();
    chars
}

#[test]
fn from_arg_translates_chars() {
    assert_eq!('n', from_arg("n")[0]);
    assert_eq!(']', from_arg("]")[0]);
}

#[test]
fn from_arg_translates_descriptions() {
    assert_eq!('n', from_arg("latin small letter n")[0]);
    assert_eq!(']', from_arg("right square bracket")[0]);
}

#[test]
fn from_arg_translates_numbers() {
    let received = from_arg("60");
    let mut iter = received.iter();
    assert_eq!('`', *iter.next().unwrap());
    assert_eq!('<', *iter.next().unwrap());
    assert_eq!('0', *iter.next().unwrap());

    assert_eq!(2, from_arg("0").len());
    assert_eq!(0x30 as char, *from_arg("0").iter().next().unwrap());

    assert_eq!(1, from_arg("0x0").len());
    assert_eq!(1, from_arg("0x41").len());
    assert_eq!('A', from_arg("0x41")[0]);
}

#[test]
fn from_arg_translates_controls() {
    assert_eq!(0x7f as char, from_arg("^?")[0]);
    assert_eq!(0x03 as char, from_arg("^c")[0]);
    assert_eq!(0x03 as char, from_arg("^C")[0]);
}
<commit_msg>Update one failing test case<commit_after>use std::char;

use super::unicode;

/// Takes a stringly description of a character (the character itself,
/// or a unicode code point name) and returns a Vec of Describable
/// elements that hold the corresponding character. The elements of
/// the vector are sorted by descending numeric code point.
pub fn from_arg(spec: &str) -> Vec<char> {
    let mut chars: Vec<char> = Vec::new();
    let mut try_names = true;

    // match the character itself, or any of its names:
    if spec.chars().count() == 1 {
        spec.chars().next().map(|c| chars.push(c));
        try_names = false;
    } else if spec.starts_with("0x") || spec.starts_with("U+") {
        let _ = u32::from_str_radix(&spec[2..], 16).ok().
            map(|num| char::from_u32(num).map(|c| chars.push(c)));
    }

    // Match plain numbers in all bases:
    for base in vec![16, 10, 8, 2] {
        let _ = u32::from_str_radix(spec, base.clone()).ok().
            map(|num| char::from_u32(num).map(|c| chars.push(c)));
    }

    // Match ^-escapes as control characters
    if spec.len() == 2 && spec.starts_with("^") {
        let control = spec.as_bytes()[1];
        match control {
            0x3f => chars.push(0x7f as char), // ^? is DEL
            _ => chars.push((spec.as_bytes()[1] & 0x1f) as char)
        }
        try_names = false;
    }

    // Match characters from all our name tables:
    if try_names {
        chars.append(unicode::lookup_by_query(spec).as_mut());
    }

    chars.sort_by(|a, b| b.cmp(a));
    chars.dedup();
    chars
}

#[test]
fn from_arg_translates_chars() {
    assert_eq!('n', from_arg("n")[0]);
    assert_eq!(']', from_arg("]")[0]);
}

#[test]
fn from_arg_translates_descriptions() {
    assert_eq!('n', from_arg("latin small letter n")[0]);
    assert_eq!(']', from_arg("right square bracket")[0]);
}

#[test]
fn from_arg_translates_numbers() {
    let received = from_arg("60");
    let mut iter = received.iter();
    assert_eq!('\u{e012b}', *iter.next().unwrap());
    assert_eq!('`', *iter.next().unwrap());
    assert_eq!('<', *iter.next().unwrap());
    assert_eq!('0', *iter.next().unwrap());

    assert_eq!(2, from_arg("0").len());
    assert_eq!(0x30 as char, *from_arg("0").iter().next().unwrap());

    assert_eq!(1, from_arg("0x0").len());
    assert_eq!(1, from_arg("0x41").len());
    assert_eq!('A', from_arg("0x41")[0]);
}

#[test]
fn from_arg_translates_controls() {
    assert_eq!(0x7f as char, from_arg("^?")[0]);
    assert_eq!(0x03 as char, from_arg("^c")[0]);
    assert_eq!(0x03 as char, from_arg("^C")[0]);
}
<|endoftext|>


<commit_before>extern crate openssl;

use self::openssl::error::ErrorStack;
use self::openssl::pkcs12::{ParsedPkcs12, Pkcs12};
use self::openssl::ssl::{
    self, MidHandshakeSslStream, SslAcceptor, SslConnector, SslContextBuilder, SslMethod,
    SslVerifyMode,
};
use self::openssl::x509::X509;
use std::error;
use std::fmt;
use std::io;

use {Protocol, TlsAcceptorBuilder, TlsConnectorBuilder};

#[cfg(have_min_max_version)]
fn supported_protocols(
    min: Option<Protocol>,
    max: Option<Protocol>,
    ctx: &mut SslContextBuilder,
) -> Result<(), ErrorStack> {
    use self::openssl::ssl::SslVersion;

    fn cvt(p: Protocol) -> SslVersion {
        match p {
            Protocol::Sslv3 => SslVersion::SSL3,
            Protocol::Tlsv10 => SslVersion::TLS1,
            Protocol::Tlsv11 => SslVersion::TLS1_1,
            Protocol::Tlsv12 => SslVersion::TLS1_2,
            Protocol::__NonExhaustive => unreachable!(),
        }
    }

    ctx.set_min_proto_version(min.map(cvt))?;
    ctx.set_max_proto_version(max.map(cvt))?;

    Ok(())
}

#[cfg(not(have_min_max_version))]
fn supported_protocols(
    min: Option<Protocol>,
    max: Option<Protocol>,
    ctx: &mut SslContextBuilder,
) -> Result<(), ErrorStack> {
    use self::openssl::ssl::SslOptions;

    let no_ssl_mask = SslOptions::NO_SSLV2
        | SslOptions::NO_SSLV3
        | SslOptions::NO_TLSV1
        | SslOptions::NO_TLSV1_1
        | SslOptions::NO_TLSV1_2;

    ctx.clear_options(no_ssl_mask);
    let mut options = SslOptions::NO_SSLV2;
    match min {
        None | Some(Protocol::Sslv3) => {}
        Some(Protocol::Tlsv10) => options |= SslOptions::NO_SSLV3,
        Some(Protocol::Tlsv11) => options |= SslOptions::NO_SSLV3 | SslOptions::NO_TLSV1,
        Some(Protocol::Tlsv12) => {
            options |= SslOptions::NO_SSLV3 | SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1
        }
        Some(Protocol::__NonExhaustive) => unreachable!(),
    }
    match max {
        None | Some(Protocol::Tlsv12) => {}
        Some(Protocol::Tlsv11) => options |= SslOptions::NO_TLSV1_2,
        Some(Protocol::Tlsv10) => options |= SslOptions::NO_TLSV1_1 | SslOptions::NO_TLSV1_2,
        Some(Protocol::Sslv3) => {
            options |= SslOptions::NO_TLSV1_0 | SslOptions::NO_TLSV1_1 | SslOptions::NO_TLSV1_2
        }
    }

    ctx.set_options(options);

    Ok(())
}

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        err.into()
    }
}

pub struct Identity(ParsedPkcs12);

impl Identity {
    pub fn from_pkcs12(buf: &[u8], pass: &str) -> Result<Identity, Error> {
        let pkcs12 = Pkcs12::from_der(buf)?;
        let parsed = pkcs12.parse(pass)?;
        Ok(Identity(parsed))
    }
}

#[derive(Clone)]
pub struct Certificate(X509);

impl Certificate {
    pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = X509::from_der(buf)?;
        Ok(Certificate(cert))
    }
    pub fn from_pem(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = X509::from_pem(buf)?;
        Ok(Certificate(cert))
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
where
    S: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
where
    S: io::Read + io::Write,
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    WouldBlock(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::SetupFailure(e) => HandshakeError::Failure(e.into()),
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e.into_error())),
            ssl::HandshakeError::WouldBlock(s) => {
                HandshakeError::WouldBlock(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

#[derive(Clone)]
pub struct TlsConnector {
    connector: SslConnector,
    use_sni: bool,
    accept_invalid_hostnames: bool,
    accept_invalid_certs: bool,
}

impl TlsConnector {
    pub fn new(builder: &TlsConnectorBuilder) -> Result<TlsConnector, Error> {
        let mut connector = SslConnector::builder(SslMethod::tls())?;
        if let Some(ref identity) = builder.identity {
            connector.set_certificate(&(identity.0).0.cert)?;
            connector.set_private_key(&(identity.0).0.pkey)?;
            if let Some(ref chain) = (identity.0).0.chain {
                for cert in chain {
                    connector.add_extra_chain_cert(cert.to_owned())?;
                }
            }
        }
        supported_protocols(builder.min_protocol, builder.max_protocol, &mut connector)?;

        for cert in &builder.root_certificates {
            connector.cert_store_mut().add_cert((cert.0).0.clone())?;
        }

        Ok(TlsConnector {
            connector: connector.build(),
            use_sni: builder.use_sni,
            accept_invalid_hostnames: builder.accept_invalid_hostnames,
            accept_invalid_certs: builder.accept_invalid_certs,
        })
    }

    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut ssl = self
            .connector
            .configure()?
            .use_server_name_indication(self.use_sni)
            .verify_hostname(!self.accept_invalid_hostnames);
        if self.accept_invalid_certs {
            ssl.set_verify(SslVerifyMode::NONE);
        }

        let s = ssl.connect(domain, stream)?;
        Ok(TlsStream(s))
    }
}

#[derive(Clone)]
pub struct TlsAcceptor(SslAcceptor);

impl TlsAcceptor {
    pub fn new(builder: &TlsAcceptorBuilder) -> Result<TlsAcceptor, Error> {
        let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
        acceptor.set_private_key(&(builder.identity.0).0.pkey)?;
        acceptor.set_certificate(&(builder.identity.0).0.cert)?;
        if let Some(ref chain) = &(builder.identity.0).0.chain {
            for cert in chain {
                acceptor.add_extra_chain_cert(cert.to_owned())?;
            }
        }
        supported_protocols(builder.min_protocol, builder.max_protocol, &mut acceptor)?;

        Ok(TlsAcceptor(acceptor.build()))
    }

    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let s = self.0.accept(stream)?;
        Ok(TlsStream(s))
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        match self.0.shutdown() {
            Ok(_) => Ok(()),
            Err(ref e) if e.code() == ssl::ErrorCode::ZERO_RETURN => Ok(()),
            Err(e) => Err(e
                .into_io_error()
                .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))),
        }
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}
<commit_msg>Fix build on older rustcs<commit_after>extern crate openssl;

use self::openssl::error::ErrorStack;
use self::openssl::pkcs12::{ParsedPkcs12, Pkcs12};
use self::openssl::ssl::{
    self, MidHandshakeSslStream, SslAcceptor, SslConnector, SslContextBuilder, SslMethod,
    SslVerifyMode,
};
use self::openssl::x509::X509;
use std::error;
use std::fmt;
use std::io;

use {Protocol, TlsAcceptorBuilder, TlsConnectorBuilder};

#[cfg(have_min_max_version)]
fn supported_protocols(
    min: Option<Protocol>,
    max: Option<Protocol>,
    ctx: &mut SslContextBuilder,
) -> Result<(), ErrorStack> {
    use self::openssl::ssl::SslVersion;

    fn cvt(p: Protocol) -> SslVersion {
        match p {
            Protocol::Sslv3 => SslVersion::SSL3,
            Protocol::Tlsv10 => SslVersion::TLS1,
            Protocol::Tlsv11 => SslVersion::TLS1_1,
            Protocol::Tlsv12 => SslVersion::TLS1_2,
            Protocol::__NonExhaustive => unreachable!(),
        }
    }

    ctx.set_min_proto_version(min.map(cvt))?;
    ctx.set_max_proto_version(max.map(cvt))?;

    Ok(())
}

#[cfg(not(have_min_max_version))]
fn supported_protocols(
    min: Option<Protocol>,
    max: Option<Protocol>,
    ctx: &mut SslContextBuilder,
) -> Result<(), ErrorStack> {
    use self::openssl::ssl::SslOptions;

    let no_ssl_mask = SslOptions::NO_SSLV2
        | SslOptions::NO_SSLV3
        | SslOptions::NO_TLSV1
        | SslOptions::NO_TLSV1_1
        | SslOptions::NO_TLSV1_2;

    ctx.clear_options(no_ssl_mask);
    let mut options = SslOptions::NO_SSLV2;
    match min {
        None | Some(Protocol::Sslv3) => {}
        Some(Protocol::Tlsv10) => options |= SslOptions::NO_SSLV3,
        Some(Protocol::Tlsv11) => options |= SslOptions::NO_SSLV3 | SslOptions::NO_TLSV1,
        Some(Protocol::Tlsv12) => {
            options |= SslOptions::NO_SSLV3 | SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1
        }
        Some(Protocol::__NonExhaustive) => unreachable!(),
    }
    match max {
        None | Some(Protocol::Tlsv12) => {}
        Some(Protocol::Tlsv11) => options |= SslOptions::NO_TLSV1_2,
        Some(Protocol::Tlsv10) => options |= SslOptions::NO_TLSV1_1 | SslOptions::NO_TLSV1_2,
        Some(Protocol::Sslv3) => {
            options |= SslOptions::NO_TLSV1_0 | SslOptions::NO_TLSV1_1 | SslOptions::NO_TLSV1_2
        }
    }

    ctx.set_options(options);

    Ok(())
}

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        err.into()
    }
}

pub struct Identity(ParsedPkcs12);

impl Identity {
    pub fn from_pkcs12(buf: &[u8], pass: &str) -> Result<Identity, Error> {
        let pkcs12 = Pkcs12::from_der(buf)?;
        let parsed = pkcs12.parse(pass)?;
        Ok(Identity(parsed))
    }
}

#[derive(Clone)]
pub struct Certificate(X509);

impl Certificate {
    pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = X509::from_der(buf)?;
        Ok(Certificate(cert))
    }
    pub fn from_pem(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = X509::from_pem(buf)?;
        Ok(Certificate(cert))
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
where
    S: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
where
    S: io::Read + io::Write,
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    WouldBlock(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::SetupFailure(e) => HandshakeError::Failure(e.into()),
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e.into_error())),
            ssl::HandshakeError::WouldBlock(s) => {
                HandshakeError::WouldBlock(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

#[derive(Clone)]
pub struct TlsConnector {
    connector: SslConnector,
    use_sni: bool,
    accept_invalid_hostnames: bool,
    accept_invalid_certs: bool,
}

impl TlsConnector {
    pub fn new(builder: &TlsConnectorBuilder) -> Result<TlsConnector, Error> {
        let mut connector = SslConnector::builder(SslMethod::tls())?;
        if let Some(ref identity) = builder.identity {
            connector.set_certificate(&(identity.0).0.cert)?;
            connector.set_private_key(&(identity.0).0.pkey)?;
            if let Some(ref chain) = (identity.0).0.chain {
                for cert in chain {
                    connector.add_extra_chain_cert(cert.to_owned())?;
                }
            }
        }
        supported_protocols(builder.min_protocol, builder.max_protocol, &mut connector)?;

        for cert in &builder.root_certificates {
            connector.cert_store_mut().add_cert((cert.0).0.clone())?;
        }

        Ok(TlsConnector {
            connector: connector.build(),
            use_sni: builder.use_sni,
            accept_invalid_hostnames: builder.accept_invalid_hostnames,
            accept_invalid_certs: builder.accept_invalid_certs,
        })
    }

    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut ssl = self
            .connector
            .configure()?
            .use_server_name_indication(self.use_sni)
            .verify_hostname(!self.accept_invalid_hostnames);
        if self.accept_invalid_certs {
            ssl.set_verify(SslVerifyMode::NONE);
        }

        let s = ssl.connect(domain, stream)?;
        Ok(TlsStream(s))
    }
}

#[derive(Clone)]
pub struct TlsAcceptor(SslAcceptor);

impl TlsAcceptor {
    pub fn new(builder: &TlsAcceptorBuilder) -> Result<TlsAcceptor, Error> {
        let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
        acceptor.set_private_key(&(builder.identity.0).0.pkey)?;
        acceptor.set_certificate(&(builder.identity.0).0.cert)?;
        if let Some(ref chain) = (builder.identity.0).0.chain {
            for cert in chain {
                acceptor.add_extra_chain_cert(cert.to_owned())?;
            }
        }
        supported_protocols(builder.min_protocol, builder.max_protocol, &mut acceptor)?;

        Ok(TlsAcceptor(acceptor.build()))
    }

    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let s = self.0.accept(stream)?;
        Ok(TlsStream(s))
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        match self.0.shutdown() {
            Ok(_) => Ok(()),
            Err(ref e) if e.code() == ssl::ErrorCode::ZERO_RETURN => Ok(()),
            Err(e) => Err(e
                .into_io_error()
                .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))),
        }
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}
<|endoftext|>