<commit_before>use cairo;
use cairo_sys;
use glib::translate::*;

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

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

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

#[derive(Debug, PartialEq)]
pub enum PathCommand {
    MoveTo(f64, f64),
    LineTo(f64, f64),
    CurveTo((f64, f64), (f64, f64), (f64, f64)), /* (x2, y2), (x3, y3), (x4, y4) <- this is
                                                  * the destination point */
    ClosePath,
}

#[repr(C)]
pub struct RsvgPathBuilder {
    path_commands: Vec<PathCommand>,
}

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

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((x2, y2), (x3, y3), (x4, y4)) => {
                cr.curve_to(x2, y2, x3, y3, x4, y4);
            }

            PathCommand::ClosePath => {
                cr.close_path();
            }
        }
    }
}

impl RsvgPathBuilder {
    pub fn new() -> RsvgPathBuilder {
        RsvgPathBuilder::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) {
        self.path_commands
            .push(PathCommand::CurveTo((x2, y2), (x3, y3), (x4, y4)));
    }

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

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

    /// * * * * * * * * * * *
    // x1/y1: starting coordinates
    // rx/ry: radiuses before rotation
    // x_axis_rotation: Rotation angle for axes, in degrees
    // large_arc: false for arc length <= 180, true for arc >= 180
    // sweep: negative or positive angle
    // x2/y2: ending coordinates
    pub fn arc(
        &mut self,
        x1: f64,
        y1: f64,
        mut rx: f64,
        mut ry: f64,
        x_axis_rotation: f64,
        large_arc: LargeArc,
        sweep: Sweep,
        x2: f64,
        y2: f64,
    ) {
        // See Appendix F.6 Elliptical arc implementation notes
        // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
        let f: f64;
        let sinf: f64;
        let cosf: f64;
        let x1_: f64;
        let y1_: f64;
        let cx_: f64;
        let cy_: f64;
        let cx: f64;
        let cy: f64;
        let gamma: f64;
        let mut theta1: f64;
        let mut delta_theta: f64;
        let mut k1: f64;
        let mut k2: f64;
        let k3: f64;
        let k4: f64;
        let mut k5: f64;
        let n_segs: i32;

        if x1 == x2 && y1 == y2 {
            return;
        }

        let is_positive_sweep = sweep == Sweep::Positive;

        let is_large_arc = large_arc.0;

        // X-axis
        f = x_axis_rotation * PI / 180.0;
        sinf = f.sin();
        cosf = f.cos();

        rx = rx.abs();
        ry = ry.abs();

        // Check the radius against floading point underflow.
        // See http://bugs.debian.org/508443
        if (rx < f64::EPSILON) || (ry < f64::EPSILON) {
            self.line_to(x2, y2);
            return;
        }

        k1 = (x1 - x2) / 2.0;
        k2 = (y1 - y2) / 2.0;

        x1_ = cosf * k1 + sinf * k2;
        y1_ = -sinf * k1 + cosf * k2;

        gamma = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry);
        if gamma > 1.0 {
            rx *= gamma.sqrt();
            ry *= gamma.sqrt();
        }

        // Compute the center
        k1 = rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_;
        if k1 == 0.0 {
            return;
        }

        k1 = ((rx * rx * ry * ry) / k1 - 1.0).abs().sqrt();
        if is_positive_sweep == is_large_arc {
            k1 = -k1;
        }

        cx_ = k1 * rx * y1_ / ry;
        cy_ = -k1 * ry * x1_ / rx;

        cx = cosf * cx_ - sinf * cy_ + (x1 + x2) / 2.0;
        cy = sinf * cx_ + cosf * cy_ + (y1 + y2) / 2.0;

        // Compute start angle
        k1 = (x1_ - cx_) / rx;
        k2 = (y1_ - cy_) / ry;
        k3 = (-x1_ - cx_) / rx;
        k4 = (-y1_ - cy_) / ry;

        k5 = (k1 * k1 + k2 * k2).abs().sqrt();
        if k5 == 0.0 {
            return;
        }

        k5 = k1 / k5;
        k5 = clamp(k5, -1.0, 1.0);
        theta1 = k5.acos();
        if k2 < 0.0 {
            theta1 = -theta1;
        }

        // Compute delta_theta
        k5 = ((k1 * k1 + k2 * k2) * (k3 * k3 + k4 * k4)).abs().sqrt();
        if k5 == 0.0 {
            return;
        }

        k5 = (k1 * k3 + k2 * k4) / k5;
        k5 = clamp(k5, -1.0, 1.0);
        delta_theta = k5.acos();
        if k1 * k4 - k3 * k2 < 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;
        }

        // Now draw the arc
        n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs().ceil() as i32;
        let n_segs_dbl = f64::from(n_segs);

        for i in 0..n_segs {
            self.arc_segment(
                cx,
                cy,
                theta1 + f64::from(i) * delta_theta / n_segs_dbl,
                theta1 + f64::from(i + 1) * delta_theta / n_segs_dbl,
                rx,
                ry,
                x_axis_rotation,
            );
        }
    }

    fn arc_segment(
        &mut self,
        xc: f64,
        yc: f64,
        th0: f64,
        th1: f64,
        rx: f64,
        ry: f64,
        x_axis_rotation: f64,
    ) {
        let x1: f64;
        let y1: f64;
        let x2: f64;
        let y2: f64;
        let x3: f64;
        let y3: f64;
        let t: f64;
        let th_half: f64;
        let f: f64;
        let sinf: f64;
        let cosf: f64;

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

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

        self.curve_to(
            xc + cosf * x1 - sinf * y1,
            yc + sinf * x1 + cosf * y1,
            xc + cosf * x2 - sinf * y2,
            yc + sinf * x2 + cosf * y2,
            xc + cosf * x3 - sinf * y3,
            yc + sinf * x3 + cosf * y3,
        );
    }

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

fn clamp(val: f64, low: f64, high: f64) -> f64 {
    if val < low {
        low
    } else if val > high {
        high
    } else {
        val
    }
}

#[no_mangle]
pub extern "C" fn rsvg_path_builder_add_to_cairo_context(
    raw_builder: *mut RsvgPathBuilder,
    raw_cr: *mut cairo_sys::cairo_t,
) {
    assert!(!raw_builder.is_null());
    assert!(!raw_cr.is_null());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };
    let cr = unsafe { cairo::Context::from_glib_none(raw_cr) };
    builder.to_cairo(&cr);
}
<commit_msg>path_builder.rs: Use approx_eq_cairo() instead of direct float comparisons<commit_after>use cairo;
use cairo_sys;
use glib::translate::*;

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

use float_eq_cairo::ApproxEqCairo;

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

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

#[derive(Debug, PartialEq)]
pub enum PathCommand {
    MoveTo(f64, f64),
    LineTo(f64, f64),
    CurveTo((f64, f64), (f64, f64), (f64, f64)), /* (x2, y2), (x3, y3), (x4, y4) <- this is
                                                  * the destination point */
    ClosePath,
}

#[repr(C)]
pub struct RsvgPathBuilder {
    path_commands: Vec<PathCommand>,
}

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

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((x2, y2), (x3, y3), (x4, y4)) => {
                cr.curve_to(x2, y2, x3, y3, x4, y4);
            }

            PathCommand::ClosePath => {
                cr.close_path();
            }
        }
    }
}

impl RsvgPathBuilder {
    pub fn new() -> RsvgPathBuilder {
        RsvgPathBuilder::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) {
        self.path_commands
            .push(PathCommand::CurveTo((x2, y2), (x3, y3), (x4, y4)));
    }

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

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

    /// * * * * * * * * * * *
    // x1/y1: starting coordinates
    // rx/ry: radiuses before rotation
    // x_axis_rotation: Rotation angle for axes, in degrees
    // large_arc: false for arc length <= 180, true for arc >= 180
    // sweep: negative or positive angle
    // x2/y2: ending coordinates
    pub fn arc(
        &mut self,
        x1: f64,
        y1: f64,
        mut rx: f64,
        mut ry: f64,
        x_axis_rotation: f64,
        large_arc: LargeArc,
        sweep: Sweep,
        x2: f64,
        y2: f64,
    ) {
        // See Appendix F.6 Elliptical arc implementation notes
        // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
        let f: f64;
        let sinf: f64;
        let cosf: f64;
        let x1_: f64;
        let y1_: f64;
        let cx_: f64;
        let cy_: f64;
        let cx: f64;
        let cy: f64;
        let gamma: f64;
        let mut theta1: f64;
        let mut delta_theta: f64;
        let mut k1: f64;
        let mut k2: f64;
        let k3: f64;
        let k4: f64;
        let mut k5: f64;
        let n_segs: i32;

        if x1.approx_eq_cairo(&x2) && y1.approx_eq_cairo(&y2) {
            return;
        }

        let is_positive_sweep = sweep == Sweep::Positive;

        let is_large_arc = large_arc.0;

        // X-axis
        f = x_axis_rotation * PI / 180.0;
        sinf = f.sin();
        cosf = f.cos();

        rx = rx.abs();
        ry = ry.abs();

        // 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) {
            self.line_to(x2, y2);
            return;
        }

        k1 = (x1 - x2) / 2.0;
        k2 = (y1 - y2) / 2.0;

        x1_ = cosf * k1 + sinf * k2;
        y1_ = -sinf * k1 + cosf * k2;

        gamma = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry);
        if gamma > 1.0 {
            rx *= gamma.sqrt();
            ry *= gamma.sqrt();
        }

        // Compute the center
        k1 = rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_;
        if k1.approx_eq_cairo(&0.0) {
            return;
        }

        k1 = ((rx * rx * ry * ry) / k1 - 1.0).abs().sqrt();
        if is_positive_sweep == is_large_arc {
            k1 = -k1;
        }

        cx_ = k1 * rx * y1_ / ry;
        cy_ = -k1 * ry * x1_ / rx;

        cx = cosf * cx_ - sinf * cy_ + (x1 + x2) / 2.0;
        cy = sinf * cx_ + cosf * cy_ + (y1 + y2) / 2.0;

        // Compute start angle
        k1 = (x1_ - cx_) / rx;
        k2 = (y1_ - cy_) / ry;
        k3 = (-x1_ - cx_) / rx;
        k4 = (-y1_ - cy_) / ry;

        k5 = (k1 * k1 + k2 * k2).abs().sqrt();
        if k5.approx_eq_cairo(&0.0) {
            return;
        }

        k5 = k1 / k5;
        k5 = clamp(k5, -1.0, 1.0);
        theta1 = k5.acos();
        if k2 < 0.0 {
            theta1 = -theta1;
        }

        // Compute delta_theta
        k5 = ((k1 * k1 + k2 * k2) * (k3 * k3 + k4 * k4)).abs().sqrt();
        if k5.approx_eq_cairo(&0.0) {
            return;
        }

        k5 = (k1 * k3 + k2 * k4) / k5;
        k5 = clamp(k5, -1.0, 1.0);
        delta_theta = k5.acos();
        if k1 * k4 - k3 * k2 < 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;
        }

        // Now draw the arc
        n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs().ceil() as i32;
        let n_segs_dbl = f64::from(n_segs);

        for i in 0..n_segs {
            self.arc_segment(
                cx,
                cy,
                theta1 + f64::from(i) * delta_theta / n_segs_dbl,
                theta1 + f64::from(i + 1) * delta_theta / n_segs_dbl,
                rx,
                ry,
                x_axis_rotation,
            );
        }
    }

    fn arc_segment(
        &mut self,
        xc: f64,
        yc: f64,
        th0: f64,
        th1: f64,
        rx: f64,
        ry: f64,
        x_axis_rotation: f64,
    ) {
        let x1: f64;
        let y1: f64;
        let x2: f64;
        let y2: f64;
        let x3: f64;
        let y3: f64;
        let t: f64;
        let th_half: f64;
        let f: f64;
        let sinf: f64;
        let cosf: f64;

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

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

        self.curve_to(
            xc + cosf * x1 - sinf * y1,
            yc + sinf * x1 + cosf * y1,
            xc + cosf * x2 - sinf * y2,
            yc + sinf * x2 + cosf * y2,
            xc + cosf * x3 - sinf * y3,
            yc + sinf * x3 + cosf * y3,
        );
    }

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

fn clamp(val: f64, low: f64, high: f64) -> f64 {
    if val < low {
        low
    } else if val > high {
        high
    } else {
        val
    }
}

#[no_mangle]
pub extern "C" fn rsvg_path_builder_add_to_cairo_context(
    raw_builder: *mut RsvgPathBuilder,
    raw_cr: *mut cairo_sys::cairo_t,
) {
    assert!(!raw_builder.is_null());
    assert!(!raw_cr.is_null());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };
    let cr = unsafe { cairo::Context::from_glib_none(raw_cr) };
    builder.to_cairo(&cr);
}

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

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


<commit_before>use std::net::TcpListener;

pub fn get_available_port(avoid: u16) -> Option<u16> {
    (1000..9000).find(|port| *port != avoid && port_is_available(*port))
}

pub fn port_is_available(port: u16) -> bool {
    TcpListener::bind(("127.0.0.1", port)).is_ok()
}
<commit_msg>Do not attempt to serve on "well-known" ports (#824)<commit_after>use std::net::TcpListener;

pub fn get_available_port(avoid: u16) -> Option<u16> {
    // Start after "well-known" ports (0–1023) as they require superuser
    // privileges on UNIX-like operating systems.
    (1024..9000).find(|port| *port != avoid && port_is_available(*port))
}

pub fn port_is_available(port: u16) -> bool {
    TcpListener::bind(("127.0.0.1", port)).is_ok()
}
<|endoftext|>


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

pub fn make_binomial(max_n: usize, max_k: usize) -> Box<[Box<[usize]>]> {
    let mut binomial = vec![vec![0; max_k + 1].into_boxed_slice(); max_n + 1].into_boxed_slice();
    binomial[0][0] = 1;
    for n in 0..max_n {
        binomial[n + 1][0] = 1;
        for k in 0..max_k {
            binomial[n + 1][k + 1] = binomial[n][k] + binomial[n][k + 1];
        }
    }
    binomial
}

pub fn encode_combination(binomial: &[Box<[usize]>], c: &[usize]) -> usize {
    debug_assert!(c.iter().zip(c.iter().skip(1)).all(|(&a, &b)| a < b));
    c.iter().enumerate().map(|(i, &a)| binomial[a][i + 1]).sum()
}

pub fn decode_combination(binomial: &[Box<[usize]>], k: usize, m: usize) -> Box<[usize]> {
    let mut c = vec![0; k].into_boxed_slice();
    let mut mm = m;
    let mut n = binomial.len();
    for i in (0..k).rev() {
        c[i] = binomial[i + 1..n]
            .binary_search_by(|b| if b[i + 1] > mm {
                Ordering::Greater
            } else {
                Ordering::Less
            })
            .unwrap_err() + i;
        mm -= binomial[c[i]][i + 1];
        n = c[i];
    }
    debug_assert!(mm == 0);
    c
}

#[cfg(test)]
mod tests {
    use super::{make_binomial, encode_combination, decode_combination};

    #[test]
    fn test_binomial() {
        let expected: &[Box<[usize]>] = &[Box::new([1, 0, 0, 0, 0, 0]),
                                          Box::new([1, 1, 0, 0, 0, 0]),
                                          Box::new([1, 2, 1, 0, 0, 0]),
                                          Box::new([1, 3, 3, 1, 0, 0]),
                                          Box::new([1, 4, 6, 4, 1, 0]),
                                          Box::new([1, 5, 10, 10, 5, 1]),
                                          Box::new([1, 6, 15, 20, 15, 6]),
                                          Box::new([1, 7, 21, 35, 35, 21]),
                                          Box::new([1, 8, 28, 56, 70, 56]),
                                          Box::new([1, 9, 36, 84, 126, 126]),
                                          Box::new([1, 10, 45, 120, 210, 252])];
        assert_eq!(*make_binomial(10, 5), *expected);
    }

    #[test]
    fn test_encode_combination() {
        let binomial = make_binomial(5, 3);
        assert_eq!(encode_combination(&binomial, &[0, 1, 2]), 0);
        assert_eq!(encode_combination(&binomial, &[0, 1, 3]), 1);
        assert_eq!(encode_combination(&binomial, &[0, 2, 3]), 2);
        assert_eq!(encode_combination(&binomial, &[1, 2, 3]), 3);
        assert_eq!(encode_combination(&binomial, &[0, 1, 4]), 4);
        assert_eq!(encode_combination(&binomial, &[0, 2, 4]), 5);
        assert_eq!(encode_combination(&binomial, &[1, 2, 4]), 6);
        assert_eq!(encode_combination(&binomial, &[0, 3, 4]), 7);
        assert_eq!(encode_combination(&binomial, &[1, 3, 4]), 8);
        assert_eq!(encode_combination(&binomial, &[2, 3, 4]), 9);
        assert_eq!(encode_combination(&binomial, &[0, 1, 5]), 10);
    }

    #[test]
    fn test_decode_combination() {
        let binomial = make_binomial(5, 3);
        assert_eq!(*decode_combination(&binomial, 3, 0), [0, 1, 2]);
        assert_eq!(*decode_combination(&binomial, 3, 1), [0, 1, 3]);
        assert_eq!(*decode_combination(&binomial, 3, 2), [0, 2, 3]);
        assert_eq!(*decode_combination(&binomial, 3, 3), [1, 2, 3]);
        assert_eq!(*decode_combination(&binomial, 3, 4), [0, 1, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 5), [0, 2, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 6), [1, 2, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 7), [0, 3, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 8), [1, 3, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 9), [2, 3, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 10), [0, 1, 5]);
    }
}
<commit_msg>Use debug_assert_eq!<commit_after>use std::cmp::Ordering;

pub fn make_binomial(max_n: usize, max_k: usize) -> Box<[Box<[usize]>]> {
    let mut binomial = vec![vec![0; max_k + 1].into_boxed_slice(); max_n + 1].into_boxed_slice();
    binomial[0][0] = 1;
    for n in 0..max_n {
        binomial[n + 1][0] = 1;
        for k in 0..max_k {
            binomial[n + 1][k + 1] = binomial[n][k] + binomial[n][k + 1];
        }
    }
    binomial
}

pub fn encode_combination(binomial: &[Box<[usize]>], c: &[usize]) -> usize {
    debug_assert!(c.iter().zip(c.iter().skip(1)).all(|(&a, &b)| a < b));
    c.iter().enumerate().map(|(i, &a)| binomial[a][i + 1]).sum()
}

pub fn decode_combination(binomial: &[Box<[usize]>], k: usize, m: usize) -> Box<[usize]> {
    let mut c = vec![0; k].into_boxed_slice();
    let mut mm = m;
    let mut n = binomial.len();
    for i in (0..k).rev() {
        c[i] = binomial[i + 1..n]
            .binary_search_by(|b| if b[i + 1] > mm {
                Ordering::Greater
            } else {
                Ordering::Less
            })
            .unwrap_err() + i;
        mm -= binomial[c[i]][i + 1];
        n = c[i];
    }
    debug_assert_eq!(mm, 0);
    c
}

#[cfg(test)]
mod tests {
    use super::{make_binomial, encode_combination, decode_combination};

    #[test]
    fn test_binomial() {
        let expected: &[Box<[usize]>] = &[Box::new([1, 0, 0, 0, 0, 0]),
                                          Box::new([1, 1, 0, 0, 0, 0]),
                                          Box::new([1, 2, 1, 0, 0, 0]),
                                          Box::new([1, 3, 3, 1, 0, 0]),
                                          Box::new([1, 4, 6, 4, 1, 0]),
                                          Box::new([1, 5, 10, 10, 5, 1]),
                                          Box::new([1, 6, 15, 20, 15, 6]),
                                          Box::new([1, 7, 21, 35, 35, 21]),
                                          Box::new([1, 8, 28, 56, 70, 56]),
                                          Box::new([1, 9, 36, 84, 126, 126]),
                                          Box::new([1, 10, 45, 120, 210, 252])];
        assert_eq!(*make_binomial(10, 5), *expected);
    }

    #[test]
    fn test_encode_combination() {
        let binomial = make_binomial(5, 3);
        assert_eq!(encode_combination(&binomial, &[0, 1, 2]), 0);
        assert_eq!(encode_combination(&binomial, &[0, 1, 3]), 1);
        assert_eq!(encode_combination(&binomial, &[0, 2, 3]), 2);
        assert_eq!(encode_combination(&binomial, &[1, 2, 3]), 3);
        assert_eq!(encode_combination(&binomial, &[0, 1, 4]), 4);
        assert_eq!(encode_combination(&binomial, &[0, 2, 4]), 5);
        assert_eq!(encode_combination(&binomial, &[1, 2, 4]), 6);
        assert_eq!(encode_combination(&binomial, &[0, 3, 4]), 7);
        assert_eq!(encode_combination(&binomial, &[1, 3, 4]), 8);
        assert_eq!(encode_combination(&binomial, &[2, 3, 4]), 9);
        assert_eq!(encode_combination(&binomial, &[0, 1, 5]), 10);
    }

    #[test]
    fn test_decode_combination() {
        let binomial = make_binomial(5, 3);
        assert_eq!(*decode_combination(&binomial, 3, 0), [0, 1, 2]);
        assert_eq!(*decode_combination(&binomial, 3, 1), [0, 1, 3]);
        assert_eq!(*decode_combination(&binomial, 3, 2), [0, 2, 3]);
        assert_eq!(*decode_combination(&binomial, 3, 3), [1, 2, 3]);
        assert_eq!(*decode_combination(&binomial, 3, 4), [0, 1, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 5), [0, 2, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 6), [1, 2, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 7), [0, 3, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 8), [1, 3, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 9), [2, 3, 4]);
        assert_eq!(*decode_combination(&binomial, 3, 10), [0, 1, 5]);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

mod gdt;
pub mod irq;
mod pit;
pub mod processor;
pub mod serial;
mod start;
mod syscall;
pub mod task;

pub use crate::arch::x86_64::kernel::syscall::syscall_handler;
use core::ptr::read_volatile;

global_asm!(include_str!("user_land.s"));
global_asm!(include_str!("switch.s"));

#[repr(C)]
struct KernelHeader {
	magic_number: u32,
	version: u32,
	mem_limit: u64,
	num_cpus: u32,
	file_addr: u64,
	file_length: u64,
}

/// Kernel header to announce machine features
#[link_section = ".kheader"]
static KERNEL_HEADER: KernelHeader = KernelHeader {
	magic_number: 0xDEADC0DEu32,
	version: 0,
	mem_limit: 0,
	num_cpus: 1,
	file_addr: 0,
	file_length: 0,
};

pub fn get_memfile() -> (u64, u64) {
	let version = unsafe { read_volatile(&KERNEL_HEADER.version) };
	let addr = unsafe { read_volatile(&KERNEL_HEADER.file_addr) };
	let len = unsafe { read_volatile(&KERNEL_HEADER.file_length) };

	if version > 0 {
		(addr, len)
	} else {
		(0, 0)
	}
}

pub fn get_memory_size() -> usize {
	unsafe { read_volatile(&KERNEL_HEADER.mem_limit) as usize }
}

pub fn register_task() {
	let sel: u16 = 6u16 << 3;

	unsafe {
		llvm_asm!("ltr $0" :: "r"(sel) :: "volatile");
	}
}

extern "C" {
	#[no_mangle]
	pub fn jump_to_user_land(entry: u64);
}

/// This macro can be used to call system functions from user-space
#[macro_export]
macro_rules! syscall {
	($arg0:expr) => {
		arch::x86_64::kernel::syscall0($arg0 as u64)
	};

	($arg0:expr, $arg1:expr) => {
		arch::x86_64::kernel::syscall1($arg0 as u64, $arg1 as u64)
	};

	($arg0:expr, $arg1:expr, $arg2:expr) => {
		arch::x86_64::kernel::syscall2($arg0 as u64, $arg1 as u64, $arg2 as u64)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr) => {
		arch::x86_64::kernel::syscall3($arg0 as u64, $arg1 as u64, $arg2 as u64, $arg3 as u64)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr) => {
		arch::x86_64::kernel::syscall4(
			$arg0 as u64,
			$arg1 as u64,
			$arg2 as u64,
			$arg3 as u64,
			$arg4 as u64,
			)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => {
		arch::x86_64::kernel::syscall5(
			$arg0 as u64,
			$arg1 as u64,
			$arg2 as u64,
			$arg3 as u64,
			$arg4 as u64,
			$arg5 as u64,
			)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr) => {
		arch::x86_64::kernel::syscall6(
			$arg0 as u64,
			$arg1 as u64,
			$arg2 as u64,
			$arg3 as u64,
			$arg4 as u64,
			$arg5 as u64,
			$arg6 as u64,
			)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr, $arg7:expr) => {
		arch::x86_64::kernel::syscall7(
			$arg0 as u64,
			$arg1 as u64,
			$arg2 as u64,
			$arg3 as u64,
			$arg4 as u64,
			$arg5 as u64,
			$arg6 as u64,
			$arg7 as u64,
			)
	};
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall0(arg0: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0) : "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall1(arg0: u64, arg1: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1)
						: "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall2(arg0: u64, arg1: u64, arg2: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2)
						: "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall3(arg0: u64, arg1: u64, arg2: u64, arg3: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2),
						"{rdx}" (arg3) : "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall4(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret)
						: "{rax}"  (arg0), "{rdi}"  (arg1), "{rsi}"  (arg2), "{rdx}"  (arg3),
						"{r10}"  (arg4) : "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall5(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret)
						: "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2), "{rdx}" (arg3),
						"{r10}" (arg4), "{r8}" (arg5) : "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall6(
	arg0: u64,
	arg1: u64,
	arg2: u64,
	arg3: u64,
	arg4: u64,
	arg5: u64,
	arg6: u64,
) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2),
						"{rdx}" (arg3), "{r10}" (arg4), "{r8}" (arg5), "{r9}" (arg6)
						: "rcx", "r11", "memory" : "volatile");
	}
	ret
}

/// Initialize module, must be called once, and only once
pub fn init() {
	processor::init();
	gdt::init();
	irq::init();
	pit::init();
}
<commit_msg>remove compiler warnings<commit_after>// Copyright (c) 2017-2018 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

mod gdt;
pub mod irq;
mod pit;
pub mod processor;
pub mod serial;
mod start;
mod syscall;
pub mod task;

pub use crate::arch::x86_64::kernel::syscall::syscall_handler;
use core::ptr::read_volatile;

global_asm!(include_str!("user_land.s"));
global_asm!(include_str!("switch.s"));

#[repr(C)]
struct KernelHeader {
	magic_number: u32,
	version: u32,
	mem_limit: u64,
	num_cpus: u32,
	file_addr: u64,
	file_length: u64,
}

/// Kernel header to announce machine features
#[link_section = ".kheader"]
static KERNEL_HEADER: KernelHeader = KernelHeader {
	magic_number: 0xDEADC0DEu32,
	version: 0,
	mem_limit: 0,
	num_cpus: 1,
	file_addr: 0,
	file_length: 0,
};

pub fn get_memfile() -> (u64, u64) {
	let version = unsafe { read_volatile(&KERNEL_HEADER.version) };
	let addr = unsafe { read_volatile(&KERNEL_HEADER.file_addr) };
	let len = unsafe { read_volatile(&KERNEL_HEADER.file_length) };

	if version > 0 {
		(addr, len)
	} else {
		(0, 0)
	}
}

pub fn get_memory_size() -> usize {
	unsafe { read_volatile(&KERNEL_HEADER.mem_limit) as usize }
}

pub fn register_task() {
	let sel: u16 = 6u16 << 3;

	unsafe {
		llvm_asm!("ltr $0" :: "r"(sel) :: "volatile");
	}
}

extern "C" {
	pub fn jump_to_user_land(entry: u64);
}

/// This macro can be used to call system functions from user-space
#[macro_export]
macro_rules! syscall {
	($arg0:expr) => {
		arch::x86_64::kernel::syscall0($arg0 as u64)
	};

	($arg0:expr, $arg1:expr) => {
		arch::x86_64::kernel::syscall1($arg0 as u64, $arg1 as u64)
	};

	($arg0:expr, $arg1:expr, $arg2:expr) => {
		arch::x86_64::kernel::syscall2($arg0 as u64, $arg1 as u64, $arg2 as u64)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr) => {
		arch::x86_64::kernel::syscall3($arg0 as u64, $arg1 as u64, $arg2 as u64, $arg3 as u64)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr) => {
		arch::x86_64::kernel::syscall4(
			$arg0 as u64,
			$arg1 as u64,
			$arg2 as u64,
			$arg3 as u64,
			$arg4 as u64,
			)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => {
		arch::x86_64::kernel::syscall5(
			$arg0 as u64,
			$arg1 as u64,
			$arg2 as u64,
			$arg3 as u64,
			$arg4 as u64,
			$arg5 as u64,
			)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr) => {
		arch::x86_64::kernel::syscall6(
			$arg0 as u64,
			$arg1 as u64,
			$arg2 as u64,
			$arg3 as u64,
			$arg4 as u64,
			$arg5 as u64,
			$arg6 as u64,
			)
	};

	($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr, $arg7:expr) => {
		arch::x86_64::kernel::syscall7(
			$arg0 as u64,
			$arg1 as u64,
			$arg2 as u64,
			$arg3 as u64,
			$arg4 as u64,
			$arg5 as u64,
			$arg6 as u64,
			$arg7 as u64,
			)
	};
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall0(arg0: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall" : "={rax}" (ret) : "{rax}" (arg0) : "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall1(arg0: u64, arg1: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1)
						: "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall2(arg0: u64, arg1: u64, arg2: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2)
						: "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall3(arg0: u64, arg1: u64, arg2: u64, arg3: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2),
						"{rdx}" (arg3) : "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall4(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret)
						: "{rax}"  (arg0), "{rdi}"  (arg1), "{rsi}"  (arg2), "{rdx}"  (arg3),
						"{r10}"  (arg4) : "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall5(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret)
						: "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2), "{rdx}" (arg3),
						"{r10}" (arg4), "{r8}" (arg5) : "rcx", "r11", "memory" : "volatile");
	}
	ret
}

#[inline(always)]
#[allow(unused_mut)]
pub fn syscall6(
	arg0: u64,
	arg1: u64,
	arg2: u64,
	arg3: u64,
	arg4: u64,
	arg5: u64,
	arg6: u64,
) -> u64 {
	let mut ret: u64;
	unsafe {
		llvm_asm!("syscall"	: "={rax}" (ret) : "{rax}" (arg0), "{rdi}" (arg1), "{rsi}" (arg2),
						"{rdx}" (arg3), "{r10}" (arg4), "{r8}" (arg5), "{r9}" (arg6)
						: "rcx", "r11", "memory" : "volatile");
	}
	ret
}

/// Initialize module, must be called once, and only once
pub fn init() {
	processor::init();
	gdt::init();
	irq::init();
	pit::init();
}
<|endoftext|>


<commit_before>//! Core type for communicated a collection of `D: Data` records.
//!
//! `Message<D>` is meant to be treated as a `Vec<D>`, with the caveat that it may wrap either
//! typed `Vec<D>` data or binary `Vec<u8>` data that have not yet been deserialized. The type
//! implements `Deref` and `DerefMut` with `Target = Vec<D>`, whose implementations accommodate
//! the possibly serialized representation.
use serialization::Serializable;
use std::ops::{Deref, DerefMut};

pub struct Message<D> {
    contents: Contents<D>,
}

enum Contents<D> {
    Bytes(Vec<u8>, usize, usize),  // bytes[offset..] decodes to length elements
    Typed(Vec<D>),
}

/// ALLOC : This Drop implementation gets *very* angry if we drop allocated data.
/// ALLOC : It probably shouldn't be used in practice, but should help track down who is being
/// ALLOC : bad about respecting allocated memory.
// impl<D> Drop for Message<D> {
//     match self.contents {
//         Contents::Bytes(bytes, _, _) => { assert!(bytes.capacity() == 0); }
//         Contents::Typed(typed) => { assert!(typed.capacity() == 0); }
//     }
// }

impl<D> Message<D> {
    /// Default number of elements in a typed allocated message. This could vary as a function of
    /// `std::mem::size_of::<D>()`, so is left as a method rather than a constant.
    pub fn default_length() -> usize { 4096 }

    /// Constructs a `Message` from typed data, replacing its argument with `Vec::new()`.
    pub fn from_typed(typed: &mut Vec<D>) -> Message<D> {
        Message { contents: Contents::Typed(::std::mem::replace(typed, Vec::new())) }
    }
    /// The length of the underlying typed vector.
    ///
    /// The length is tracked without needing to deserialize the data, so that this method can be
    /// called even for `D` that do not implement `Serializable`.
    pub fn len(&self) -> usize {
        match self.contents {
            Contents::Bytes(_, _, length) => length,
            Contents::Typed(ref data) => data.len(),
        }
    }
    /// Returns the typed vector, cleared, or a Vec::new() if the data are binary (and drops them
    /// on the floor, I guess! Ouch.
    /// ALLOC : dropping of binary data. likely called only by persons who pushed typed data on,
    /// ALLOC : so perhaps not all that common. Could put a panic! here just for fun! :D
    pub fn into_typed(self) -> Vec<D> {
        match self.contents {
            Contents::Bytes(_,_,_) => Vec::new(),
            Contents::Typed(mut data) => { data.clear(); data },
        }
    }

    // pub fn test_capacity(&self) {
    //     if let Contents::Typed(ref data) = self.contents {
    //         assert!(data.capacity() == 0 || data.capacity() == Message::<D>::default_length());
    //     }
    // }
}

impl<D: Serializable> Message<D> {
    /// Constructs a `Message` from binary data, starting at `offset` in `bytes`.
    ///
    /// This method calls `decode` on the binary data, ensuring that pointers are properly
    /// adjusted, and that future calls to `verify` should succeed.
    pub fn from_bytes(mut bytes: Vec<u8>, offset: usize) -> Message<D> {
        let length = <Vec<D> as Serializable>::decode(&mut bytes[offset..]).unwrap().0.len();
        Message { contents: Contents::Bytes(bytes, offset, length) }
    }
}

impl<D: Serializable> Deref for Message<D> {
    type Target = Vec<D>;
    fn deref(&self) -> &Vec<D> {
        match self.contents {
            // NOTE : decoded in Contents::Byte constructor. verification should pass.
            // NOTE : privacy of Contents should mean cannot construct w/o validation.
            Contents::Bytes(ref bytes, offset, _length) => {
                <Vec<D> as Serializable>::verify(&bytes[offset..]).unwrap().0
            },
            Contents::Typed(ref data) => data,
        }
    }
}

// TODO : Rather than .clone() the decoded data, we should try and re-rig serialization so that the
// TODO : underlying byte array can just be handed to Vec::from_raw_parts, cloning any owned data.
// TODO : I think we would need to make sure that the byte array had the right alignment, so that
// TODO : when the Vec is eventually dropped we don't de-allocate the wrong number of bytes.
// TODO : This require mucking with the Abomonation code, as it doesn't currently let you step in
// TODO : and skip copying the 24 byte Vec struct first. We'd also have to bake in the typed length
// TODO : somewhere outside of this serialized hunk of data.
impl<D: Clone+Serializable> DerefMut for Message<D> {
    fn deref_mut(&mut self) -> &mut Vec<D> {
        let value = if let Contents::Bytes(ref mut bytes, offset, _length) = self.contents {
            let (data, _) = <Vec<D> as Serializable>::decode(&mut bytes[offset..]).unwrap();
            // ALLOC : clone() will allocate a Vec<D> and maybe more.
            Some(Contents::Typed((*data).clone()))
        }
        else { None };

        if let Some(contents) = value {
            self.contents = contents;
        }

        if let Contents::Typed(ref mut data) = self.contents {
            data
        }
        else { unreachable!() }
    }
}
<commit_msg>decode -> verify<commit_after>//! Core type for communicated a collection of `D: Data` records.
//!
//! `Message<D>` is meant to be treated as a `Vec<D>`, with the caveat that it may wrap either
//! typed `Vec<D>` data or binary `Vec<u8>` data that have not yet been deserialized. The type
//! implements `Deref` and `DerefMut` with `Target = Vec<D>`, whose implementations accommodate
//! the possibly serialized representation.
use serialization::Serializable;
use std::ops::{Deref, DerefMut};

pub struct Message<D> {
    contents: Contents<D>,
}

enum Contents<D> {
    Bytes(Vec<u8>, usize, usize),  // bytes[offset..] decodes to length elements
    Typed(Vec<D>),
}

/// ALLOC : This Drop implementation gets *very* angry if we drop allocated data.
/// ALLOC : It probably shouldn't be used in practice, but should help track down who is being
/// ALLOC : bad about respecting allocated memory.
// impl<D> Drop for Message<D> {
//     match self.contents {
//         Contents::Bytes(bytes, _, _) => { assert!(bytes.capacity() == 0); }
//         Contents::Typed(typed) => { assert!(typed.capacity() == 0); }
//     }
// }

impl<D> Message<D> {
    /// Default number of elements in a typed allocated message. This could vary as a function of
    /// `std::mem::size_of::<D>()`, so is left as a method rather than a constant.
    pub fn default_length() -> usize { 4096 }

    /// Constructs a `Message` from typed data, replacing its argument with `Vec::new()`.
    pub fn from_typed(typed: &mut Vec<D>) -> Message<D> {
        Message { contents: Contents::Typed(::std::mem::replace(typed, Vec::new())) }
    }
    /// The length of the underlying typed vector.
    ///
    /// The length is tracked without needing to deserialize the data, so that this method can be
    /// called even for `D` that do not implement `Serializable`.
    pub fn len(&self) -> usize {
        match self.contents {
            Contents::Bytes(_, _, length) => length,
            Contents::Typed(ref data) => data.len(),
        }
    }
    /// Returns the typed vector, cleared, or a Vec::new() if the data are binary (and drops them
    /// on the floor, I guess! Ouch.
    /// ALLOC : dropping of binary data. likely called only by persons who pushed typed data on,
    /// ALLOC : so perhaps not all that common. Could put a panic! here just for fun! :D
    pub fn into_typed(self) -> Vec<D> {
        match self.contents {
            Contents::Bytes(_,_,_) => Vec::new(),
            Contents::Typed(mut data) => { data.clear(); data },
        }
    }

    // pub fn test_capacity(&self) {
    //     if let Contents::Typed(ref data) = self.contents {
    //         assert!(data.capacity() == 0 || data.capacity() == Message::<D>::default_length());
    //     }
    // }
}

impl<D: Serializable> Message<D> {
    /// Constructs a `Message` from binary data, starting at `offset` in `bytes`.
    ///
    /// This method calls `decode` on the binary data, ensuring that pointers are properly
    /// adjusted, and that future calls to `verify` should succeed.
    pub fn from_bytes(mut bytes: Vec<u8>, offset: usize) -> Message<D> {
        let length = <Vec<D> as Serializable>::decode(&mut bytes[offset..]).unwrap().0.len();
        Message { contents: Contents::Bytes(bytes, offset, length) }
    }
}

impl<D: Serializable> Deref for Message<D> {
    type Target = Vec<D>;
    fn deref(&self) -> &Vec<D> {
        match self.contents {
            // NOTE : decoded in Contents::Byte constructor. verification should pass.
            // NOTE : privacy of Contents should mean cannot construct w/o validation.
            Contents::Bytes(ref bytes, offset, _length) => {
                <Vec<D> as Serializable>::verify(&bytes[offset..]).unwrap().0
            },
            Contents::Typed(ref data) => data,
        }
    }
}

// TODO : Rather than .clone() the decoded data, we should try and re-rig serialization so that the
// TODO : underlying byte array can just be handed to Vec::from_raw_parts, cloning any owned data.
// TODO : I think we would need to make sure that the byte array had the right alignment, so that
// TODO : when the Vec is eventually dropped we don't de-allocate the wrong number of bytes.
// TODO : This require mucking with the Abomonation code, as it doesn't currently let you step in
// TODO : and skip copying the 24 byte Vec struct first. We'd also have to bake in the typed length
// TODO : somewhere outside of this serialized hunk of data.
impl<D: Clone+Serializable> DerefMut for Message<D> {
    fn deref_mut(&mut self) -> &mut Vec<D> {
        let value = if let Contents::Bytes(ref mut bytes, offset, _length) = self.contents {
            let (data, _) = <Vec<D> as Serializable>::verify(&bytes[offset..]).unwrap();
            // ALLOC : clone() will allocate a Vec<D> and maybe more.
            Some(Contents::Typed((*data).clone()))
        }
        else { None };

        if let Some(contents) = value {
            self.contents = contents;
        }

        if let Contents::Typed(ref mut data) = self.contents {
            data
        }
        else { unreachable!() }
    }
}
<|endoftext|>


<commit_before>// Extracting metadata from crate files

import driver::session;
import syntax::{ast, ast_util};
import lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
import front::attr;
import middle::resolve;
import syntax::visit;
import syntax::codemap::span;
import back::x86;
import util::{common, filesearch};
import std::{vec, str, fs, io, option};
import std::option::{none, some};
import std::map::{hashmap, new_int_hash};
import syntax::print::pprust;
import common::*;

export read_crates;
export list_file_metadata;

// Traverses an AST, reading all the information about use'd crates and native
// libraries necessary for later resolving, typechecking, linking, etc.
fn read_crates(sess: session::session, crate: ast::crate) {
    let e =
        @{sess: sess,
          crate_cache: @std::map::new_str_hash::<int>(),
          mutable next_crate_num: 1};
    let v =
        visit::mk_simple_visitor(@{visit_view_item:
                                       bind visit_view_item(e, _),
                                   visit_item: bind visit_item(e, _)
                                      with *visit::default_simple_visitor()});
    visit::visit_crate(crate, (), v);
}

type env =
    @{sess: session::session,
      crate_cache: @hashmap<str, int>,
      mutable next_crate_num: ast::crate_num};

fn visit_view_item(e: env, i: @ast::view_item) {
    alt i.node {
      ast::view_item_use(ident, meta_items, id) {
        let cnum = resolve_crate(e, ident, meta_items, i.span);
        cstore::add_use_stmt_cnum(e.sess.get_cstore(), id, cnum);
      }
      _ { }
    }
}

fn visit_item(e: env, i: @ast::item) {
    alt i.node {
      ast::item_native_mod(m) {
        if m.abi != ast::native_abi_rust && m.abi != ast::native_abi_cdecl &&
                m.abi != ast::native_abi_c_stack_cdecl &&
                m.abi != ast::native_abi_c_stack_stdcall {
            ret;
        }
        let cstore = e.sess.get_cstore();
        if !cstore::add_used_library(cstore, m.native_name) { ret; }
        for a: ast::attribute in
            attr::find_attrs_by_name(i.attrs, "link_args") {

            alt attr::get_meta_item_value_str(attr::attr_meta(a)) {
              some(linkarg) { cstore::add_used_link_args(cstore, linkarg); }
              none. {/* fallthrough */ }
            }
        }
      }
      _ { }
    }
}

// A diagnostic function for dumping crate metadata to an output stream
fn list_file_metadata(path: str, out: io::writer) {
    alt get_metadata_section(path) {
      option::some(bytes) { decoder::list_crate_metadata(bytes, out); }
      option::none. {
        out.write_str("Could not find metadata in " + path + ".\n");
      }
    }
}

fn metadata_matches(crate_data: @[u8], metas: [@ast::meta_item]) -> bool {
    let attrs = decoder::get_crate_attributes(crate_data);
    let linkage_metas = attr::find_linkage_metas(attrs);

    log #fmt["matching %u metadata requirements against %u items",
             vec::len(metas), vec::len(linkage_metas)];

    for needed: @ast::meta_item in metas {
        if !attr::contains(linkage_metas, needed) {
            log #fmt["missing %s", pprust::meta_item_to_str(*needed)];
            ret false;
        }
    }
    ret true;
}

fn default_native_lib_naming(sess: session::session, static: bool) ->
   {prefix: str, suffix: str} {
    if static { ret {prefix: "lib", suffix: ".rlib"}; }
    alt sess.get_targ_cfg().os {
      session::os_win32. { ret {prefix: "", suffix: ".dll"}; }
      session::os_macos. { ret {prefix: "lib", suffix: ".dylib"}; }
      session::os_linux. { ret {prefix: "lib", suffix: ".so"}; }
    }
}

fn find_library_crate(sess: session::session, ident: ast::ident,
                      metas: [@ast::meta_item])
   -> option::t<{ident: str, data: @[u8]}> {

    attr::require_unique_names(sess, metas);

    let crate_name =
        {
            let name_items = attr::find_meta_items_by_name(metas, "name");
            alt vec::last(name_items) {
              some(i) {
                alt attr::get_meta_item_value_str(i) {
                  some(n) { n }
                  // FIXME: Probably want a warning here since the user
                  // is using the wrong type of meta item
                  _ { ident }
                }
              }
              none. { ident }
            }
        };

    let nn = default_native_lib_naming(sess, sess.get_opts().static);
    let x =
        find_library_crate_aux(nn, crate_name, metas,
                               sess.filesearch());
    if x != none || sess.get_opts().static { ret x; }
    let nn2 = default_native_lib_naming(sess, true);
    ret find_library_crate_aux(nn2, crate_name, metas,
                               sess.filesearch());
}

fn find_library_crate_aux(nn: {prefix: str, suffix: str}, crate_name: str,
                          metas: [@ast::meta_item],
                          filesearch: filesearch::filesearch) ->
   option::t<{ident: str, data: @[u8]}> {
    let prefix: str = nn.prefix + crate_name;
    let suffix: str = nn.suffix;

    ret filesearch::search(filesearch, { |path|
        let f: str = fs::basename(path);
        if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
            log #fmt["skipping %s, doesn't look like %s*%s", path, prefix,
                     suffix];
            option::none
        } else {
            alt get_metadata_section(path) {
              option::some(cvec) {
                if !metadata_matches(cvec, metas) {
                    log #fmt["skipping %s, metadata doesn't match", path];
                    option::none
                } else {
                    log #fmt["found %s with matching metadata", path];
                    option::some({ident: path, data: cvec})
                }
              }
              _ { option::none }
            }
        }
    });
}

fn get_metadata_section(filename: str) -> option::t<@[u8]> unsafe {
    let mb = str::as_buf(filename, {|buf|
        llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
                                   });
    if mb as int == 0 { ret option::none::<@[u8]>; }
    let of = mk_object_file(mb);
    let si = mk_section_iter(of.llof);
    while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
        let name_buf = llvm::LLVMGetSectionName(si.llsi);
        let name = str::str_from_cstr(name_buf);
        if str::eq(name, x86::get_meta_sect_name()) {
            let cbuf = llvm::LLVMGetSectionContents(si.llsi);
            let csz = llvm::LLVMGetSectionSize(si.llsi);
            let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf);
            ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz));
        }
        llvm::LLVMMoveToNextSection(si.llsi);
    }
    ret option::none::<@[u8]>;
}

fn load_library_crate(sess: session::session, span: span, ident: ast::ident,
                      metas: [@ast::meta_item])
   -> {ident: str, data: @[u8]} {

    alt find_library_crate(sess, ident, metas) {
      some(t) { ret t; }
      none. {
        sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]);
      }
    }
}

fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item],
                 span: span) -> ast::crate_num {
    if !e.crate_cache.contains_key(ident) {
        let cinfo =
            load_library_crate(e.sess, span, ident, metas);

        let cfilename = cinfo.ident;
        let cdata = cinfo.data;

        // Claim this crate number and cache it
        let cnum = e.next_crate_num;
        e.crate_cache.insert(ident, cnum);
        e.next_crate_num += 1;

        // Now resolve the crates referenced by this crate
        let cnum_map = resolve_crate_deps(e, cdata);

        let cmeta = {name: ident, data: cdata, cnum_map: cnum_map};

        let cstore = e.sess.get_cstore();
        cstore::set_crate_data(cstore, cnum, cmeta);
        cstore::add_used_crate_file(cstore, cfilename);
        ret cnum;
    } else { ret e.crate_cache.get(ident); }
}

// Go through the crate metadata and load any crates that it references
fn resolve_crate_deps(e: env, cdata: @[u8]) -> cstore::cnum_map {
    log "resolving deps of external crate";
    // The map from crate numbers in the crate we're resolving to local crate
    // numbers
    let cnum_map = new_int_hash::<ast::crate_num>();
    for dep: decoder::crate_dep in decoder::get_crate_deps(cdata) {
        let extrn_cnum = dep.cnum;
        let cname = dep.ident;
        log #fmt["resolving dep %s", cname];
        if e.crate_cache.contains_key(cname) {
            log "already have it";
            // We've already seen this crate
            let local_cnum = e.crate_cache.get(cname);
            cnum_map.insert(extrn_cnum, local_cnum);
        } else {
            log "need to load it";
            // This is a new one so we've got to load it
            // FIXME: Need better error reporting than just a bogus span
            let fake_span = ast_util::dummy_sp();
            let local_cnum = resolve_crate(e, cname, [], fake_span);
            cnum_map.insert(extrn_cnum, local_cnum);
        }
    }
    ret cnum_map;
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Add more logging to crate resolution<commit_after>// Extracting metadata from crate files

import driver::session;
import syntax::{ast, ast_util};
import lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
import front::attr;
import middle::resolve;
import syntax::visit;
import syntax::codemap::span;
import back::x86;
import util::{common, filesearch};
import std::{vec, str, fs, io, option};
import std::option::{none, some};
import std::map::{hashmap, new_int_hash};
import syntax::print::pprust;
import common::*;

export read_crates;
export list_file_metadata;

// Traverses an AST, reading all the information about use'd crates and native
// libraries necessary for later resolving, typechecking, linking, etc.
fn read_crates(sess: session::session, crate: ast::crate) {
    let e =
        @{sess: sess,
          crate_cache: @std::map::new_str_hash::<int>(),
          mutable next_crate_num: 1};
    let v =
        visit::mk_simple_visitor(@{visit_view_item:
                                       bind visit_view_item(e, _),
                                   visit_item: bind visit_item(e, _)
                                      with *visit::default_simple_visitor()});
    visit::visit_crate(crate, (), v);
}

type env =
    @{sess: session::session,
      crate_cache: @hashmap<str, int>,
      mutable next_crate_num: ast::crate_num};

fn visit_view_item(e: env, i: @ast::view_item) {
    alt i.node {
      ast::view_item_use(ident, meta_items, id) {
        let cnum = resolve_crate(e, ident, meta_items, i.span);
        cstore::add_use_stmt_cnum(e.sess.get_cstore(), id, cnum);
      }
      _ { }
    }
}

fn visit_item(e: env, i: @ast::item) {
    alt i.node {
      ast::item_native_mod(m) {
        if m.abi != ast::native_abi_rust && m.abi != ast::native_abi_cdecl &&
                m.abi != ast::native_abi_c_stack_cdecl &&
                m.abi != ast::native_abi_c_stack_stdcall {
            ret;
        }
        let cstore = e.sess.get_cstore();
        if !cstore::add_used_library(cstore, m.native_name) { ret; }
        for a: ast::attribute in
            attr::find_attrs_by_name(i.attrs, "link_args") {

            alt attr::get_meta_item_value_str(attr::attr_meta(a)) {
              some(linkarg) { cstore::add_used_link_args(cstore, linkarg); }
              none. {/* fallthrough */ }
            }
        }
      }
      _ { }
    }
}

// A diagnostic function for dumping crate metadata to an output stream
fn list_file_metadata(path: str, out: io::writer) {
    alt get_metadata_section(path) {
      option::some(bytes) { decoder::list_crate_metadata(bytes, out); }
      option::none. {
        out.write_str("Could not find metadata in " + path + ".\n");
      }
    }
}

fn metadata_matches(crate_data: @[u8], metas: [@ast::meta_item]) -> bool {
    let attrs = decoder::get_crate_attributes(crate_data);
    let linkage_metas = attr::find_linkage_metas(attrs);

    log #fmt["matching %u metadata requirements against %u items",
             vec::len(metas), vec::len(linkage_metas)];

    log #fmt("crate metadata:");
    for have: @ast::meta_item in linkage_metas {
        log #fmt("  %s", pprust::meta_item_to_str(*have));
    }

    for needed: @ast::meta_item in metas {
        log #fmt["looking for %s", pprust::meta_item_to_str(*needed)];
        if !attr::contains(linkage_metas, needed) {
            log #fmt["missing %s", pprust::meta_item_to_str(*needed)];
            ret false;
        }
    }
    ret true;
}

fn default_native_lib_naming(sess: session::session, static: bool) ->
   {prefix: str, suffix: str} {
    if static { ret {prefix: "lib", suffix: ".rlib"}; }
    alt sess.get_targ_cfg().os {
      session::os_win32. { ret {prefix: "", suffix: ".dll"}; }
      session::os_macos. { ret {prefix: "lib", suffix: ".dylib"}; }
      session::os_linux. { ret {prefix: "lib", suffix: ".so"}; }
    }
}

fn find_library_crate(sess: session::session, ident: ast::ident,
                      metas: [@ast::meta_item])
   -> option::t<{ident: str, data: @[u8]}> {

    attr::require_unique_names(sess, metas);

    let crate_name =
        {
            let name_items = attr::find_meta_items_by_name(metas, "name");
            alt vec::last(name_items) {
              some(i) {
                alt attr::get_meta_item_value_str(i) {
                  some(n) { n }
                  // FIXME: Probably want a warning here since the user
                  // is using the wrong type of meta item
                  _ { ident }
                }
              }
              none. { ident }
            }
        };

    let nn = default_native_lib_naming(sess, sess.get_opts().static);
    let x =
        find_library_crate_aux(nn, crate_name, metas,
                               sess.filesearch());
    if x != none || sess.get_opts().static { ret x; }
    let nn2 = default_native_lib_naming(sess, true);
    ret find_library_crate_aux(nn2, crate_name, metas,
                               sess.filesearch());
}

fn find_library_crate_aux(nn: {prefix: str, suffix: str}, crate_name: str,
                          metas: [@ast::meta_item],
                          filesearch: filesearch::filesearch) ->
   option::t<{ident: str, data: @[u8]}> {
    let prefix: str = nn.prefix + crate_name;
    let suffix: str = nn.suffix;

    ret filesearch::search(filesearch, { |path|
        log #fmt("inspecting file %s", path);
        let f: str = fs::basename(path);
        if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
            log #fmt["skipping %s, doesn't look like %s*%s", path, prefix,
                     suffix];
            option::none
        } else {
            log #fmt("%s is a candidate", path);
            alt get_metadata_section(path) {
              option::some(cvec) {
                if !metadata_matches(cvec, metas) {
                    log #fmt["skipping %s, metadata doesn't match", path];
                    option::none
                } else {
                    log #fmt["found %s with matching metadata", path];
                    option::some({ident: path, data: cvec})
                }
              }
              _ {
                log #fmt("could not load metadata for %s", path);
                option::none
              }
            }
        }
    });
}

fn get_metadata_section(filename: str) -> option::t<@[u8]> unsafe {
    let mb = str::as_buf(filename, {|buf|
        llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
                                   });
    if mb as int == 0 { ret option::none::<@[u8]>; }
    let of = mk_object_file(mb);
    let si = mk_section_iter(of.llof);
    while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
        let name_buf = llvm::LLVMGetSectionName(si.llsi);
        let name = str::str_from_cstr(name_buf);
        if str::eq(name, x86::get_meta_sect_name()) {
            let cbuf = llvm::LLVMGetSectionContents(si.llsi);
            let csz = llvm::LLVMGetSectionSize(si.llsi);
            let cvbuf: *u8 = std::unsafe::reinterpret_cast(cbuf);
            ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz));
        }
        llvm::LLVMMoveToNextSection(si.llsi);
    }
    ret option::none::<@[u8]>;
}

fn load_library_crate(sess: session::session, span: span, ident: ast::ident,
                      metas: [@ast::meta_item])
   -> {ident: str, data: @[u8]} {

    alt find_library_crate(sess, ident, metas) {
      some(t) { ret t; }
      none. {
        sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]);
      }
    }
}

fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item],
                 span: span) -> ast::crate_num {
    if !e.crate_cache.contains_key(ident) {
        let cinfo =
            load_library_crate(e.sess, span, ident, metas);

        let cfilename = cinfo.ident;
        let cdata = cinfo.data;

        // Claim this crate number and cache it
        let cnum = e.next_crate_num;
        e.crate_cache.insert(ident, cnum);
        e.next_crate_num += 1;

        // Now resolve the crates referenced by this crate
        let cnum_map = resolve_crate_deps(e, cdata);

        let cmeta = {name: ident, data: cdata, cnum_map: cnum_map};

        let cstore = e.sess.get_cstore();
        cstore::set_crate_data(cstore, cnum, cmeta);
        cstore::add_used_crate_file(cstore, cfilename);
        ret cnum;
    } else { ret e.crate_cache.get(ident); }
}

// Go through the crate metadata and load any crates that it references
fn resolve_crate_deps(e: env, cdata: @[u8]) -> cstore::cnum_map {
    log "resolving deps of external crate";
    // The map from crate numbers in the crate we're resolving to local crate
    // numbers
    let cnum_map = new_int_hash::<ast::crate_num>();
    for dep: decoder::crate_dep in decoder::get_crate_deps(cdata) {
        let extrn_cnum = dep.cnum;
        let cname = dep.ident;
        log #fmt["resolving dep %s", cname];
        if e.crate_cache.contains_key(cname) {
            log "already have it";
            // We've already seen this crate
            let local_cnum = e.crate_cache.get(cname);
            cnum_map.insert(extrn_cnum, local_cnum);
        } else {
            log "need to load it";
            // This is a new one so we've got to load it
            // FIXME: Need better error reporting than just a bogus span
            let fake_span = ast_util::dummy_sp();
            let local_cnum = resolve_crate(e, cname, [], fake_span);
            cnum_map.insert(extrn_cnum, local_cnum);
        }
    }
    ret cnum_map;
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use super::{ASTNode, SymbolTable};

use std::rc::Rc;
use std::borrow::Borrow;
use std::hash::Hash;

// pub type STCell<'a> = Rc<RefCell<SymbolTable<'a>>>;

pub struct Annotated<'a, T> where T: ASTNode {
    node: T, scope: Rc<SymbolTable<'a>>
}

impl<'a, T> Annotated<'a, T> where T: ASTNode {

    /// Get the type signature associated with the given name.
    ///
    /// This returns a borrowed reference to the type signature
    /// associated with that name in the current scope. The argument
    /// can be any type `Q` such that `String: Borrow<Q>` (i.e.
    /// you can pass an `&str` to this function).
    pub fn get_type<Q: ?Sized>(&self, name: &Q) -> Option<&Type>
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.get(name)
    }

    /// Check if the given name is defined in this scope.
    ///
    /// The argument can be any type `Q` such that `String: Borrow<Q>`
    /// (i.e. you can pass an `&str` to this function).
    pub fn is_defined_here<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.contains_key(name)
    }

}

#[derive(Debug, Clone)]
pub enum Type { Ref(Reference)
              , Prim(Primitive)
              , Algebraic //TODO: make me a thing
              }

/// Reference types
///
/// TODO: how will lifetime analysis actually work?
#[derive(Debug, Clone)]
pub enum Reference { Borrowed(Box<Type>) // TODO: borrowed from where?
                   , Moved(Box<Type>) // TODO: moved from where?
                   , Owned(Box<Type>)
                   , Raw(Box<Type>)
                   }

#[derive(Debug, Clone, Copy)]
pub enum Primitive { Int
                   , Uint
                   , Byte
                   , Char
                   , Str
                   // TODO: finish
                   }
<commit_msg>Add more types<commit_after>use super::{ASTNode, SymbolTable};

use std::rc::Rc;
use std::borrow::Borrow;
use std::hash::Hash;

// pub type STCell<'a> = Rc<RefCell<SymbolTable<'a>>>;

pub struct Annotated<'a, T> where T: ASTNode {
    node: T, scope: Rc<SymbolTable<'a>>
}

impl<'a, T> Annotated<'a, T> where T: ASTNode {

    /// Get the type signature associated with the given name.
    ///
    /// This returns a borrowed reference to the type signature
    /// associated with that name in the current scope. The argument
    /// can be any type `Q` such that `String: Borrow<Q>` (i.e.
    /// you can pass an `&str` to this function).
    pub fn get_type<Q: ?Sized>(&self, name: &Q) -> Option<&Type>
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.get(name)
    }

    /// Check if the given name is defined in this scope.
    ///
    /// The argument can be any type `Q` such that `String: Borrow<Q>`
    /// (i.e. you can pass an `&str` to this function).
    pub fn is_defined_here<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>, Q: Hash + Eq {
        self.scope.contains_key(name)
    }

}

#[derive(Debug, Clone)]
pub enum Type { Ref(Reference)
              , Prim(Primitive)
              , Algebraic //TODO: make me a thing
              , Function { params: Vec<Type>, rt: Box<Type> }
              }

/// Reference types
///
/// TODO: how will lifetime analysis actually work?
#[derive(Debug, Clone)]
pub enum Reference { Borrowed(Box<Type>) // TODO: borrowed from where?
                   , Moved(Box<Type>) // TODO: moved from where?
                   , Owned(Box<Type>)
                   , Raw(Box<Type>)
                   }

#[derive(Debug, Clone)]
pub enum Primitive { Int
                   , Uint
                   , Byte
                   , Char
                   , Str
                   , Bool
                   , Symbol(String)
                   // TODO: finish
                   }
<|endoftext|>


<commit_before>use operations::scope::ScopeStack;

pub fn populate_scope(scope: &mut ScopeStack) {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let array_type = scope.declare_type(
        Identifier::from("[]"),
        ItemType::Primitive(1)
    );
    scope.set_array_type_id(array_type);
}
<commit_msg>Making array primitive compile and changing the type name to represent its fixed size<commit_after>use parser::Identifier;
use operations::item_type::ItemType;
use operations::scope::ScopeStack;

pub fn populate_scope(scope: &mut ScopeStack) {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let array_type = scope.declare_type(
        Identifier::from("[T; N]"),
        ItemType::Primitive(1)
    );
    scope.set_array_type_id(array_type);
}
<|endoftext|>


<commit_before>use crate::{
    backend::renderer::{Frame, ImportAll, Renderer, Texture},
    desktop::{space::*, utils::*},
    utils::{Logical, Point, Rectangle},
    wayland::output::Output,
};
use std::{
    any::{Any, TypeId},
    hash::{Hash, Hasher},
};
use wayland_server::protocol::wl_surface::WlSurface;

/// Indicates default values for some zindexs inside smithay
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum RenderZindex {
    /// WlrLayer::Background default zindex
    Background = 10,
    /// WlrLayer::Bottom default zindex
    Bottom = 20,
    /// Default zindex for Windows
    Shell = 30,
    /// Default zindex for Windows PopUps
    PopUpsShell = 40,
    /// WlrLayer::Top default zindex
    Top = 50,
    /// Default Layer for RenderElements
    Overlay = 80,
    /// Default Layer for Overlay PopUp
    PopUpsOverlay = 100,
}

/// Elements rendered by [`Space::render_output`] in addition to windows, layers and popups.
pub type DynamicRenderElements<R> =
    Box<dyn RenderElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>>;

pub(super) type SpaceElem<R> =
    dyn SpaceElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>;

/// Trait for custom elements to be rendered during [`Space::render_output`].
pub trait RenderElement<R, F, E, T>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
    Self: Any + 'static,
{
    /// Returns an id unique to this element for the type of Self.
    fn id(&self) -> usize;
    #[doc(hidden)]
    fn type_of(&self) -> TypeId {
        std::any::Any::type_id(self)
    }
    /// Returns the bounding box of this element including its position in the space.
    fn geometry(&self) -> Rectangle<i32, Logical>;
    /// Returns the damage of the element since it's last update.
    /// It should be relative to the elements coordinates.
    ///
    /// If you receive `Some(_)` for `for_values` you may cache that you
    /// send the damage for this `Space` and `Output` combination once
    /// and return an empty vector for subsequent calls until the contents
    /// of this element actually change again for optimization reasons.
    ///
    /// Returning `vec![Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX))]` is always
    /// correct, but very inefficient.
    fn accumulated_damage(
        &self,
        for_values: Option<SpaceOutputTuple<'_, '_>>,
    ) -> Vec<Rectangle<i32, Logical>>;
    /// Draws the element using the provided `Frame` and `Renderer`.
    ///
    /// - `scale` provides the current fractional scale value to render as
    /// - `damage` provides the regions you need to re-draw and *may* not
    ///   be equivalent to the damage returned by `accumulated_damage`.
    ///   Redrawing other parts of the element is not valid and may cause rendering artifacts.
    fn draw(
        &self,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error>;

    /// Returns z_index of RenderElement, reverf too [`RenderZindex`] for default values
    fn z_index(&self) -> u8 {
        RenderZindex::Overlay as u8
    }
}

pub(crate) trait SpaceElement<R, F, E, T>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture,
{
    fn id(&self) -> usize;
    fn type_of(&self) -> TypeId;
    fn location(&self, space_id: usize) -> Point<i32, Logical> {
        self.geometry(space_id).loc
    }
    fn geometry(&self, space_id: usize) -> Rectangle<i32, Logical>;
    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>>;
    #[allow(clippy::too_many_arguments)]
    fn draw(
        &self,
        space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error>;
    fn z_index(&self) -> u8; //{
                             //    0
                             //}
}

impl<R, F, E, T> SpaceElement<R, F, E, T> for Box<dyn RenderElement<R, F, E, T>>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll + 'static,
    F: Frame<Error = E, TextureId = T> + 'static,
    E: std::error::Error + 'static,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        (&**self as &dyn RenderElement<R, F, E, T>).id()
    }
    fn type_of(&self) -> TypeId {
        (&**self as &dyn RenderElement<R, F, E, T>).type_of()
    }
    fn geometry(&self, _space_id: usize) -> Rectangle<i32, Logical> {
        (&**self as &dyn RenderElement<R, F, E, T>).geometry()
    }
    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        (&**self as &dyn RenderElement<R, F, E, T>).accumulated_damage(for_values.map(SpaceOutputTuple::from))
    }
    fn draw(
        &self,
        _space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        _location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        (&**self as &dyn RenderElement<R, F, E, T>).draw(renderer, frame, scale, damage, log)
    }

    fn z_index(&self) -> u8 {
        RenderElement::z_index(self.as_ref())
    }
}

/// Generic helper for drawing [`WlSurface`]s and their subsurfaces
/// as custom elements via [`RenderElement`].
///
/// For example useful for cursor or drag-and-drop surfaces.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
#[derive(Debug)]
pub struct SurfaceTree {
    /// Surface to be drawn
    pub surface: WlSurface,
    /// Position to draw add
    pub position: Point<i32, Logical>,
}

impl<R, F, E, T> RenderElement<R, F, E, T> for SurfaceTree
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        self.surface.as_ref().id() as usize
    }

    fn geometry(&self) -> Rectangle<i32, Logical> {
        let mut bbox = bbox_from_surface_tree(&self.surface, (0, 0));
        bbox.loc += self.position;
        bbox
    }

    fn accumulated_damage(
        &self,
        for_values: Option<SpaceOutputTuple<'_, '_>>,
    ) -> Vec<Rectangle<i32, Logical>> {
        damage_from_surface_tree(&self.surface, (0, 0), for_values.map(|x| (x.0, x.1)))
    }

    fn draw(
        &self,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        crate::backend::renderer::utils::draw_surface_tree(
            renderer,
            frame,
            &self.surface,
            scale,
            self.position,
            damage,
            log,
        )
    }
}

/// Newtype for (&Space, &Output) to provide a `Hash` implementation for damage tracking
#[derive(Debug, PartialEq)]
pub struct SpaceOutputTuple<'a, 'b>(pub &'a Space, pub &'b Output);

impl<'a, 'b> Hash for SpaceOutputTuple<'a, 'b> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.id.hash(state);
        (std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize).hash(state);
    }
}

impl<'a, 'b> SpaceOutputTuple<'a, 'b> {
    /// Returns an owned version that produces and equivalent hash
    pub fn owned_hash(&self) -> SpaceOutputHash {
        SpaceOutputHash(
            self.0.id,
            std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize,
        )
    }
}

impl<'a, 'b> From<(&'a Space, &'b Output)> for SpaceOutputTuple<'a, 'b> {
    fn from((space, output): (&'a Space, &'b Output)) -> SpaceOutputTuple<'a, 'b> {
        SpaceOutputTuple(space, output)
    }
}

/// Type to use as an owned hashable value equal to [`SpaceOutputTuple`]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct SpaceOutputHash(usize, usize);
<commit_msg>remove left over comment from default implemantion for z_index<commit_after>use crate::{
    backend::renderer::{Frame, ImportAll, Renderer, Texture},
    desktop::{space::*, utils::*},
    utils::{Logical, Point, Rectangle},
    wayland::output::Output,
};
use std::{
    any::{Any, TypeId},
    hash::{Hash, Hasher},
};
use wayland_server::protocol::wl_surface::WlSurface;

/// Indicates default values for some zindexs inside smithay
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum RenderZindex {
    /// WlrLayer::Background default zindex
    Background = 10,
    /// WlrLayer::Bottom default zindex
    Bottom = 20,
    /// Default zindex for Windows
    Shell = 30,
    /// Default zindex for Windows PopUps
    PopUpsShell = 40,
    /// WlrLayer::Top default zindex
    Top = 50,
    /// Default Layer for RenderElements
    Overlay = 80,
    /// Default Layer for Overlay PopUp
    PopUpsOverlay = 100,
}

/// Elements rendered by [`Space::render_output`] in addition to windows, layers and popups.
pub type DynamicRenderElements<R> =
    Box<dyn RenderElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>>;

pub(super) type SpaceElem<R> =
    dyn SpaceElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>;

/// Trait for custom elements to be rendered during [`Space::render_output`].
pub trait RenderElement<R, F, E, T>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
    Self: Any + 'static,
{
    /// Returns an id unique to this element for the type of Self.
    fn id(&self) -> usize;
    #[doc(hidden)]
    fn type_of(&self) -> TypeId {
        std::any::Any::type_id(self)
    }
    /// Returns the bounding box of this element including its position in the space.
    fn geometry(&self) -> Rectangle<i32, Logical>;
    /// Returns the damage of the element since it's last update.
    /// It should be relative to the elements coordinates.
    ///
    /// If you receive `Some(_)` for `for_values` you may cache that you
    /// send the damage for this `Space` and `Output` combination once
    /// and return an empty vector for subsequent calls until the contents
    /// of this element actually change again for optimization reasons.
    ///
    /// Returning `vec![Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX))]` is always
    /// correct, but very inefficient.
    fn accumulated_damage(
        &self,
        for_values: Option<SpaceOutputTuple<'_, '_>>,
    ) -> Vec<Rectangle<i32, Logical>>;
    /// Draws the element using the provided `Frame` and `Renderer`.
    ///
    /// - `scale` provides the current fractional scale value to render as
    /// - `damage` provides the regions you need to re-draw and *may* not
    ///   be equivalent to the damage returned by `accumulated_damage`.
    ///   Redrawing other parts of the element is not valid and may cause rendering artifacts.
    fn draw(
        &self,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error>;

    /// Returns z_index of RenderElement, reverf too [`RenderZindex`] for default values
    fn z_index(&self) -> u8 {
        RenderZindex::Overlay as u8
    }
}

pub(crate) trait SpaceElement<R, F, E, T>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture,
{
    fn id(&self) -> usize;
    fn type_of(&self) -> TypeId;
    fn location(&self, space_id: usize) -> Point<i32, Logical> {
        self.geometry(space_id).loc
    }
    fn geometry(&self, space_id: usize) -> Rectangle<i32, Logical>;
    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>>;
    #[allow(clippy::too_many_arguments)]
    fn draw(
        &self,
        space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error>;
    fn z_index(&self) -> u8;
}

impl<R, F, E, T> SpaceElement<R, F, E, T> for Box<dyn RenderElement<R, F, E, T>>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll + 'static,
    F: Frame<Error = E, TextureId = T> + 'static,
    E: std::error::Error + 'static,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        (&**self as &dyn RenderElement<R, F, E, T>).id()
    }
    fn type_of(&self) -> TypeId {
        (&**self as &dyn RenderElement<R, F, E, T>).type_of()
    }
    fn geometry(&self, _space_id: usize) -> Rectangle<i32, Logical> {
        (&**self as &dyn RenderElement<R, F, E, T>).geometry()
    }
    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        (&**self as &dyn RenderElement<R, F, E, T>).accumulated_damage(for_values.map(SpaceOutputTuple::from))
    }
    fn draw(
        &self,
        _space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        _location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        (&**self as &dyn RenderElement<R, F, E, T>).draw(renderer, frame, scale, damage, log)
    }

    fn z_index(&self) -> u8 {
        RenderElement::z_index(self.as_ref())
    }
}

/// Generic helper for drawing [`WlSurface`]s and their subsurfaces
/// as custom elements via [`RenderElement`].
///
/// For example useful for cursor or drag-and-drop surfaces.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
#[derive(Debug)]
pub struct SurfaceTree {
    /// Surface to be drawn
    pub surface: WlSurface,
    /// Position to draw add
    pub position: Point<i32, Logical>,
}

impl<R, F, E, T> RenderElement<R, F, E, T> for SurfaceTree
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        self.surface.as_ref().id() as usize
    }

    fn geometry(&self) -> Rectangle<i32, Logical> {
        let mut bbox = bbox_from_surface_tree(&self.surface, (0, 0));
        bbox.loc += self.position;
        bbox
    }

    fn accumulated_damage(
        &self,
        for_values: Option<SpaceOutputTuple<'_, '_>>,
    ) -> Vec<Rectangle<i32, Logical>> {
        damage_from_surface_tree(&self.surface, (0, 0), for_values.map(|x| (x.0, x.1)))
    }

    fn draw(
        &self,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        crate::backend::renderer::utils::draw_surface_tree(
            renderer,
            frame,
            &self.surface,
            scale,
            self.position,
            damage,
            log,
        )
    }
}

/// Newtype for (&Space, &Output) to provide a `Hash` implementation for damage tracking
#[derive(Debug, PartialEq)]
pub struct SpaceOutputTuple<'a, 'b>(pub &'a Space, pub &'b Output);

impl<'a, 'b> Hash for SpaceOutputTuple<'a, 'b> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.id.hash(state);
        (std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize).hash(state);
    }
}

impl<'a, 'b> SpaceOutputTuple<'a, 'b> {
    /// Returns an owned version that produces and equivalent hash
    pub fn owned_hash(&self) -> SpaceOutputHash {
        SpaceOutputHash(
            self.0.id,
            std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize,
        )
    }
}

impl<'a, 'b> From<(&'a Space, &'b Output)> for SpaceOutputTuple<'a, 'b> {
    fn from((space, output): (&'a Space, &'b Output)) -> SpaceOutputTuple<'a, 'b> {
        SpaceOutputTuple(space, output)
    }
}

/// Type to use as an owned hashable value equal to [`SpaceOutputTuple`]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct SpaceOutputHash(usize, usize);
<|endoftext|>