<commit_before>use cairo;

use std::f64;
use std::f64::consts::*;

use float_eq_cairo::ApproxEqCairo;
use util::clamp;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LargeArc(pub bool);

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Sweep {
    Negative,
    Positive,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CubicBezierCurve {
    /// The (x, y) coordinates of the first control point.
    pub pt1: (f64, f64),
    /// The (x, y) coordinates of the second control point.
    pub pt2: (f64, f64),
    /// The (x, y) coordinates of the end point of this path segment.
    pub to: (f64, f64),
}

impl CubicBezierCurve {
    fn to_cairo(self, cr: &cairo::Context) {
        let Self { pt1, pt2, to } = self;
        cr.curve_to(pt1.0, pt1.1, pt2.0, pt2.1, to.0, to.1);
    }
}

/// When attempting to compute the center parameterization of the arc,
/// out of range parameters may see an arc omited or treated as a line.
pub enum ArcParameterization {
    /// Center parameterization of the arc.
    CenterParameters {
        /// Center of the ellipse.
        center: (f64, f64),
        /// Radii of the ellipse (corrected).
        radii: (f64, f64),
        /// Angle of the start point.
        theta1: f64,
        /// Delta angle to the end point.
        delta_theta: f64,
    },
    /// Treat the arc as a line to the end point.
    LineTo,
    /// Omit the arc.
    Omit,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct EllipticalArc {
    /// The (x-axis, y-axis) radii for the ellipse.
    pub r: (f64, f64),
    /// The rotation angle in degrees for the ellipse's x-axis
    /// relative to the x-axis of the user coordinate system.
    pub x_axis_rotation: f64,
    /// Flag indicating whether the arc sweep should be
    /// greater than or equal to 180 degrees, or smaller than 180 degrees.
    pub large_arc: LargeArc,
    /// Flag indicating the angular direction in which the arc is drawn.
    pub sweep: Sweep,
    /// The (x, y) coordinates for the start point of this path segment.
    pub from: (f64, f64),
    /// The (x, y) coordinates for the end point of this path segment.
    pub to: (f64, f64),
}

impl EllipticalArc {
    /// Calculates a center parameterization from the endpoint parameterization.
    ///
    /// Radii may be adjusted if there is no solution.
    ///
    /// See Appendix F.6 Elliptical arc implementation notes.
    /// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
    pub(crate) fn center_parameterization(self) -> ArcParameterization {
        let Self {
            r: (mut rx, mut ry),
            x_axis_rotation,
            large_arc,
            sweep,
            from: (x1, y1),
            to: (x2, y2),
        } = self;

        // If the end points are identical, omit the arc segment entirely.
        if x1.approx_eq_cairo(&x2) && y1.approx_eq_cairo(&y2) {
            return ArcParameterization::Omit;
        }

        // Ensure radii are non-zero.
        // Otherwise this arc is treated as a line segment joining the end points.
        //
        // A bit further down we divide by the square of the radii.
        // Check that we won't divide by zero.
        // See http://bugs.debian.org/508443
        if rx * rx < f64::EPSILON || ry * ry < f64::EPSILON {
            return ArcParameterization::LineTo;
        }

        let is_large_arc = large_arc.0;
        let is_positive_sweep = sweep == Sweep::Positive;

        let f = x_axis_rotation * PI / 180.0;
        let sinf = f.sin();
        let cosf = f.cos();

        // Ensure radii are positive.
        rx = rx.abs();
        ry = ry.abs();

        // The equations simplify after a translation which places
        // the origin at the midpoint of the line joining (x1, y1) to (x2, y2),
        // followed by a rotation to line up the coordinate axes
        // with the axes of the ellipse.
        // All transformed coordinates will be written with primes.
        //
        // Compute (x1', y1').
        let mid_x = (x1 - x2) / 2.0;
        let mid_y = (y1 - y2) / 2.0;
        let x1_ = cosf * mid_x + sinf * mid_y;
        let y1_ = -sinf * mid_x + cosf * mid_y;

        // Ensure radii are large enough.
        let lambda = (x1_ / rx).powi(2) + (y1_ / ry).powi(2);
        if lambda > 1.0 {
            // If not, scale up the ellipse uniformly
            // until there is exactly one solution.
            rx *= lambda.sqrt();
            ry *= lambda.sqrt();
        }

        // Compute the transformed center (cx', cy').
        let d = (rx * y1_).powi(2) + (ry * x1_).powi(2);
        if d.approx_eq_cairo(&0.0) {
            return ArcParameterization::Omit;
        }
        let k = {
            let mut k = ((rx * ry).powi(2) / d - 1.0).abs().sqrt();
            if is_positive_sweep == is_large_arc {
                k = -k;
            }
            k
        };
        let cx_ = k * rx * y1_ / ry;
        let cy_ = -k * ry * x1_ / rx;

        // Compute the center (cx, cy).
        let cx = cosf * cx_ - sinf * cy_ + (x1 + x2) / 2.0;
        let cy = sinf * cx_ + cosf * cy_ + (y1 + y2) / 2.0;

        // Compute the start angle θ1.
        let ux = (x1_ - cx_) / rx;
        let uy = (y1_ - cy_) / ry;
        let u_len = (ux * ux + uy * uy).abs().sqrt();
        if u_len.approx_eq_cairo(&0.0) {
            return ArcParameterization::Omit;
        }
        let cos_theta1 = clamp(ux / u_len, -1.0, 1.0);
        let theta1 = {
            let mut theta1 = cos_theta1.acos();
            if uy < 0.0 {
                theta1 = -theta1;
            }
            theta1
        };

        // Compute the total delta angle Δθ.
        let vx = (-x1_ - cx_) / rx;
        let vy = (-y1_ - cy_) / ry;
        let v_len = (vx * vx + vy * vy).abs().sqrt();
        if v_len.approx_eq_cairo(&0.0) {
            return ArcParameterization::Omit;
        }
        let dp_uv = ux * vx + uy * vy;
        let cos_delta_theta = clamp(dp_uv / (u_len * v_len), -1.0, 1.0);
        let delta_theta = {
            let mut delta_theta = cos_delta_theta.acos();
            if ux * vy - uy * vx < 0.0 {
                delta_theta = -delta_theta;
            }
            if is_positive_sweep && delta_theta < 0.0 {
                delta_theta += PI * 2.0;
            } else if !is_positive_sweep && delta_theta > 0.0 {
                delta_theta -= PI * 2.0;
            }
            delta_theta
        };

        ArcParameterization::CenterParameters {
            center: (cx, cy),
            radii: (rx, ry),
            theta1,
            delta_theta,
        }
    }

    fn to_cairo(self, cr: &cairo::Context) {
        match self.center_parameterization() {
            ArcParameterization::CenterParameters {
                center,
                radii,
                theta1,
                delta_theta,
            } => {
                let n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs().ceil() as u32;
                let d_theta = delta_theta / f64::from(n_segs);

                let mut theta = theta1;
                for _ in 0..n_segs {
                    arc_segment(center, radii, self.x_axis_rotation, theta, theta + d_theta)
                        .to_cairo(cr);
                    theta += d_theta;
                }
            }
            ArcParameterization::LineTo => {
                let (x2, y2) = self.to;
                cr.line_to(x2, y2);
            }
            ArcParameterization::Omit => {}
        }
    }
}

/// Turns an arc segment into a cubic bezier curve.
///
/// Takes the center, the radii and the x-axis rotation of the ellipse,
/// the angles of the start and end points,
/// and returns cubic bezier curve parameters.
pub(crate) fn arc_segment(
    c: (f64, f64),
    r: (f64, f64),
    x_axis_rotation: f64,
    th0: f64,
    th1: f64,
) -> CubicBezierCurve {
    let (cx, cy) = c;
    let (rx, ry) = r;
    let f = x_axis_rotation * PI / 180.0;
    let (sinf, cosf) = (f.sin(), f.cos());

    let th_half = 0.5 * (th1 - th0);
    let t = (8.0 / 3.0) * (th_half * 0.5).sin().powi(2) / th_half.sin();
    let x1 = rx * (th0.cos() - t * th0.sin());
    let y1 = ry * (th0.sin() + t * th0.cos());
    let x3 = rx * th1.cos();
    let y3 = ry * th1.sin();
    let x2 = x3 + rx * (t * th1.sin());
    let y2 = y3 + ry * (-t * th1.cos());

    CubicBezierCurve {
        pt1: (cx + cosf * x1 - sinf * y1, cy + sinf * x1 + cosf * y1),
        pt2: (cx + cosf * x2 - sinf * y2, cy + sinf * x2 + cosf * y2),
        to: (cx + cosf * x3 - sinf * y3, cy + sinf * x3 + cosf * y3),
    }
}

#[derive(Debug, PartialEq)]
pub enum PathCommand {
    MoveTo(f64, f64),
    LineTo(f64, f64),
    CurveTo(CubicBezierCurve),
    Arc(EllipticalArc),
    ClosePath,
}

impl PathCommand {
    fn to_cairo(&self, cr: &cairo::Context) {
        match *self {
            PathCommand::MoveTo(x, y) => cr.move_to(x, y),
            PathCommand::LineTo(x, y) => cr.line_to(x, y),
            PathCommand::CurveTo(curve) => curve.to_cairo(cr),
            PathCommand::Arc(arc) => arc.to_cairo(cr),
            PathCommand::ClosePath => cr.close_path(),
        }
    }
}

pub struct PathBuilder {
    path_commands: Vec<PathCommand>,
}

impl Default for PathBuilder {
    fn default() -> PathBuilder {
        PathBuilder {
            path_commands: Vec::new(),
        }
    }
}

impl PathBuilder {
    pub fn new() -> PathBuilder {
        PathBuilder::default()
    }

    pub fn move_to(&mut self, x: f64, y: f64) {
        self.path_commands.push(PathCommand::MoveTo(x, y));
    }

    pub fn line_to(&mut self, x: f64, y: f64) {
        self.path_commands.push(PathCommand::LineTo(x, y));
    }

    pub fn curve_to(&mut self, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
        let curve = CubicBezierCurve {
            pt1: (x2, y2),
            pt2: (x3, y3),
            to: (x4, y4),
        };
        self.path_commands.push(PathCommand::CurveTo(curve));
    }

    pub fn arc(
        &mut self,
        x1: f64,
        y1: f64,
        rx: f64,
        ry: f64,
        x_axis_rotation: f64,
        large_arc: LargeArc,
        sweep: Sweep,
        x2: f64,
        y2: f64,
    ) {
        let arc = EllipticalArc {
            r: (rx, ry),
            x_axis_rotation,
            large_arc,
            sweep,
            from: (x1, y1),
            to: (x2, y2),
        };
        self.path_commands.push(PathCommand::Arc(arc));
    }

    pub fn close_path(&mut self) {
        self.path_commands.push(PathCommand::ClosePath);
    }

    pub fn get_path_commands(&self) -> &[PathCommand] {
        &self.path_commands
    }

    pub fn to_cairo(&self, cr: &cairo::Context) {
        for s in &self.path_commands {
            s.to_cairo(cr);
        }
    }
}

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

    #[test]
    fn survives_degenerate_arcs() {
        let mut builder = PathBuilder::new();
        builder.move_to(0.0, 0.0);
        // Deliberately close to 0 to try to trigger division by 0.
        builder.arc(
            0.0,
            0.0,
            f64::EPSILON,
            f64::EPSILON,
            0.0,
            LargeArc(true),
            Sweep::Positive,
            1.0,
            1.0,
        );
    }
}
<commit_msg>Use f64::sin_cos where applicable<commit_after>use cairo;

use std::f64;
use std::f64::consts::*;

use float_eq_cairo::ApproxEqCairo;
use util::clamp;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LargeArc(pub bool);

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Sweep {
    Negative,
    Positive,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CubicBezierCurve {
    /// The (x, y) coordinates of the first control point.
    pub pt1: (f64, f64),
    /// The (x, y) coordinates of the second control point.
    pub pt2: (f64, f64),
    /// The (x, y) coordinates of the end point of this path segment.
    pub to: (f64, f64),
}

impl CubicBezierCurve {
    fn to_cairo(self, cr: &cairo::Context) {
        let Self { pt1, pt2, to } = self;
        cr.curve_to(pt1.0, pt1.1, pt2.0, pt2.1, to.0, to.1);
    }
}

/// When attempting to compute the center parameterization of the arc,
/// out of range parameters may see an arc omited or treated as a line.
pub enum ArcParameterization {
    /// Center parameterization of the arc.
    CenterParameters {
        /// Center of the ellipse.
        center: (f64, f64),
        /// Radii of the ellipse (corrected).
        radii: (f64, f64),
        /// Angle of the start point.
        theta1: f64,
        /// Delta angle to the end point.
        delta_theta: f64,
    },
    /// Treat the arc as a line to the end point.
    LineTo,
    /// Omit the arc.
    Omit,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct EllipticalArc {
    /// The (x-axis, y-axis) radii for the ellipse.
    pub r: (f64, f64),
    /// The rotation angle in degrees for the ellipse's x-axis
    /// relative to the x-axis of the user coordinate system.
    pub x_axis_rotation: f64,
    /// Flag indicating whether the arc sweep should be
    /// greater than or equal to 180 degrees, or smaller than 180 degrees.
    pub large_arc: LargeArc,
    /// Flag indicating the angular direction in which the arc is drawn.
    pub sweep: Sweep,
    /// The (x, y) coordinates for the start point of this path segment.
    pub from: (f64, f64),
    /// The (x, y) coordinates for the end point of this path segment.
    pub to: (f64, f64),
}

impl EllipticalArc {
    /// Calculates a center parameterization from the endpoint parameterization.
    ///
    /// Radii may be adjusted if there is no solution.
    ///
    /// See Appendix F.6 Elliptical arc implementation notes.
    /// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
    pub(crate) fn center_parameterization(self) -> ArcParameterization {
        let Self {
            r: (mut rx, mut ry),
            x_axis_rotation,
            large_arc,
            sweep,
            from: (x1, y1),
            to: (x2, y2),
        } = self;

        // If the end points are identical, omit the arc segment entirely.
        if x1.approx_eq_cairo(&x2) && y1.approx_eq_cairo(&y2) {
            return ArcParameterization::Omit;
        }

        // Ensure radii are non-zero.
        // Otherwise this arc is treated as a line segment joining the end points.
        //
        // A bit further down we divide by the square of the radii.
        // Check that we won't divide by zero.
        // See http://bugs.debian.org/508443
        if rx * rx < f64::EPSILON || ry * ry < f64::EPSILON {
            return ArcParameterization::LineTo;
        }

        let is_large_arc = large_arc.0;
        let is_positive_sweep = sweep == Sweep::Positive;

        let phi = x_axis_rotation * PI / 180.0;
        let (sin_phi, cos_phi) = phi.sin_cos();

        // Ensure radii are positive.
        rx = rx.abs();
        ry = ry.abs();

        // The equations simplify after a translation which places
        // the origin at the midpoint of the line joining (x1, y1) to (x2, y2),
        // followed by a rotation to line up the coordinate axes
        // with the axes of the ellipse.
        // All transformed coordinates will be written with primes.
        //
        // Compute (x1', y1').
        let mid_x = (x1 - x2) / 2.0;
        let mid_y = (y1 - y2) / 2.0;
        let x1_ = cos_phi * mid_x + sin_phi * mid_y;
        let y1_ = -sin_phi * mid_x + cos_phi * mid_y;

        // Ensure radii are large enough.
        let lambda = (x1_ / rx).powi(2) + (y1_ / ry).powi(2);
        if lambda > 1.0 {
            // If not, scale up the ellipse uniformly
            // until there is exactly one solution.
            rx *= lambda.sqrt();
            ry *= lambda.sqrt();
        }

        // Compute the transformed center (cx', cy').
        let d = (rx * y1_).powi(2) + (ry * x1_).powi(2);
        if d.approx_eq_cairo(&0.0) {
            return ArcParameterization::Omit;
        }
        let k = {
            let mut k = ((rx * ry).powi(2) / d - 1.0).abs().sqrt();
            if is_positive_sweep == is_large_arc {
                k = -k;
            }
            k
        };
        let cx_ = k * rx * y1_ / ry;
        let cy_ = -k * ry * x1_ / rx;

        // Compute the center (cx, cy).
        let cx = cos_phi * cx_ - sin_phi * cy_ + (x1 + x2) / 2.0;
        let cy = sin_phi * cx_ + cos_phi * cy_ + (y1 + y2) / 2.0;

        // Compute the start angle θ1.
        let ux = (x1_ - cx_) / rx;
        let uy = (y1_ - cy_) / ry;
        let u_len = (ux * ux + uy * uy).abs().sqrt();
        if u_len.approx_eq_cairo(&0.0) {
            return ArcParameterization::Omit;
        }
        let cos_theta1 = clamp(ux / u_len, -1.0, 1.0);
        let theta1 = {
            let mut theta1 = cos_theta1.acos();
            if uy < 0.0 {
                theta1 = -theta1;
            }
            theta1
        };

        // Compute the total delta angle Δθ.
        let vx = (-x1_ - cx_) / rx;
        let vy = (-y1_ - cy_) / ry;
        let v_len = (vx * vx + vy * vy).abs().sqrt();
        if v_len.approx_eq_cairo(&0.0) {
            return ArcParameterization::Omit;
        }
        let dp_uv = ux * vx + uy * vy;
        let cos_delta_theta = clamp(dp_uv / (u_len * v_len), -1.0, 1.0);
        let delta_theta = {
            let mut delta_theta = cos_delta_theta.acos();
            if ux * vy - uy * vx < 0.0 {
                delta_theta = -delta_theta;
            }
            if is_positive_sweep && delta_theta < 0.0 {
                delta_theta += PI * 2.0;
            } else if !is_positive_sweep && delta_theta > 0.0 {
                delta_theta -= PI * 2.0;
            }
            delta_theta
        };

        ArcParameterization::CenterParameters {
            center: (cx, cy),
            radii: (rx, ry),
            theta1,
            delta_theta,
        }
    }

    fn to_cairo(self, cr: &cairo::Context) {
        match self.center_parameterization() {
            ArcParameterization::CenterParameters {
                center,
                radii,
                theta1,
                delta_theta,
            } => {
                let n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs().ceil() as u32;
                let d_theta = delta_theta / f64::from(n_segs);

                let mut theta = theta1;
                for _ in 0..n_segs {
                    arc_segment(center, radii, self.x_axis_rotation, theta, theta + d_theta)
                        .to_cairo(cr);
                    theta += d_theta;
                }
            }
            ArcParameterization::LineTo => {
                let (x2, y2) = self.to;
                cr.line_to(x2, y2);
            }
            ArcParameterization::Omit => {}
        }
    }
}

/// Turns an arc segment into a cubic bezier curve.
///
/// Takes the center, the radii and the x-axis rotation of the ellipse,
/// the angles of the start and end points,
/// and returns cubic bezier curve parameters.
pub(crate) fn arc_segment(
    c: (f64, f64),
    r: (f64, f64),
    x_axis_rotation: f64,
    th0: f64,
    th1: f64,
) -> CubicBezierCurve {
    let (cx, cy) = c;
    let (rx, ry) = r;
    let phi = x_axis_rotation * PI / 180.0;
    let (sin_phi, cos_phi) = phi.sin_cos();
    let (sin_th0, cos_th0) = th0.sin_cos();
    let (sin_th1, cos_th1) = th1.sin_cos();

    let th_half = 0.5 * (th1 - th0);
    let t = (8.0 / 3.0) * (th_half * 0.5).sin().powi(2) / th_half.sin();
    let x1 = rx * (cos_th0 - t * sin_th0);
    let y1 = ry * (sin_th0 + t * cos_th0);
    let x3 = rx * cos_th1;
    let y3 = ry * sin_th1;
    let x2 = x3 + rx * (t * sin_th1);
    let y2 = y3 + ry * (-t * cos_th1);

    CubicBezierCurve {
        pt1: (
            cx + cos_phi * x1 - sin_phi * y1,
            cy + sin_phi * x1 + cos_phi * y1,
        ),
        pt2: (
            cx + cos_phi * x2 - sin_phi * y2,
            cy + sin_phi * x2 + cos_phi * y2,
        ),
        to: (
            cx + cos_phi * x3 - sin_phi * y3,
            cy + sin_phi * x3 + cos_phi * y3,
        ),
    }
}

#[derive(Debug, PartialEq)]
pub enum PathCommand {
    MoveTo(f64, f64),
    LineTo(f64, f64),
    CurveTo(CubicBezierCurve),
    Arc(EllipticalArc),
    ClosePath,
}

impl PathCommand {
    fn to_cairo(&self, cr: &cairo::Context) {
        match *self {
            PathCommand::MoveTo(x, y) => cr.move_to(x, y),
            PathCommand::LineTo(x, y) => cr.line_to(x, y),
            PathCommand::CurveTo(curve) => curve.to_cairo(cr),
            PathCommand::Arc(arc) => arc.to_cairo(cr),
            PathCommand::ClosePath => cr.close_path(),
        }
    }
}

pub struct PathBuilder {
    path_commands: Vec<PathCommand>,
}

impl Default for PathBuilder {
    fn default() -> PathBuilder {
        PathBuilder {
            path_commands: Vec::new(),
        }
    }
}

impl PathBuilder {
    pub fn new() -> PathBuilder {
        PathBuilder::default()
    }

    pub fn move_to(&mut self, x: f64, y: f64) {
        self.path_commands.push(PathCommand::MoveTo(x, y));
    }

    pub fn line_to(&mut self, x: f64, y: f64) {
        self.path_commands.push(PathCommand::LineTo(x, y));
    }

    pub fn curve_to(&mut self, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
        let curve = CubicBezierCurve {
            pt1: (x2, y2),
            pt2: (x3, y3),
            to: (x4, y4),
        };
        self.path_commands.push(PathCommand::CurveTo(curve));
    }

    pub fn arc(
        &mut self,
        x1: f64,
        y1: f64,
        rx: f64,
        ry: f64,
        x_axis_rotation: f64,
        large_arc: LargeArc,
        sweep: Sweep,
        x2: f64,
        y2: f64,
    ) {
        let arc = EllipticalArc {
            r: (rx, ry),
            x_axis_rotation,
            large_arc,
            sweep,
            from: (x1, y1),
            to: (x2, y2),
        };
        self.path_commands.push(PathCommand::Arc(arc));
    }

    pub fn close_path(&mut self) {
        self.path_commands.push(PathCommand::ClosePath);
    }

    pub fn get_path_commands(&self) -> &[PathCommand] {
        &self.path_commands
    }

    pub fn to_cairo(&self, cr: &cairo::Context) {
        for s in &self.path_commands {
            s.to_cairo(cr);
        }
    }
}

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

    #[test]
    fn survives_degenerate_arcs() {
        let mut builder = PathBuilder::new();
        builder.move_to(0.0, 0.0);
        // Deliberately close to 0 to try to trigger division by 0.
        builder.arc(
            0.0,
            0.0,
            f64::EPSILON,
            f64::EPSILON,
            0.0,
            LargeArc(true),
            Sweep::Positive,
            1.0,
            1.0,
        );
    }
}
<|endoftext|>


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

#![deny(unused_variables)]
#![deny(unused_assignments)]
#![allow(dead_code, non_camel_case_types, trivial_numeric_casts)]

fn f1(x: isize) {
    //~^ ERROR unused variable: `x`
}

fn f1b(x: &mut isize) {
    //~^ ERROR unused variable: `x`
}

#[allow(unused_variables)]
fn f1c(x: isize) {}

fn f1d() {
    let x: isize;
    //~^ ERROR unused variable: `x`
}

fn f2() {
    let x = 3;
    //~^ ERROR unused variable: `x`
}

fn f3() {
    let mut x = 3;
    //~^ ERROR variable `x` is assigned to, but never used
    x += 4;
    //~^ ERROR value assigned to `x` is never read
}

fn f3b() {
    let mut z = 3;
    //~^ ERROR variable `z` is assigned to, but never used
    loop {
        z += 4;
    }
}

#[allow(unused_variables)]
fn f3c() {
    let mut z = 3;
    loop { z += 4; }
}

#[allow(unused_variables)]
#[allow(unused_assignments)]
fn f3d() {
    let mut x = 3;
    x += 4;
}

fn f4() {
    match Some(3) {
      Some(i) => {
        //~^ ERROR unused variable: `i`
      }
      None => {}
    }
}

enum tri {
    a(isize), b(isize), c(isize)
}

fn f4b() -> isize {
    match tri::a(3) {
      tri::a(i) | tri::b(i) | tri::c(i) => {
        i
      }
    }
}

fn f5a() {
    for x in 1..10 { }
    //~^ ERROR unused variable: `x`
}

fn f5b() {
    for (x, _) in [1, 2, 3].iter().enumerate() { }
    //~^ ERROR unused variable: `x`
}

fn f5c() {
    for (_, x) in [1, 2, 3].iter().enumerate() {
    //~^ ERROR unused variable: `x`
        continue;
        drop(*x as i32); //~ WARNING unreachable statement
    }
}

fn main() {
}
<commit_msg>Add liveness test for unused_assignments for tricky lhs<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(unused_variables)]
#![deny(unused_assignments)]
#![allow(dead_code, non_camel_case_types, trivial_numeric_casts)]

use std::ops::AddAssign;

fn f1(x: isize) {
    //~^ ERROR unused variable: `x`
}

fn f1b(x: &mut isize) {
    //~^ ERROR unused variable: `x`
}

#[allow(unused_variables)]
fn f1c(x: isize) {}

fn f1d() {
    let x: isize;
    //~^ ERROR unused variable: `x`
}

fn f2() {
    let x = 3;
    //~^ ERROR unused variable: `x`
}

fn f3() {
    let mut x = 3;
    //~^ ERROR variable `x` is assigned to, but never used
    x += 4;
    //~^ ERROR value assigned to `x` is never read
}

fn f3b() {
    let mut z = 3;
    //~^ ERROR variable `z` is assigned to, but never used
    loop {
        z += 4;
    }
}

#[allow(unused_variables)]
fn f3c() {
    let mut z = 3;
    loop { z += 4; }
}

#[allow(unused_variables)]
#[allow(unused_assignments)]
fn f3d() {
    let mut x = 3;
    x += 4;
}

fn f4() {
    match Some(3) {
      Some(i) => {
        //~^ ERROR unused variable: `i`
      }
      None => {}
    }
}

enum tri {
    a(isize), b(isize), c(isize)
}

fn f4b() -> isize {
    match tri::a(3) {
      tri::a(i) | tri::b(i) | tri::c(i) => {
        i
      }
    }
}

fn f5a() {
    for x in 1..10 { }
    //~^ ERROR unused variable: `x`
}

fn f5b() {
    for (x, _) in [1, 2, 3].iter().enumerate() { }
    //~^ ERROR unused variable: `x`
}

fn f5c() {
    for (_, x) in [1, 2, 3].iter().enumerate() {
    //~^ ERROR unused variable: `x`
        continue;
        drop(*x as i32); //~ WARNING unreachable statement
    }
}

struct View<'a>(&'a mut [i32]);

impl<'a> AddAssign<i32> for View<'a> {
    fn add_assign(&mut self, rhs: i32) {
        for lhs in self.0.iter_mut() {
            *lhs += rhs;
        }
    }
}

fn f6() {
    let mut array = [1, 2, 3];
    let mut v = View(&mut array);

    // ensure an error shows up for x even if lhs of an overloaded add assign

    let x;
    //~^ ERROR variable `x` is assigned to, but never used

    *({
        x = 0;  //~ ERROR value assigned to `x` is never read
        &mut v
    }) += 1;
}

fn main() {
}
<|endoftext|>


<commit_before>use alloc::arc::{Arc, Weak};
use alloc::boxed::Box;

use collections::vec_deque::VecDeque;

use schemes::{Result, Resource, Url};

use scheduler::context::context_switch;

use sync::Intex;

use syscall::{SysError, EPIPE};

/// Read side of a pipe
pub struct PipeRead {
    vec: Arc<Intex<VecDeque<u8>>>,
    eof_toggle: bool,
}

impl PipeRead {
    pub fn new() -> Self {
        PipeRead {
            vec: Arc::new(Intex::new(VecDeque::new())),
            eof_toggle: false,
        }
    }
}

impl Resource for PipeRead {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box PipeRead {
            vec: self.vec.clone(),
            eof_toggle: self.eof_toggle,
        })
    }

    fn url(&self) -> Url {
        return Url::from_str("pipe:r");
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if self.eof_toggle {
            debugln!("EOF");
            self.eof_toggle = false;
            return Ok(0);
        }

        loop {
            {
                let mut vec = self.vec.lock();
                if vec.is_empty() {
                    if Arc::weak_count(&self.vec) == 0 {
                        return Ok(0);
                    }
                } else {
                    debugln!("Reading {}", vec.len());
                    let mut i = 0;
                    while i < buf.len() {
                        match vec.pop_front() {
                            Some(b) => {
                                buf[i] = b;
                                i += 1;
                            },
                            None => break
                        }
                    }
                    self.eof_toggle = true;
                    return Ok(i);
                }
            }

            unsafe { context_switch(false) };
        }
    }
}

/// Read side of a pipe
pub struct PipeWrite {
    vec: Weak<Intex<VecDeque<u8>>>,
}

impl PipeWrite {
    pub fn new(read: &PipeRead) -> Self {
        PipeWrite {
            vec: Arc::downgrade(&read.vec),
        }
    }
}

impl Resource for PipeWrite {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box PipeWrite {
            vec: self.vec.clone(),
        })
    }

    fn url(&self) -> Url {
        return Url::from_str("pipe:w");
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        match self.vec.upgrade() {
            Some(vec_intex) => {
                let mut vec = vec_intex.lock();
                let mut i = 0;
                while i < buf.len() {
                    vec.push_back(buf[i]);
                    i += 1;
                }
                Ok(i)
            },
            None => Err(SysError::new(EPIPE))
        }
    }
}
<commit_msg>Remove debugging from pipe<commit_after>use alloc::arc::{Arc, Weak};
use alloc::boxed::Box;

use collections::vec_deque::VecDeque;

use schemes::{Result, Resource, Url};

use scheduler::context::context_switch;

use sync::Intex;

use syscall::{SysError, EPIPE};

/// Read side of a pipe
pub struct PipeRead {
    vec: Arc<Intex<VecDeque<u8>>>,
    eof_toggle: bool,
}

impl PipeRead {
    pub fn new() -> Self {
        PipeRead {
            vec: Arc::new(Intex::new(VecDeque::new())),
            eof_toggle: false,
        }
    }
}

impl Resource for PipeRead {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box PipeRead {
            vec: self.vec.clone(),
            eof_toggle: self.eof_toggle,
        })
    }

    fn url(&self) -> Url {
        return Url::from_str("pipe:r");
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if self.eof_toggle {
            self.eof_toggle = false;
            return Ok(0);
        }

        loop {
            {
                let mut vec = self.vec.lock();
                if vec.is_empty() {
                    if Arc::weak_count(&self.vec) == 0 {
                        return Ok(0);
                    }
                } else {
                    let mut i = 0;
                    while i < buf.len() {
                        match vec.pop_front() {
                            Some(b) => {
                                buf[i] = b;
                                i += 1;
                            },
                            None => break
                        }
                    }
                    self.eof_toggle = true;
                    return Ok(i);
                }
            }

            unsafe { context_switch(false) };
        }
    }
}

/// Read side of a pipe
pub struct PipeWrite {
    vec: Weak<Intex<VecDeque<u8>>>,
}

impl PipeWrite {
    pub fn new(read: &PipeRead) -> Self {
        PipeWrite {
            vec: Arc::downgrade(&read.vec),
        }
    }
}

impl Resource for PipeWrite {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box PipeWrite {
            vec: self.vec.clone(),
        })
    }

    fn url(&self) -> Url {
        return Url::from_str("pipe:w");
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        match self.vec.upgrade() {
            Some(vec_intex) => {
                let mut vec = vec_intex.lock();
                let mut i = 0;
                while i < buf.len() {
                    vec.push_back(buf[i]);
                    i += 1;
                }
                Ok(i)
            },
            None => Err(SysError::new(EPIPE))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error::Error;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;

use buffer::Buffer;
use command_buffer::CommandBuffer;
use command_buffer::cb::CommandBufferBuild;
use command_buffer::pool::AllocatedCommandBuffer;
use command_buffer::pool::CommandPool;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use framebuffer::EmptySinglePassRenderPassDesc;
use framebuffer::Framebuffer;
use framebuffer::FramebufferAbstract;
use framebuffer::RenderPass;
use framebuffer::RenderPassAbstract;
use framebuffer::Subpass;
use image::Image;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::GpuFuture;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Determines the kind of command buffer that we want to create.
#[derive(Debug, Clone)]
pub enum Kind<R, F> {
    /// A primary command buffer can execute all commands and can call secondary command buffers.
    Primary,

    /// A secondary command buffer can execute all dispatch and transfer operations, but not
    /// drawing operations.
    Secondary,

    /// A secondary command buffer within a render pass can only call draw operations that can
    /// be executed from within a specific subpass.
    SecondaryRenderPass {
        /// Which subpass this secondary command buffer can be called from.
        subpass: Subpass<R>,

        /// The framebuffer object that will be used when calling the command buffer.
        /// This parameter is optional and is an optimization hint for the implementation.
        framebuffer: Option<F>,
    },
}

impl Kind<RenderPass<EmptySinglePassRenderPassDesc>, Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>> {
    /// Equivalent to `Kind::Primary`.
    ///
    /// > **Note**: If you use `let kind = Kind::Primary;` in your code, you will probably get a
    /// > compilation error because the Rust compiler couldn't determine the template parameters
    /// > of `Kind`. To solve that problem in an easy way you can use this function instead.
    #[inline]
    pub fn primary() -> Kind<RenderPass<EmptySinglePassRenderPassDesc>, Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>> {
        Kind::Primary
    }
}

/// Flags to pass when creating a command buffer.
///
/// The safest option is `SimultaneousUse`, but it may be slower than the other two.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Flags {
    /// The command buffer can be used multiple times, but must not execute more than once
    /// simultaneously.
    None,

    /// The command buffer can be executed multiple times in parallel.
    SimultaneousUse,

    /// The command buffer can only be submitted once. Any further submit is forbidden.
    OneTimeSubmit,
}

/// Command buffer being built.
///
/// You can add commands to an `UnsafeCommandBufferBuilder` by using the `AddCommand` trait.
/// The `AddCommand<&Cmd>` trait is implemented on the `UnsafeCommandBufferBuilder` for any `Cmd`
/// that is a raw Vulkan command.
///
/// When you are finished adding commands, you can use the `CommandBufferBuild` trait to turn this
/// builder into an `UnsafeCommandBuffer`.
pub struct UnsafeCommandBufferBuilder<P> where P: CommandPool {
    // The Vulkan command buffer. Will be 0 if `build()` has been called.
    cmd: vk::CommandBuffer,

    // Device that owns the command buffer.
    device: Arc<Device>,

    // Pool that owns the command buffer.
    pool: Option<P>,

    // Flags that were used at creation.
    flags: Flags,

    // True if we are a secondary command buffer.
    secondary_cb: bool,
}

impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
    /// Creates a new builder.
    ///
    /// # Safety
    ///
    /// Creating and destroying an unsafe command buffer is not unsafe per se, but the commands
    /// that you add to it are unchecked, do not have any synchronization, and are not kept alive.
    ///
    /// In other words, it is your job to make sure that the commands you add are valid, that they
    /// don't use resources that have been destroyed, and that they do not introduce any race
    /// condition.
    ///
    /// > **Note**: Some checks are still made with `debug_assert!`. Do not expect to be able to
    /// > submit invalid commands.
    pub unsafe fn new<R, F>(pool: P, kind: Kind<R, F>, flags: Flags)
                            -> Result<UnsafeCommandBufferBuilder<P>, OomError>
        where R: RenderPassAbstract, F: FramebufferAbstract
    {
        let secondary = match kind {
            Kind::Primary => false,
            Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
        };

        let cmd = try!(pool.alloc(secondary, 1)).next().unwrap();

        match UnsafeCommandBufferBuilder::already_allocated(pool, cmd, kind, flags) {
            Ok(cmd) => Ok(cmd),
            Err(err) => {
                // FIXME: uncomment this and solve the fact that `pool` has been moved
                //unsafe { pool.free(secondary, Some(cmd.into()).into_iter()) };
                Err(err)
            },
        }
    }

    /// Creates a new command buffer builder from an already-allocated command buffer.
    ///
    /// # Safety
    ///
    /// See the `new` method.
    ///
    /// The allocated command buffer must belong to the pool and must not be used anywhere else
    /// in the code for the duration of this command buffer.
    ///
    pub unsafe fn already_allocated<R, F>(pool: P, cmd: AllocatedCommandBuffer,
                                          kind: Kind<R, F>, flags: Flags)
                                          -> Result<UnsafeCommandBufferBuilder<P>, OomError>
        where R: RenderPassAbstract, F: FramebufferAbstract
    {
        let device = pool.device().clone();
        let vk = device.pointers();
        let cmd = cmd.internal_object();

        let vk_flags = {
            let a = match flags {
                Flags::None => 0,
                Flags::SimultaneousUse => vk::COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
                Flags::OneTimeSubmit => vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
            };

            let b = match kind {
                Kind::Primary | Kind::Secondary => 0,
                Kind::SecondaryRenderPass { .. } => {
                    vk::COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
                },
            };

            a | b
        };

        let (rp, sp) = if let Kind::SecondaryRenderPass { ref subpass, .. } = kind {
            (subpass.render_pass().inner().internal_object(), subpass.index())
        } else {
            (0, 0)
        };

        let framebuffer = if let Kind::SecondaryRenderPass { ref subpass, framebuffer: Some(ref framebuffer) } = kind {
            // TODO: restore check
            //assert!(framebuffer.is_compatible_with(subpass.render_pass()));     // TODO: proper error
            FramebufferAbstract::inner(&framebuffer).internal_object()
        } else {
            0
        };

        let inheritance = vk::CommandBufferInheritanceInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
            pNext: ptr::null(),
            renderPass: rp,
            subpass: sp,
            framebuffer: framebuffer,
            occlusionQueryEnable: 0,            // TODO:
            queryFlags: 0,          // TODO:
            pipelineStatistics: 0,          // TODO:
        };

        let infos = vk::CommandBufferBeginInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
            pNext: ptr::null(),
            flags: vk_flags,
            pInheritanceInfo: &inheritance,
        };

        try!(check_errors(vk.BeginCommandBuffer(cmd, &infos)));

        Ok(UnsafeCommandBufferBuilder {
            device: device.clone(),
            pool: Some(pool),
            cmd: cmd,
            flags: flags,
            secondary_cb: match kind {
                Kind::Primary => false,
                Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
            },
        })
    }
}

unsafe impl<P> DeviceOwned for UnsafeCommandBufferBuilder<P> where P: CommandPool {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl<P> VulkanObject for UnsafeCommandBufferBuilder<P> where P: CommandPool {
    type Object = vk::CommandBuffer;

    #[inline]
    fn internal_object(&self) -> vk::CommandBuffer {
        self.cmd
    }
}

impl<P> Drop for UnsafeCommandBufferBuilder<P> where P: CommandPool {
    #[inline]
    fn drop(&mut self) {
        //unsafe {
            if self.cmd == 0 {
                return;
            }

            // FIXME: vk.FreeCommandBuffers()
        //}
    }
}

unsafe impl<P> CommandBufferBuild for UnsafeCommandBufferBuilder<P>
    where P: CommandPool
{
    type Out = UnsafeCommandBuffer<P>;
    type Err = OomError;

    #[inline]
    fn build(mut self) -> Result<Self::Out, OomError> {
        unsafe {
            debug_assert_ne!(self.cmd, 0);
            let cmd = self.cmd;
            let vk = self.device.pointers();
            try!(check_errors(vk.EndCommandBuffer(cmd)));
            self.cmd = 0;       // Prevents the `Drop` impl of the builder from destroying the cb.

            Ok(UnsafeCommandBuffer {
                cmd: cmd,
                device: self.device.clone(),
                pool: self.pool.take().unwrap().finish(),
                flags: self.flags,
                already_submitted: AtomicBool::new(false),
            })
        }
    }
}

/// Command buffer that has been built.
///
/// Doesn't perform any synchronization and doesn't keep the object it uses alive.
pub struct UnsafeCommandBuffer<P> where P: CommandPool {
    // The Vulkan command buffer.
    cmd: vk::CommandBuffer,

    // Device that owns the command buffer.
    device: Arc<Device>,

    // Pool that owns the command buffer.
    pool: P::Finished,

    // Flags that were used at creation.
    flags: Flags,

    // True if the command buffer has always been submitted once. Only relevant if `flags` is
    // `OneTimeSubmit`.
    already_submitted: AtomicBool,
}

unsafe impl<P> CommandBuffer for UnsafeCommandBuffer<P> where P: CommandPool {
    type Pool = P;

    #[inline]
    fn inner(&self) -> &UnsafeCommandBuffer<P> {
        self
    }

    #[inline]
    fn submit_check(&self, _: &GpuFuture, _: &Queue) -> Result<(), Box<Error>> {
        // Not our job to check.
        Ok(())
    }

    #[inline]
    fn check_buffer_access(&self, buffer: &Buffer, exclusive: bool, queue: &Queue)
                           -> Result<Option<(PipelineStages, AccessFlagBits)>, ()>
    {
        Err(())
    }

    #[inline]
    fn check_image_access(&self, image: &Image, exclusive: bool, queue: &Queue)
                          -> Result<Option<(PipelineStages, AccessFlagBits)>, ()>
    {
        Err(())
    }
}

unsafe impl<P> DeviceOwned for UnsafeCommandBuffer<P> where P: CommandPool {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl<P> VulkanObject for UnsafeCommandBuffer<P> where P: CommandPool {
    type Object = vk::CommandBuffer;

    #[inline]
    fn internal_object(&self) -> vk::CommandBuffer {
        self.cmd
    }
}

impl<P> Drop for UnsafeCommandBuffer<P> where P: CommandPool {
    #[inline]
    fn drop(&mut self) {
        //unsafe {
            // FIXME: vk.FreeCommandBuffers()
        //}
    }
}
<commit_msg>fixing memory leak in command buffers - Drop will now release to pools for reuse<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error::Error;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;

use buffer::Buffer;
use command_buffer::CommandBuffer;
use command_buffer::cb::CommandBufferBuild;
use command_buffer::pool::AllocatedCommandBuffer;
use command_buffer::pool::CommandPool;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use framebuffer::EmptySinglePassRenderPassDesc;
use framebuffer::Framebuffer;
use framebuffer::FramebufferAbstract;
use framebuffer::RenderPass;
use framebuffer::RenderPassAbstract;
use framebuffer::Subpass;
use image::Image;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::GpuFuture;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Determines the kind of command buffer that we want to create.
#[derive(Debug, Clone)]
pub enum Kind<R, F> {
    /// A primary command buffer can execute all commands and can call secondary command buffers.
    Primary,

    /// A secondary command buffer can execute all dispatch and transfer operations, but not
    /// drawing operations.
    Secondary,

    /// A secondary command buffer within a render pass can only call draw operations that can
    /// be executed from within a specific subpass.
    SecondaryRenderPass {
        /// Which subpass this secondary command buffer can be called from.
        subpass: Subpass<R>,

        /// The framebuffer object that will be used when calling the command buffer.
        /// This parameter is optional and is an optimization hint for the implementation.
        framebuffer: Option<F>,
    },
}

impl Kind<RenderPass<EmptySinglePassRenderPassDesc>, Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>> {
    /// Equivalent to `Kind::Primary`.
    ///
    /// > **Note**: If you use `let kind = Kind::Primary;` in your code, you will probably get a
    /// > compilation error because the Rust compiler couldn't determine the template parameters
    /// > of `Kind`. To solve that problem in an easy way you can use this function instead.
    #[inline]
    pub fn primary() -> Kind<RenderPass<EmptySinglePassRenderPassDesc>, Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>> {
        Kind::Primary
    }
}

/// Flags to pass when creating a command buffer.
///
/// The safest option is `SimultaneousUse`, but it may be slower than the other two.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Flags {
    /// The command buffer can be used multiple times, but must not execute more than once
    /// simultaneously.
    None,

    /// The command buffer can be executed multiple times in parallel.
    SimultaneousUse,

    /// The command buffer can only be submitted once. Any further submit is forbidden.
    OneTimeSubmit,
}

/// Command buffer being built.
///
/// You can add commands to an `UnsafeCommandBufferBuilder` by using the `AddCommand` trait.
/// The `AddCommand<&Cmd>` trait is implemented on the `UnsafeCommandBufferBuilder` for any `Cmd`
/// that is a raw Vulkan command.
///
/// When you are finished adding commands, you can use the `CommandBufferBuild` trait to turn this
/// builder into an `UnsafeCommandBuffer`.
pub struct UnsafeCommandBufferBuilder<P> where P: CommandPool {
    // The Vulkan command buffer. Will be 0 if `build()` has been called.
    cmd: vk::CommandBuffer,

    // Device that owns the command buffer.
    device: Arc<Device>,

    // Pool that owns the command buffer.
    pool: Option<P>,

    // Flags that were used at creation.
    flags: Flags,

    // True if we are a secondary command buffer.
    secondary_cb: bool,
}

impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
    /// Creates a new builder.
    ///
    /// # Safety
    ///
    /// Creating and destroying an unsafe command buffer is not unsafe per se, but the commands
    /// that you add to it are unchecked, do not have any synchronization, and are not kept alive.
    ///
    /// In other words, it is your job to make sure that the commands you add are valid, that they
    /// don't use resources that have been destroyed, and that they do not introduce any race
    /// condition.
    ///
    /// > **Note**: Some checks are still made with `debug_assert!`. Do not expect to be able to
    /// > submit invalid commands.
    pub unsafe fn new<R, F>(pool: P, kind: Kind<R, F>, flags: Flags)
                            -> Result<UnsafeCommandBufferBuilder<P>, OomError>
        where R: RenderPassAbstract, F: FramebufferAbstract
    {
        let secondary = match kind {
            Kind::Primary => false,
            Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
        };

        let cmd = try!(pool.alloc(secondary, 1)).next().unwrap();

        match UnsafeCommandBufferBuilder::already_allocated(pool, cmd, kind, flags) {
            Ok(cmd) => Ok(cmd),
            Err(err) => {
                // FIXME: uncomment this and solve the fact that `pool` has been moved
                //unsafe { pool.free(secondary, Some(cmd.into()).into_iter()) };
                Err(err)
            },
        }
    }

    /// Creates a new command buffer builder from an already-allocated command buffer.
    ///
    /// # Safety
    ///
    /// See the `new` method.
    ///
    /// The allocated command buffer must belong to the pool and must not be used anywhere else
    /// in the code for the duration of this command buffer.
    ///
    pub unsafe fn already_allocated<R, F>(pool: P, cmd: AllocatedCommandBuffer,
                                          kind: Kind<R, F>, flags: Flags)
                                          -> Result<UnsafeCommandBufferBuilder<P>, OomError>
        where R: RenderPassAbstract, F: FramebufferAbstract
    {
        let device = pool.device().clone();
        let vk = device.pointers();
        let cmd = cmd.internal_object();

        let vk_flags = {
            let a = match flags {
                Flags::None => 0,
                Flags::SimultaneousUse => vk::COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
                Flags::OneTimeSubmit => vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
            };

            let b = match kind {
                Kind::Primary | Kind::Secondary => 0,
                Kind::SecondaryRenderPass { .. } => {
                    vk::COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
                },
            };

            a | b
        };

        let (rp, sp) = if let Kind::SecondaryRenderPass { ref subpass, .. } = kind {
            (subpass.render_pass().inner().internal_object(), subpass.index())
        } else {
            (0, 0)
        };

        let framebuffer = if let Kind::SecondaryRenderPass { ref subpass, framebuffer: Some(ref framebuffer) } = kind {
            // TODO: restore check
            //assert!(framebuffer.is_compatible_with(subpass.render_pass()));     // TODO: proper error
            FramebufferAbstract::inner(&framebuffer).internal_object()
        } else {
            0
        };

        let inheritance = vk::CommandBufferInheritanceInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
            pNext: ptr::null(),
            renderPass: rp,
            subpass: sp,
            framebuffer: framebuffer,
            occlusionQueryEnable: 0,            // TODO:
            queryFlags: 0,          // TODO:
            pipelineStatistics: 0,          // TODO:
        };

        let infos = vk::CommandBufferBeginInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
            pNext: ptr::null(),
            flags: vk_flags,
            pInheritanceInfo: &inheritance,
        };

        try!(check_errors(vk.BeginCommandBuffer(cmd, &infos)));

        Ok(UnsafeCommandBufferBuilder {
            device: device.clone(),
            pool: Some(pool),
            cmd: cmd,
            flags: flags,
            secondary_cb: match kind {
                Kind::Primary => false,
                Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
            },
        })
    }
}

unsafe impl<P> DeviceOwned for UnsafeCommandBufferBuilder<P> where P: CommandPool {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl<P> VulkanObject for UnsafeCommandBufferBuilder<P> where P: CommandPool {
    type Object = vk::CommandBuffer;

    #[inline]
    fn internal_object(&self) -> vk::CommandBuffer {
        self.cmd
    }
}

impl<P> Drop for UnsafeCommandBufferBuilder<P> where P: CommandPool {
    #[inline]
    fn drop(&mut self) {
        //unsafe {
            if self.cmd == 0 {
                return;
            }
            // FIXME: vk.FreeCommandBuffers()
        //}
    }
}

unsafe impl<P> CommandBufferBuild for UnsafeCommandBufferBuilder<P>
    where P: CommandPool
{
    type Out = UnsafeCommandBuffer<P>;
    type Err = OomError;

    #[inline]
    fn build(mut self) -> Result<Self::Out, OomError> {
        unsafe {
            debug_assert_ne!(self.cmd, 0);
            let cmd = self.cmd;
            let vk = self.device.pointers();
            try!(check_errors(vk.EndCommandBuffer(cmd)));
            self.cmd = 0;       // Prevents the `Drop` impl of the builder from destroying the cb.

            Ok(UnsafeCommandBuffer {
                cmd: cmd,
                device: self.device.clone(),
                pool: self.pool.take().unwrap().finish(),
                flags: self.flags,
                already_submitted: AtomicBool::new(false),
                secondary_cb: self.secondary_cb
            })
        }
    }
}

/// Command buffer that has been built.
///
/// Doesn't perform any synchronization and doesn't keep the object it uses alive.
pub struct UnsafeCommandBuffer<P> where P: CommandPool {
    // The Vulkan command buffer.
    cmd: vk::CommandBuffer,

    // Device that owns the command buffer.
    device: Arc<Device>,

    // Pool that owns the command buffer.
    pool: P::Finished,

    // Flags that were used at creation.
    flags: Flags,

    // True if the command buffer has always been submitted once. Only relevant if `flags` is
    // `OneTimeSubmit`.
    already_submitted: AtomicBool,

    // True if this command buffer belongs to a secondary pool - needed for Drop
    secondary_cb: bool
}

unsafe impl<P> CommandBuffer for UnsafeCommandBuffer<P> where P: CommandPool {
    type Pool = P;

    #[inline]
    fn inner(&self) -> &UnsafeCommandBuffer<P> {
        self
    }

    #[inline]
    fn submit_check(&self, _: &GpuFuture, _: &Queue) -> Result<(), Box<Error>> {
        // Not our job to check.
        Ok(())
    }

    #[inline]
    fn check_buffer_access(&self, buffer: &Buffer, exclusive: bool, queue: &Queue)
                           -> Result<Option<(PipelineStages, AccessFlagBits)>, ()>
    {
        Err(())
    }

    #[inline]
    fn check_image_access(&self, image: &Image, exclusive: bool, queue: &Queue)
                          -> Result<Option<(PipelineStages, AccessFlagBits)>, ()>
    {
        Err(())
    }
}

unsafe impl<P> DeviceOwned for UnsafeCommandBuffer<P> where P: CommandPool {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl<P> VulkanObject for UnsafeCommandBuffer<P> where P: CommandPool {
    type Object = vk::CommandBuffer;

    #[inline]
    fn internal_object(&self) -> vk::CommandBuffer {
        self.cmd
    }
}

impl<P> Drop for UnsafeCommandBuffer<P> where P: CommandPool {
    #[inline]
    fn drop(&mut self) {
        // release this command buffer for reuse
        use command_buffer::pool::CommandPoolFinished;
        unsafe {
            self.pool.free(self.secondary_cb, Some(self.cmd.into()).into_iter());
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use zbackup::proto;

/// The size of a ZBackup encryption key, in bytes
pub const KEY_SIZE: usize = 16;

/// The size of a ZBackup HMAC, in bytes
pub const HMAC_SIZE: usize = 20;

/// The size of a ZBackup initialisation vector, in bytes
pub const IV_SIZE: usize = 16;

/// The size of the buffers used when reading and decompressing ZBackup data
pub const BUFFER_SIZE: usize = 0x10000;

/// The default number of total jobs to queue up during a restore operation.
/// Since many chunks can be stored in a single bundle, and we can only use a
/// single thread to decompress one bundle, this needs to be high enough to
/// guarantee that we will always have enough jobs in the queue to make use of
/// all of the threads available.
pub const WORK_JOBS_TOTAL: usize = 0x1000;

/// The batch size for adding and removing jobs from the work queue. By doing
/// this in batches, we can avoid a certain amount of unnecessary locking.
pub const WORK_JOBS_BATCH: usize = 0x100;

/// A ZBackup bundle ID
pub type BundleId = [u8; 24];

/// A ZBackup chunk ID
pub type ChunkId = [u8; 24];

/// A ZBackup index ID
pub type IndexId = [u8; 24];

/// A ZBackup chunk's data
pub type ChunkData = Arc <Vec <u8>>;

/// A ZBackup encryption key
pub type EncryptionKey = [u8; KEY_SIZE];

/// A ZBackup index entry. This combined the header with the bundle info, since
/// generally both of these are needed to make use of the data.
pub type IndexEntry = (
	proto::IndexBundleHeader,
	proto::BundleInfo,
);

/// The default number of uncompressed memory cache entries. This number of
/// chunks will be kept in memory uncompressed, in an LRU cache.
pub const MAX_UNCOMPRESSED_MEMORY_CACHE_ENTRIES: usize = 0x800;

/// The default number of uncompressed memory cache entries. This number of
/// chunks will be kept in memory after LZO-compression, in an LRU cache.
pub const MAX_COMPRESSED_MEMORY_CACHE_ENTRIES: usize = 0x4000;

/// The default number of compressed filesystem cache entries. This number of
/// chunks will be stored in a temporary directory after LZO-compression.
pub const MAX_COMPRESSED_FILESYSTEM_CACHE_ENTRIES: usize = 0x20000;

/// The default location for the filesystem cache.
pub const FILESYSTEM_CACHE_PATH: & 'static str = "/tmp/rzbackup-cache";

// ex: noet ts=4 filetype=rust
<commit_msg>use much more conservative default cache sizes<commit_after>use std::sync::Arc;

use zbackup::proto;

/// The size of a ZBackup encryption key, in bytes
pub const KEY_SIZE: usize = 16;

/// The size of a ZBackup HMAC, in bytes
pub const HMAC_SIZE: usize = 20;

/// The size of a ZBackup initialisation vector, in bytes
pub const IV_SIZE: usize = 16;

/// The size of the buffers used when reading and decompressing ZBackup data
pub const BUFFER_SIZE: usize = 0x10000;

/// The default number of total jobs to queue up during a restore operation.
/// Since many chunks can be stored in a single bundle, and we can only use a
/// single thread to decompress one bundle, this needs to be high enough to
/// guarantee that we will always have enough jobs in the queue to make use of
/// all of the threads available.
pub const WORK_JOBS_TOTAL: usize = 0x1000;

/// The batch size for adding and removing jobs from the work queue. By doing
/// this in batches, we can avoid a certain amount of unnecessary locking.
pub const WORK_JOBS_BATCH: usize = 0x100;

/// A ZBackup bundle ID
pub type BundleId = [u8; 24];

/// A ZBackup chunk ID
pub type ChunkId = [u8; 24];

/// A ZBackup index ID
pub type IndexId = [u8; 24];

/// A ZBackup chunk's data
pub type ChunkData = Arc <Vec <u8>>;

/// A ZBackup encryption key
pub type EncryptionKey = [u8; KEY_SIZE];

/// A ZBackup index entry. This combined the header with the bundle info, since
/// generally both of these are needed to make use of the data.
pub type IndexEntry = (
	proto::IndexBundleHeader,
	proto::BundleInfo,
);

/// The default number of uncompressed memory cache entries. This number of
/// chunks will be kept in memory uncompressed, in an LRU cache.
pub const MAX_UNCOMPRESSED_MEMORY_CACHE_ENTRIES: usize = 0x100;

/// The default number of uncompressed memory cache entries. This number of
/// chunks will be kept in memory after LZO-compression, in an LRU cache.
pub const MAX_COMPRESSED_MEMORY_CACHE_ENTRIES: usize = 0x800;

/// The default number of compressed filesystem cache entries. This number of
/// chunks will be stored in a temporary directory after LZO-compression.
pub const MAX_COMPRESSED_FILESYSTEM_CACHE_ENTRIES: usize = 0x4000;

/// The default location for the filesystem cache.
pub const FILESYSTEM_CACHE_PATH: & 'static str = "/tmp/rzbackup-cache";

// ex: noet ts=4 filetype=rust
<|endoftext|>


<commit_before>use rlp::{Encodable, Decodable, RlpStream, DecoderError, UntrustedRlp};
use bigint::H512;
use std::io;
use std::net::SocketAddr;
use ecies::ECIESStream;
use tokio_core::reactor::Handle;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::{Framed, Encoder, Decoder};
use secp256k1::{self, SECP256K1};
use secp256k1::key::{PublicKey, SecretKey};
use util::pk2id;
use futures::future;
use futures::{Poll, Async, StartSend, AsyncSink, Future, Stream, Sink};
use rlp;

#[derive(Clone, Debug, Copy, PartialEq, Eq)]
/// Capability information
pub struct CapabilityInfo {
    pub name: &'static str,
    pub version: usize,
    pub length: usize,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CapabilityMessage {
    pub name: String,
    pub version: usize,
}

impl Encodable for CapabilityMessage {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.begin_list(2);
        s.append(&self.name);
        s.append(&self.version);
    }
}

impl Decodable for CapabilityMessage {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        Ok(Self {
            name: rlp.val_at(0)?,
            version: rlp.val_at(1)?,
        })
    }
}

#[derive(Clone, Debug)]
pub struct HelloMessage {
    pub protocol_version: usize,
    pub client_version: String,
    pub capabilities: Vec<CapabilityMessage>,
    pub port: u16,
    pub id: H512,
}

impl Encodable for HelloMessage {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.begin_list(5);
        s.append(&self.protocol_version);
        s.append(&self.client_version);
        s.append_list(&self.capabilities);
        s.append(&self.port);
        s.append(&self.id);
    }
}

impl Decodable for HelloMessage {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        Ok(Self {
            protocol_version: rlp.val_at(0)?,
            client_version: rlp.val_at(1)?,
            capabilities: rlp.list_at(2)?,
            port: rlp.val_at(3)?,
            id: rlp.val_at(4)?,
        })
    }
}

/// Peer stream of a RLPx
pub struct PeerStream {
    stream: ECIESStream,
    protocol_version: usize,
    client_version: String,
    shared_capabilities: Vec<CapabilityInfo>,
    port: u16,
    id: H512,
    remote_id: H512,
}

impl PeerStream {
    /// Remote public id of this peer
    pub fn remote_id(&self) -> H512 {
        self.remote_id
    }

    /// Get all capabilities of this peer stream
    pub fn capabilities(&self) -> &[CapabilityInfo] {
        &self.shared_capabilities
    }

    /// Connect to a peer over TCP
    pub fn connect(
        addr: &SocketAddr, handle: &Handle,
        secret_key: SecretKey, remote_id: H512,
        protocol_version: usize, client_version: String,
        capabilities: Vec<CapabilityInfo>, port: u16
    ) -> Box<Future<Item = PeerStream, Error = io::Error>> {
        let public_key = match PublicKey::from_secret_key(&SECP256K1, &secret_key) {
            Ok(key) => key,
            Err(_) => return Box::new(future::err(
                io::Error::new(io::ErrorKind::Other, "SECP256K1 public key error")))
                as Box<Future<Item = PeerStream, Error = io::Error>>,
        };
        let id = pk2id(&public_key);
        let nonhello_capabilities = capabilities.clone();
        let nonhello_client_version = client_version.clone();

        debug!("connecting to rlpx peer {:x}", id);

        let stream = ECIESStream::connect(addr, handle, secret_key.clone(), remote_id)
            .and_then(move |socket| {
                debug!("sending hello message ...");
                let hello = rlp::encode(&HelloMessage {
                    port, id, protocol_version, client_version,
                    capabilities: {
                        let mut caps = Vec::new();
                        for cap in capabilities {
                            caps.push(CapabilityMessage {
                                name: cap.name.to_string(),
                                version: cap.version
                            });
                        }
                        caps
                    }
                }).to_vec();
                let message_id: Vec<u8> = rlp::encode(&0usize).to_vec();
                assert!(message_id.len() == 1);
                let mut ret: Vec<u8> = Vec::new();
                ret.push(message_id[0]);
                for d in &hello {
                    ret.push(*d);
                }
                socket.send(ret)
            })
            .and_then(|transport| transport.into_future().map_err(|(e, _)| {
                debug!("transport error: {:?}", e);
                e
            }))
            .and_then(move |(hello, transport)| {
                debug!("receiving hello message ...");
                if hello.is_none() {
                    debug!("hello failed because of no value");
                    return Err(io::Error::new(io::ErrorKind::Other, "hello failed (no value)"));
                }
                let hello = hello.unwrap();

                let message_id_rlp = UntrustedRlp::new(&hello[0..1]);
                let message_id: Result<usize, rlp::DecoderError> = message_id_rlp.as_val();
                match message_id {
                    Ok(message_id) => {
                        if message_id != 0 {
                            error!("hello failed because message id is not 0 but {}", message_id);
                            return Err(io::Error::new(io::ErrorKind::Other,
                                                      "hello failed (message id)"));
                        }
                    },
                    Err(_) => {
                        debug!("hello failed because message id cannot be parsed");
                        return Err(io::Error::new(io::ErrorKind::Other,
                                                  "hello failed (message id parsing)"));
                    }
                }

                let rlp: Result<HelloMessage, rlp::DecoderError> =
                    UntrustedRlp::new(&hello[1..]).as_val();
                match rlp {
                    Ok(val) => {
                        debug!("hello message: {:?}", val);
                        let mut shared_capabilities: Vec<CapabilityInfo> = Vec::new();

                        for cap_info in nonhello_capabilities {
                            if val.capabilities.iter().find(
                                |v| v.name == cap_info.name && v.version == cap_info.version)
                                .is_some()
                            {
                                shared_capabilities.push(cap_info.clone());
                            }
                        }

                        let mut shared_caps_original = shared_capabilities.clone();

                        for cap_info in shared_caps_original {
                            shared_capabilities.retain(|v| {
                                if v.name != cap_info.name { true }
                                else if v.version < cap_info.version { false }
                                else { true }
                            });
                        }

                        shared_capabilities.sort_by_key(|v| v.name.clone());

                        Ok(PeerStream {
                            stream: transport,
                            client_version: nonhello_client_version,
                            protocol_version, port, id, remote_id,
                            shared_capabilities
                        })
                    },
                    Err(_) => {
                        debug!("hello failed because message rlp parsing failed");
                        Err(io::Error::new(io::ErrorKind::Other, "hello failed (rlp error)"))
                    }
                }
            });

        Box::new(stream)
    }

    fn handle_reserved_message(
        &mut self, message_id: usize, data: Vec<u8>
    ) -> Result<(), io::Error> {
        match message_id {
            0x01 /* disconnect */ => {
                let reason: Result<usize, rlp::DecoderError> = UntrustedRlp::new(&data).val_at(0);
                debug!("received disconnect message, reason: {:?}", reason);
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "explicit disconnect"));
            },
            0x02 /* ping */ => {
                debug!("received ping message data {:?}", data);
                let mut payload: Vec<u8> = rlp::encode(&0x03usize /* pong */).to_vec();
                payload.append(&mut rlp::EMPTY_LIST_RLP.to_vec());
                debug!("sending pong message payload {:?}", payload);
                self.stream.start_send(payload)?;
                self.stream.poll_complete()?;
            },
            0x03 /* pong */ => {
                debug!("received pong message");
            },
            _ => {
                debug!("received unknown reserved message");
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "unhandled reserved message"))
            },
        }
        Ok(())
    }
}

impl Stream for PeerStream {
    type Item = (CapabilityInfo, usize, Vec<u8>);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match try_ready!(self.stream.poll()) {
            Some(val) => {
                debug!("received peer message: {:?}", val);
                let message_id_rlp = UntrustedRlp::new(&val[0..1]);
                let message_id: Result<usize, rlp::DecoderError> = message_id_rlp.as_val();

                let (cap, id) = match message_id {
                    Ok(message_id) => {
                        if message_id < 0x10 {
                            self.handle_reserved_message(message_id, (&val[1..]).into())?;
                            return Ok(Async::NotReady);
                        }

                        let mut message_id = message_id - 0x10;
                        let mut index = 0;
                        for cap in &self.shared_capabilities {
                            if message_id > cap.length {
                                message_id = message_id - cap.length;
                                index = index + 1;
                            }
                        }
                        if index >= self.shared_capabilities.len() {
                            return Err(io::Error::new(io::ErrorKind::Other,
                                                      "message id parsing failed (too big)"));
                        }
                        (self.shared_capabilities[index].clone(), message_id)
                    },
                    Err(_) => {
                        return Err(io::Error::new(io::ErrorKind::Other,
                                                  "message id parsing failed (invalid)"));
                    }
                };

                Ok(Async::Ready(Some((cap, id, (&val[1..]).into()))))
            },
            None => Ok(Async::Ready(None)),
        }
    }
}

impl Sink for PeerStream {
    type SinkItem = (&'static str, usize, Vec<u8>);
    type SinkError = io::Error;

    fn start_send(&mut self, (cap_name, id, data): (&'static str, usize, Vec<u8>)) -> StartSend<Self::SinkItem, Self::SinkError> {
        let cap = self.shared_capabilities.iter().find(|cap| {
            cap.name == cap_name
        });

        if cap.is_none() {
            debug!("giving up sending cap {} of id {} to 0x{:x} because remote does not support.",
                   cap_name, id, self.remote_id());
            return Ok(AsyncSink::Ready);
        }

        let cap = *cap.unwrap();

        if id >= cap.length {
            debug!("giving up sending cap {} of id {} to 0x{:x} because it is too big.",
                   cap_name, id, self.remote_id());
            return Ok(AsyncSink::Ready);
        }

        let mut message_id = 0x10;
        for scap in &self.shared_capabilities {
            if scap != &cap {
                message_id = message_id + scap.length;
            } else {
                break;
            }
        }
        message_id = message_id + id;
        let first = rlp::encode(&message_id);
        assert!(first.len() == 1);

        let mut ret: Vec<u8> = Vec::new();
        ret.push(first[0]);
        for d in &data {
            ret.push(*d);
        }

        match self.stream.start_send(ret)? {
            AsyncSink::Ready => Ok(AsyncSink::Ready),
            AsyncSink::NotReady(_) => Ok(AsyncSink::NotReady((cap_name, id, data))),
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        self.stream.poll_complete()
    }
}
<commit_msg>rlpx: support incoming connection in peer stream<commit_after>use rlp::{Encodable, Decodable, RlpStream, DecoderError, UntrustedRlp};
use bigint::H512;
use std::io;
use std::net::SocketAddr;
use ecies::ECIESStream;
use tokio_core::reactor::Handle;
use tokio_core::net::TcpStream;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::{Framed, Encoder, Decoder};
use secp256k1::{self, SECP256K1};
use secp256k1::key::{PublicKey, SecretKey};
use util::pk2id;
use futures::future;
use futures::{Poll, Async, StartSend, AsyncSink, Future, Stream, Sink};
use rlp;

#[derive(Clone, Debug, Copy, PartialEq, Eq)]
/// Capability information
pub struct CapabilityInfo {
    pub name: &'static str,
    pub version: usize,
    pub length: usize,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CapabilityMessage {
    pub name: String,
    pub version: usize,
}

impl Encodable for CapabilityMessage {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.begin_list(2);
        s.append(&self.name);
        s.append(&self.version);
    }
}

impl Decodable for CapabilityMessage {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        Ok(Self {
            name: rlp.val_at(0)?,
            version: rlp.val_at(1)?,
        })
    }
}

#[derive(Clone, Debug)]
pub struct HelloMessage {
    pub protocol_version: usize,
    pub client_version: String,
    pub capabilities: Vec<CapabilityMessage>,
    pub port: u16,
    pub id: H512,
}

impl Encodable for HelloMessage {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.begin_list(5);
        s.append(&self.protocol_version);
        s.append(&self.client_version);
        s.append_list(&self.capabilities);
        s.append(&self.port);
        s.append(&self.id);
    }
}

impl Decodable for HelloMessage {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        Ok(Self {
            protocol_version: rlp.val_at(0)?,
            client_version: rlp.val_at(1)?,
            capabilities: rlp.list_at(2)?,
            port: rlp.val_at(3)?,
            id: rlp.val_at(4)?,
        })
    }
}

/// Peer stream of a RLPx
pub struct PeerStream {
    stream: ECIESStream,
    protocol_version: usize,
    client_version: String,
    shared_capabilities: Vec<CapabilityInfo>,
    port: u16,
    id: H512,
    remote_id: H512,
}

impl PeerStream {
    /// Remote public id of this peer
    pub fn remote_id(&self) -> H512 {
        self.remote_id
    }

    /// Get all capabilities of this peer stream
    pub fn capabilities(&self) -> &[CapabilityInfo] {
        &self.shared_capabilities
    }

    /// Connect to a peer over TCP
    pub fn connect(
        addr: &SocketAddr, handle: &Handle,
        secret_key: SecretKey, remote_id: H512,
        protocol_version: usize, client_version: String,
        capabilities: Vec<CapabilityInfo>, port: u16
    ) -> Box<Future<Item = PeerStream, Error = io::Error>> {
        Box::new(
            ECIESStream::connect(addr, handle, secret_key.clone(), remote_id)
                .and_then(move |socket| {
                    PeerStream::new(socket, secret_key, protocol_version,
                                    client_version, capabilities, port)
                }))
    }

    /// Incoming peer stream over TCP
    pub fn incoming(
        stream: TcpStream,
        secret_key: SecretKey, remote_id: H512,
        protocol_version: usize, client_version: String,
        capabilities: Vec<CapabilityInfo>, port: u16
    ) -> Box<Future<Item = PeerStream, Error = io::Error>> {
        Box::new(
            ECIESStream::incoming(stream, secret_key.clone())
                .and_then(move |socket| {
                    PeerStream::new(socket, secret_key, protocol_version,
                                    client_version, capabilities, port)
                }))
    }

    /// Create a new peer stream
    pub fn new(
        ecies_stream: ECIESStream, secret_key: SecretKey,
        protocol_version: usize, client_version: String,
        capabilities: Vec<CapabilityInfo>, port: u16
    ) -> Box<Future<Item = PeerStream, Error = io::Error>> {
        let public_key = match PublicKey::from_secret_key(&SECP256K1, &secret_key) {
            Ok(key) => key,
            Err(_) => return Box::new(future::err(
                io::Error::new(io::ErrorKind::Other, "SECP256K1 public key error")))
                as Box<Future<Item = PeerStream, Error = io::Error>>,
        };
        let id = pk2id(&public_key);
        let nonhello_capabilities = capabilities.clone();
        let nonhello_client_version = client_version.clone();

        debug!("connecting to rlpx peer {:x}", id);

        let stream = future::ok(ecies_stream)
            .and_then(move |socket| {
                debug!("sending hello message ...");
                let hello = rlp::encode(&HelloMessage {
                    port, id, protocol_version, client_version,
                    capabilities: {
                        let mut caps = Vec::new();
                        for cap in capabilities {
                            caps.push(CapabilityMessage {
                                name: cap.name.to_string(),
                                version: cap.version
                            });
                        }
                        caps
                    }
                }).to_vec();
                let message_id: Vec<u8> = rlp::encode(&0usize).to_vec();
                assert!(message_id.len() == 1);
                let mut ret: Vec<u8> = Vec::new();
                ret.push(message_id[0]);
                for d in &hello {
                    ret.push(*d);
                }
                socket.send(ret)
            })
            .and_then(|transport| transport.into_future().map_err(|(e, _)| {
                debug!("transport error: {:?}", e);
                e
            }))
            .and_then(move |(hello, transport)| {
                debug!("receiving hello message ...");
                if hello.is_none() {
                    debug!("hello failed because of no value");
                    return Err(io::Error::new(io::ErrorKind::Other, "hello failed (no value)"));
                }
                let hello = hello.unwrap();

                let message_id_rlp = UntrustedRlp::new(&hello[0..1]);
                let message_id: Result<usize, rlp::DecoderError> = message_id_rlp.as_val();
                match message_id {
                    Ok(message_id) => {
                        if message_id != 0 {
                            error!("hello failed because message id is not 0 but {}", message_id);
                            return Err(io::Error::new(io::ErrorKind::Other,
                                                      "hello failed (message id)"));
                        }
                    },
                    Err(_) => {
                        debug!("hello failed because message id cannot be parsed");
                        return Err(io::Error::new(io::ErrorKind::Other,
                                                  "hello failed (message id parsing)"));
                    }
                }

                let rlp: Result<HelloMessage, rlp::DecoderError> =
                    UntrustedRlp::new(&hello[1..]).as_val();
                match rlp {
                    Ok(val) => {
                        debug!("hello message: {:?}", val);
                        let mut shared_capabilities: Vec<CapabilityInfo> = Vec::new();

                        for cap_info in nonhello_capabilities {
                            if val.capabilities.iter().find(
                                |v| v.name == cap_info.name && v.version == cap_info.version)
                                .is_some()
                            {
                                shared_capabilities.push(cap_info.clone());
                            }
                        }

                        let mut shared_caps_original = shared_capabilities.clone();

                        for cap_info in shared_caps_original {
                            shared_capabilities.retain(|v| {
                                if v.name != cap_info.name { true }
                                else if v.version < cap_info.version { false }
                                else { true }
                            });
                        }

                        shared_capabilities.sort_by_key(|v| v.name.clone());

                        Ok(PeerStream {
                            remote_id: transport.remote_id(),
                            stream: transport,
                            client_version: nonhello_client_version,
                            protocol_version, port, id,
                            shared_capabilities,
                        })
                    },
                    Err(_) => {
                        debug!("hello failed because message rlp parsing failed");
                        Err(io::Error::new(io::ErrorKind::Other, "hello failed (rlp error)"))
                    }
                }
            });

        Box::new(stream)
    }

    fn handle_reserved_message(
        &mut self, message_id: usize, data: Vec<u8>
    ) -> Result<(), io::Error> {
        match message_id {
            0x01 /* disconnect */ => {
                let reason: Result<usize, rlp::DecoderError> = UntrustedRlp::new(&data).val_at(0);
                debug!("received disconnect message, reason: {:?}", reason);
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "explicit disconnect"));
            },
            0x02 /* ping */ => {
                debug!("received ping message data {:?}", data);
                let mut payload: Vec<u8> = rlp::encode(&0x03usize /* pong */).to_vec();
                payload.append(&mut rlp::EMPTY_LIST_RLP.to_vec());
                debug!("sending pong message payload {:?}", payload);
                self.stream.start_send(payload)?;
                self.stream.poll_complete()?;
            },
            0x03 /* pong */ => {
                debug!("received pong message");
            },
            _ => {
                debug!("received unknown reserved message");
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "unhandled reserved message"))
            },
        }
        Ok(())
    }
}

impl Stream for PeerStream {
    type Item = (CapabilityInfo, usize, Vec<u8>);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match try_ready!(self.stream.poll()) {
            Some(val) => {
                debug!("received peer message: {:?}", val);
                let message_id_rlp = UntrustedRlp::new(&val[0..1]);
                let message_id: Result<usize, rlp::DecoderError> = message_id_rlp.as_val();

                let (cap, id) = match message_id {
                    Ok(message_id) => {
                        if message_id < 0x10 {
                            self.handle_reserved_message(message_id, (&val[1..]).into())?;
                            return Ok(Async::NotReady);
                        }

                        let mut message_id = message_id - 0x10;
                        let mut index = 0;
                        for cap in &self.shared_capabilities {
                            if message_id > cap.length {
                                message_id = message_id - cap.length;
                                index = index + 1;
                            }
                        }
                        if index >= self.shared_capabilities.len() {
                            return Err(io::Error::new(io::ErrorKind::Other,
                                                      "message id parsing failed (too big)"));
                        }
                        (self.shared_capabilities[index].clone(), message_id)
                    },
                    Err(_) => {
                        return Err(io::Error::new(io::ErrorKind::Other,
                                                  "message id parsing failed (invalid)"));
                    }
                };

                Ok(Async::Ready(Some((cap, id, (&val[1..]).into()))))
            },
            None => Ok(Async::Ready(None)),
        }
    }
}

impl Sink for PeerStream {
    type SinkItem = (&'static str, usize, Vec<u8>);
    type SinkError = io::Error;

    fn start_send(&mut self, (cap_name, id, data): (&'static str, usize, Vec<u8>)) -> StartSend<Self::SinkItem, Self::SinkError> {
        let cap = self.shared_capabilities.iter().find(|cap| {
            cap.name == cap_name
        });

        if cap.is_none() {
            debug!("giving up sending cap {} of id {} to 0x{:x} because remote does not support.",
                   cap_name, id, self.remote_id());
            return Ok(AsyncSink::Ready);
        }

        let cap = *cap.unwrap();

        if id >= cap.length {
            debug!("giving up sending cap {} of id {} to 0x{:x} because it is too big.",
                   cap_name, id, self.remote_id());
            return Ok(AsyncSink::Ready);
        }

        let mut message_id = 0x10;
        for scap in &self.shared_capabilities {
            if scap != &cap {
                message_id = message_id + scap.length;
            } else {
                break;
            }
        }
        message_id = message_id + id;
        let first = rlp::encode(&message_id);
        assert!(first.len() == 1);

        let mut ret: Vec<u8> = Vec::new();
        ret.push(first[0]);
        for d in &data {
            ret.push(*d);
        }

        match self.stream.start_send(ret)? {
            AsyncSink::Ready => Ok(AsyncSink::Ready),
            AsyncSink::NotReady(_) => Ok(AsyncSink::NotReady((cap_name, id, data))),
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        self.stream.poll_complete()
    }
}
<|endoftext|>


<commit_before>//
// base16.rs - base16 module
//
// The Base 16 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//      0 0             4 4             8 8            12 C
//      1 1             5 5             9 9            13 D
//      2 2             6 6            10 A            14 E
//      3 3             7 7            11 B            15 F
//

use std;

export mk, enc, encode, decode;

import vec::len;

type enc_t = {table: [u8], decode_map: [u8]};

iface enc {
    fn encode(dst: [mut u8], src: [u8]);
    fn encode_bytes(src: [u8]) -> [u8];
    fn decode(dst: [mut u8], src: [u8]) -> uint;
    fn decode_bytes(src: [u8]) -> [u8];
}

impl of enc for enc_t {
    fn encode(dst: [mut u8], src: [u8]) {
        b16encode(self.table, dst, src);
    }
    fn encode_bytes(src: [u8]) -> [u8] {
        let dst_len = encoded_len(len(src));
        let dst = vec::to_mut(vec::from_elem(dst_len, 0u8));
        self.encode(dst, src);
        vec::from_mut(dst)
    }
    fn decode(dst: [mut u8], src: [u8]) -> uint {
        b16decode(self.decode_map, dst, src)
    }
    fn decode_bytes(src: [u8]) -> [u8] {
        let dst_len = decoded_len(len(src));
        let dst = vec::to_mut(vec::from_elem(dst_len, 0u8));
        let end = self.decode(dst, src);
        vec::slice(vec::from_mut(dst), 0u, end)
    }
}

fn mk() -> enc {
    let table = str::bytes("0123456789ABCDEF");
    let decode_map = vec::to_mut(vec::from_elem(256u, 0xff_u8));

    let mut i = 0u8;
    while i < 16u8 {
        decode_map[table[i]] = i;
        i += 1u8;
    }

    i -= 6u8;
    while i < 16u8 {
        decode_map[table[i] + 32u8] = i;
        i += 1u8;
    }

    {table: table,
     decode_map: vec::from_mut(decode_map)} as enc
}

fn encode(src: [u8]) -> [u8] {
    let enc = mk();
    enc.encode_bytes(src)
}

fn decode(src: [u8]) -> [u8] {
    let enc = mk();
    enc.decode_bytes(src)
}

fn encoded_len(src_len: uint) -> uint { src_len * 2u }
fn decoded_len(src_len: uint) -> uint { src_len / 2u }

fn b16encode(table: [u8], dst: [mut u8], src: [u8]) {
    let mut src_length = len(src);
    let mut i = 0u;
    let mut j = 0u;

    while src_length > 0u {
        dst[i] = table[src[j] >> 4u8];
        dst[i + 1u] = table[src[j] & 0x0f_u8];

        src_length -= 1u;
        i += 2u;
        j += 1u;
    }
}

fn b16decode(decode_map: [u8], dst: [mut u8], src: [u8]) -> uint {
    let mut src_length = len(src);
    let mut i = 0u;
    let mut j = 0u;
    let mut chr1 = 0u8;
    let mut chr2 = 0u8;

    while src_length > 0u {
        if src[i] == 10u8 || src[j] == 13u8 || src[i] == 32u8 {
            src_length -= 1u;
            i += 1u;
            cont;
        }

        chr1 = decode_map[src[i]];
        chr2 = decode_map[src[i + 1u]];
        if chr1 == 0xff_u8 || chr2 == 0xff_u8 {
            fail "malformed base16 string";
        }
        dst[j] = chr1 << 4u8 | chr2;

        src_length -= 2u;
        i += 2u;
        j += 1u;
    }

    j
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_encode() {
        let src = str::bytes("foo");
        let exp = str::bytes("666F6F");
        let res = encode(src);
        assert res == exp;
    }
    #[test]
    fn test_decode() {
        let src = str::bytes("66 6f 6f");
        let exp = str::bytes("foo");
        let res = decode(src);
        assert res == exp;
    }
}
<commit_msg>base16: documentation<commit_after>//
// base16.rs - base16 module
//
// The Base 16 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//      0 0             4 4             8 8            12 C
//      1 1             5 5             9 9            13 D
//      2 2             6 6            10 A            14 E
//      3 3             7 7            11 B            15 F
//

#[doc = "

    Base16 Module

    See <http://tools.ietf.org/html/rfc4648#section-8> for details.

"];

use std;

export mk, enc, encode, decode;

import vec::len;

type enc_t = {table: [u8], decode_map: [u8]};

iface enc {
    fn encode(dst: [mut u8], src: [u8]);
    fn decode(dst: [mut u8], src: [u8]) -> uint;
    #[doc = "
    Encode input bytes to hex-encoded bytes.

    # Arguments

    * src - bytes for encoding

    # Return

    hex-encoded bytes
    "]
    fn encode_bytes(src: [u8]) -> [u8];
    #[doc = "
    Decode hex-encoded bytes to its original bytes.

    # Arguments

    * src - hex-encoded bytes

    # Return

    decoded bytes
    "]
    fn decode_bytes(src: [u8]) -> [u8];
}

impl of enc for enc_t {
    fn encode(dst: [mut u8], src: [u8]) {
        b16encode(self.table, dst, src);
    }
    fn decode(dst: [mut u8], src: [u8]) -> uint {
        b16decode(self.decode_map, dst, src)
    }
    fn encode_bytes(src: [u8]) -> [u8] {
        let dst_len = encoded_len(len(src));
        let dst = vec::to_mut(vec::from_elem(dst_len, 0u8));
        self.encode(dst, src);
        vec::from_mut(dst)
    }
    fn decode_bytes(src: [u8]) -> [u8] {
        let dst_len = decoded_len(len(src));
        let dst = vec::to_mut(vec::from_elem(dst_len, 0u8));
        let end = self.decode(dst, src);
        vec::slice(vec::from_mut(dst), 0u, end)
    }
}

fn mk() -> enc {
    #[doc = "
    Make instance of interface `enc`

    # Return

    instance of interface `enc`
    "];

    let table = str::bytes("0123456789ABCDEF");
    let decode_map = vec::to_mut(vec::from_elem(256u, 0xff_u8));

    let mut i = 0u8;
    while i < 16u8 {
        decode_map[table[i]] = i;
        i += 1u8;
    }

    i -= 6u8;
    while i < 16u8 {
        decode_map[table[i] + 32u8] = i;
        i += 1u8;
    }

    {table: table,
     decode_map: vec::from_mut(decode_map)} as enc
}

fn encode(src: [u8]) -> [u8] {
    #[doc = "
    Shortcut for enc#encode_bytes

    Table of hex alphabet and decode map is allocated
    every time when this function is called, so it's
    recommended to use `mk` and then `encode_bytes` instead
    if it's necessary to use this function many times.

    # Arguments

    * src - bytes for encoding

    # Return

    hex-encoded bytes
    "];

    let enc = mk();
    enc.encode_bytes(src)
}

fn decode(src: [u8]) -> [u8] {
    #[doc = "
    Shortcut for enc#decode_bytes

    Table of hex alphabet and decode map is allocated
    every time when this function is called, so it's
    recommended to use `mk` and then `decode_bytes` instead
    if it's necessary to use this function many times.

    # Arguments

    * src - hex-encoded bytes

    # Return

    decoded bytes
    "];

    let enc = mk();
    enc.decode_bytes(src)
}

fn encoded_len(src_len: uint) -> uint { src_len * 2u }
fn decoded_len(src_len: uint) -> uint { src_len / 2u }

fn b16encode(table: [u8], dst: [mut u8], src: [u8]) {
    let mut src_length = len(src);
    let mut i = 0u;
    let mut j = 0u;

    while src_length > 0u {
        dst[i] = table[src[j] >> 4u8];
        dst[i + 1u] = table[src[j] & 0x0f_u8];

        src_length -= 1u;
        i += 2u;
        j += 1u;
    }
}

fn b16decode(decode_map: [u8], dst: [mut u8], src: [u8]) -> uint {
    let mut src_length = len(src);
    let mut i = 0u;
    let mut j = 0u;
    let mut chr1 = 0u8;
    let mut chr2 = 0u8;

    while src_length > 0u {
        if src[i] == 10u8 || src[j] == 13u8 || src[i] == 32u8 {
            src_length -= 1u;
            i += 1u;
            cont;
        }

        chr1 = decode_map[src[i]];
        chr2 = decode_map[src[i + 1u]];
        if chr1 == 0xff_u8 || chr2 == 0xff_u8 {
            fail "malformed base16 string";
        }
        dst[j] = chr1 << 4u8 | chr2;

        src_length -= 2u;
        i += 2u;
        j += 1u;
    }

    j
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_encode() {
        let src = str::bytes("foo");
        let exp = str::bytes("666F6F");
        let res = encode(src);
        assert res == exp;
    }
    #[test]
    fn test_decode() {
        let src = str::bytes("66 6f 6f");
        let exp = str::bytes("foo");
        let res = decode(src);
        assert res == exp;
    }
}
<|endoftext|>


<commit_before>//!
//! Module to access bitcoin-core style blk files
//! that store the integral blockchain

extern crate byteorder;

use byteorder::{ReadBytesExt, LittleEndian};

use std::io;

/// Magic number stored at the start of each block
const MAGIC: u32 = 0xD9B4BEF9;

/// Reads a block from a blk_file as used by
/// bitcoin-core and various other implementations
pub fn read_block(rdr: &mut io::Read) -> Result<Option<Vec<u8>>, io::Error> {

    let magicnr    = rdr.read_u32::<LittleEndian>();
    if magicnr.is_err() {
        return Ok(None)
    }

    let length     = try!(rdr.read_u32::<LittleEndian>());
    let mut buffer = vec![0; length as usize];

    if magicnr.unwrap() != MAGIC {
        return Err(io::Error::new(io::ErrorKind::InvalidData, "Incorrect magic number"));
    }

    try!(rdr.read_exact(&mut buffer));

    Ok(Some(buffer))

    //bitcrust_lib::decode(&buffer)
    //    .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Incorrect length"))

}

<commit_msg>Ignore leasing zeros when importing blk-files<commit_after>//!
//! Module to access bitcoin-core style blk files
//! that store the integral blockchain

extern crate byteorder;

use byteorder::{ReadBytesExt, LittleEndian};

use std::io;

/// Magic number stored at the start of each block
const MAGIC: u32 = 0xD9B4BEF9;

/// Reads a block from a blk_file as used by
/// bitcoin-core and various other implementations
pub fn read_block(rdr: &mut io::Read) -> Result<Option<Vec<u8>>, io::Error> {

    loop {
        let magicnr = rdr.read_u32::<LittleEndian>();
        match magicnr {
            Err(_)     => return Ok(None), // assume EOF
            Ok(m) => match m {

                // TODO investigate.
                // this happens on bitcrust-1 at blcok  451327
                // file blk000760, file pos 54391594
                // first 8 zero-bytes before magicnr
                // for now we skip them
                0     => continue,

                MAGIC => break,
                _     =>return Err(io::Error::new(io::ErrorKind::InvalidData, "Incorrect magic number"))
            }
        }

    }

    let length     = try!(rdr.read_u32::<LittleEndian>());
    let mut buffer = vec![0; length as usize];

    try!(rdr.read_exact(&mut buffer));

    Ok(Some(buffer))

    //bitcrust_lib::decode(&buffer)
    //    .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Incorrect length"))

}

<|endoftext|>