<commit_before>use std::collections::{BTreeMap, BTreeSet};

#[derive(Debug)]
struct Matrix {
    elems: BTreeMap<char, BTreeMap<char, u32>>,
    keys: BTreeSet<char>,
}

impl Matrix {
    fn new() -> Matrix {
        Matrix {
            elems: BTreeMap::new(),
            keys: BTreeSet::new(),
        }
    }

    fn insert(&mut self, c1: &char, c2: &char, val: u32) {
        let mut ins_map = self.elems.entry(*c1).or_insert_with(BTreeMap::new);
        ins_map.insert(*c2, val);
        self.keys.insert(*c1);
        self.keys.insert(*c2);
    }

    fn len(&self) -> usize {
        self.keys.len()
    }

    fn get_d(&self, c1: &char, c2: &char) -> &u32 {
        match self.elems.get(c1) {
            Some(map) => {
                match map.get(c2) {
                    Some(val) => val,
                    None => &self.elems[c2][c1],
                }
            }
            None => {
                match self.elems.get(c2) {
                    Some(map) => {
                        match map.get(c1) {
                            Some(val) => val,
                            None => panic!("c1 wasn't found"),
                        }
                    }
                    None => panic!("c2 wasn't found"),
                }
            }
        }
    }

    fn s_calculation(&self, c: &char) -> f64 {
        let mut keys = self.keys.clone();
        if keys.remove(c) {
            let mut sum = 0;
            for &key in &keys {
                match self.elems.get(c) {
                    Some(map) => {
                        match map.get(&key) {
                            Some(val) => sum += *val,
                            None => sum += self.elems[&key][c],
                        }
                    }
                    None => sum += self.elems[&key][c],
                }
            }
            sum as f64 / (keys.len() - 1) as f64
        } else {
            panic!("Key not found in matrix");
        }
    }

    fn m_calculation(&self, c1: &char, c2: &char) -> f64 {
        *self.get_d(c1, c2) as f64 - self.s_calculation(c1) - self.s_calculation(c2)
    }

    fn lowest_m(&self) -> (f64, char, char) {
        let mut iter = self.keys.iter();
        let mut key_1 = match iter.next() {
            Some(val) => val,
            None => panic!("No elements in matrix"),
        };

        let mut lowest = (999.9, *key_1, *key_1);

        for key_2 in iter {
            let m = self.m_calculation(key_1, key_2);
            println!("M_{}{} = {}", key_1, key_2, m);

            if lowest.0 > m {
                lowest = (m, *key_1, *key_2);
            }
            key_1 = key_2;
        }

        lowest
    }

    fn join(&mut self, k1: &char, k2: &char, k: &char) -> Matrix {
        if !(self.keys.contains(k1) || self.keys.contains(k2)) {
            panic!("Keys aren't in matrix");
        }
        /********************************************************************/
        let d_12_2 = *self.get_d(k1, k2) as f64 / 2.0;
        let s_1 = self.s_calculation(k1);
        let s_2 = self.s_calculation(k2);
        println!("S_{}{} = {}", k1, k, d_12_2 + (s_1 - s_2) / 2.0);
        println!("S_{}{} = {}", k2, k, d_12_2 + (s_2 - s_1) / 2.0);
        /********************************************************************/
        let mut elems = self.elems.clone();
        elems.remove(k1);
        elems.remove(k2);

        let mut keys = self.keys.clone();
        keys.remove(k1);
        keys.remove(k2);
        let rem_keys = keys.clone();

        let mut ret_m = Matrix {
            elems: elems,
            keys: keys
        };

        for key in rem_keys {
            let val = self.get_d(k1, &key) + self.get_d(k2, &key) - self.get_d(k1, k2);
            ret_m.insert(k, &key, val / 2);
        }

        ret_m
    }

    fn print_matrix(&self) {
        println!("{:#?}", self.elems);
    }

    fn print_s_calculations(&self) {
        for &key in &self.keys {
            println!("S_{} = {}", key, self.s_calculation(&key));
        }
    }
}

fn neighbor_joining(input: &[(char, char, u32)]) {
    let mut matrix = Matrix::new();

    for &(c1, c2, val) in input {
        matrix.insert(&c1, &c2, val);
    }

    let mut letter: u8 = 49; // 85; // 'U'

    while matrix.len() - 2 > 0 {
        matrix.print_matrix();
        matrix.print_s_calculations();
        let (_, key_1, key_2) = matrix.lowest_m();
        println!("Joining: {} and {}", key_1, key_2);
        matrix = matrix.join(&key_1, &key_2, &char::from(letter));
        letter += 1;
    }
    matrix.print_matrix();
}

fn main() {
    let input = vec![('A', 'B', 5),
                     ('A', 'C', 4),
                     ('A', 'D', 7),
                     ('A', 'E', 6),
                     ('A', 'F', 8),
                     ('B', 'C', 7),
                     ('B', 'D', 10),
                     ('B', 'E', 9),
                     ('B', 'F', 11),
                     ('C', 'D', 7),
                     ('C', 'E', 6),
                     ('C', 'F', 8),
                     ('D', 'E', 5),
                     ('D', 'F', 9),
                     ('E', 'F', 8)];

    neighbor_joining(&input);
}
<commit_msg>Finished practica 20<commit_after>use std::collections::{BTreeMap, BTreeSet};

#[derive(Debug)]
struct Matrix {
    elems: BTreeMap<char, BTreeMap<char, u32>>,
    keys: BTreeSet<char>,
}

impl Matrix {
    fn new() -> Matrix {
        Matrix {
            elems: BTreeMap::new(),
            keys: BTreeSet::new(),
        }
    }

    fn insert(&mut self, c1: &char, c2: &char, val: u32) {
        let mut ins_map = self.elems.entry(*c1).or_insert_with(BTreeMap::new);
        ins_map.insert(*c2, val);
        self.keys.insert(*c1);
        self.keys.insert(*c2);
    }

    fn len(&self) -> usize {
        self.keys.len()
    }

    fn get_d(&self, c1: &char, c2: &char) -> &u32 {
        match self.elems.get(c1) {
            Some(map) => {
                match map.get(c2) {
                    Some(val) => val,
                    None => &self.elems[c2][c1],
                }
            }
            None => {
                match self.elems.get(c2) {
                    Some(map) => {
                        match map.get(c1) {
                            Some(val) => val,
                            None => panic!("c1 wasn't found"),
                        }
                    }
                    None => panic!("c2 wasn't found"),
                }
            }
        }
    }

    fn s_calculation(&self, c: &char) -> f64 {
        let mut keys = self.keys.clone();
        if keys.remove(c) {
            let mut sum = 0;
            for &key in &keys {
                match self.elems.get(c) {
                    Some(map) => {
                        match map.get(&key) {
                            Some(val) => sum += *val,
                            None => sum += self.elems[&key][c],
                        }
                    }
                    None => sum += self.elems[&key][c],
                }
            }
            sum as f64 / (keys.len() - 1) as f64
        } else {
            panic!("Key not found in matrix");
        }
    }

    fn m_calculation(&self, c1: &char, c2: &char) -> f64 {
        *self.get_d(c1, c2) as f64 - self.s_calculation(c1) - self.s_calculation(c2)
    }

    fn lowest_m(&self) -> (f64, char, char) {
        let mut iter = self.keys.iter();
        let mut key_1 = match iter.next() {
            Some(val) => val,
            None => panic!("No elements in matrix"),
        };

        let mut lowest = (999.9, *key_1, *key_1);

        for key_2 in iter {
            let m = self.m_calculation(key_1, key_2);
            println!("M_{}{} = {}", key_1, key_2, m);

            if lowest.0 > m {
                lowest = (m, *key_1, *key_2);
            }
            key_1 = key_2;
        }

        lowest
    }

    fn join(&mut self, k1: &char, k2: &char, k: &char) -> Matrix {
        if !(self.keys.contains(k1) || self.keys.contains(k2)) {
            panic!("Keys aren't in matrix");
        }
        /********************************************************************/
        let d_12_2 = *self.get_d(k1, k2) as f64 / 2.0;
        let s_1 = self.s_calculation(k1);
        let s_2 = self.s_calculation(k2);
        println!("S_{}{} = {}", k1, k, d_12_2 + (s_1 - s_2) / 2.0);
        println!("S_{}{} = {}", k2, k, d_12_2 + (s_2 - s_1) / 2.0);
        /********************************************************************/
        let mut elems = self.elems.clone();
        elems.remove(k1);
        elems.remove(k2);
        for (_, val) in &mut elems {
            val.remove(k1);
            val.remove(k2);
        }

        let mut keys = self.keys.clone();
        keys.remove(k1);
        keys.remove(k2);
        let rem_keys = keys.clone();

        let mut ret_m = Matrix {
            elems: elems,
            keys: keys,
        };

        for key in rem_keys {
            let val = self.get_d(k1, &key) + self.get_d(k2, &key) - self.get_d(k1, k2);
            ret_m.insert(k, &key, val / 2);
        }

        ret_m
    }

    fn print_matrix(&self) {
        for (key, val) in &self.elems {
            println!("{}: {:?}", key, val);
        }
    }

    fn print_s_calculations(&self) {
        for &key in &self.keys {
            println!("S_{} = {}", key, self.s_calculation(&key));
        }
    }
}

fn neighbor_joining(input: &[(char, char, u32)]) {
    let mut matrix = Matrix::new();

    for &(c1, c2, val) in input {
        matrix.insert(&c1, &c2, val);
    }

    let mut letter: u8 = 49; // 85; // 'U'

    while matrix.len() - 2 > 0 {
        matrix.print_matrix();
        println!("");
        matrix.print_s_calculations();
        println!("");
        let (_, key_1, key_2) = matrix.lowest_m();
        println!("\nJoining: {} and {}", key_1, key_2);
        matrix = matrix.join(&key_1, &key_2, &char::from(letter));
        letter += 1;
    }
    matrix.print_matrix();
}

fn main() {
    let input = vec![('A', 'B', 5),
                     ('A', 'C', 4),
                     ('A', 'D', 7),
                     ('A', 'E', 6),
                     ('A', 'F', 8),
                     ('B', 'C', 7),
                     ('B', 'D', 10),
                     ('B', 'E', 9),
                     ('B', 'F', 11),
                     ('C', 'D', 7),
                     ('C', 'E', 6),
                     ('C', 'F', 8),
                     ('D', 'E', 5),
                     ('D', 'F', 9),
                     ('E', 'F', 8)];

    neighbor_joining(&input);
}
<|endoftext|>


<commit_before>use crate::{Point3D, StrError, Vector3D};

/// Computes the distance between a point and this segment
///
/// ```text
///                 c
///                /^
/// ⇀             / | ⇀   ⇀   ⇀
/// x = vec(c-a) /  | q = x - p
///             /   |
///            /    |
///           a----->-------------b
///             ⇀              ⇀
///             p = projection(x)
///
///           a-------------------b
///               ⇀
///               n = vec(b-c)
/// ```
///
/// ```text
/// x := c - a
/// n := b - a
/// p := ((x ⋅ n) / (n ⋅ n)) * n
/// q := x - p
/// distance := norm(q)
/// ```
pub fn point_segment_distance_3d(a: &Point3D, b: &Point3D, c: &Point3D) -> Result<f64, StrError> {
    let n = Vector3D::new_from_points(a, b); // b - a
    let denominator = n.dot(&n); // n ⋅ n
    if denominator <= f64::EPSILON {
        return Err("segment is too short");
    }
    let x = Vector3D::new_from_points(a, c); // c - a
    let scale = x.dot(&n) / denominator; // (x ⋅ n) / (n ⋅ n)
    let p = Vector3D::new_scaled(n.u, n.v, n.w, scale);
    let q = x.get_subtracted(&p); // x - p
    Ok(q.norm())
}

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

#[cfg(test)]
mod tests {
    use super::*;
    use crate::SQRT_2_BY_3;
    use russell_chk::assert_approx_eq;

    #[test]
    fn point_segment_distance_3d_fails_on_short_segment() -> Result<(), StrError> {
        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D {
            x: f64::EPSILON,
            y: f64::EPSILON,
            z: f64::EPSILON,
        };
        let c = Point3D { x: 1.0, y: 1.0, z: 1.0 };
        assert_eq!(
            point_segment_distance_3d(&a, &b, &c).err(),
            Some("segment is too short")
        );
        Ok(())
    }

    #[test]
    fn point_segment_distance_3d_works() -> Result<(), StrError> {
        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D { x: 1.0, y: 1.0, z: 1.0 };
        let c = a.clone();
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let c = b.clone();
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let c = Point3D { x: 1.0, y: 1.0, z: 0.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_approx_eq!(distance, SQRT_2_BY_3, 1e-15);

        let c = Point3D { x: 0.0, y: 1.0, z: 1.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_approx_eq!(distance, SQRT_2_BY_3, 1e-15);

        let c = Point3D { x: 1.0, y: 0.0, z: 1.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_approx_eq!(distance, SQRT_2_BY_3, 1e-15);

        let c = Point3D { x: 0.5, y: 0.5, z: 0.5 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D { x: 1.0, y: 0.0, z: 0.0 };
        let c = Point3D { x: 1.0, y: 0.5, z: 0.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.5);

        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D { x: 0.0, y: 1.0, z: 0.0 };
        let c = Point3D { x: 0.5, y: 1.0, z: 0.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.5);

        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D { x: 0.0, y: 0.0, z: 1.0 };
        let c = Point3D { x: 0.0, y: 0.5, z: 1.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.5);
        Ok(())
    }
}
<commit_msg>Impl 2d point distance<commit_after>use crate::{Point2D, Point3D, StrError, Vector2D, Vector3D};

/// Computes the distance between a point and a segment in 2D
///
/// ```text
///                 c
///                /^
/// ⇀             / | ⇀   ⇀   ⇀
/// x = vec(c-a) /  | q = x - p
///             /   |
///            /    |
///           a----->-------------b
///             ⇀              ⇀
///             p = projection(x)
///
///           a-------------------b
///               ⇀
///               n = vec(b-c)
/// ```
///
/// ```text
/// x := c - a
/// n := b - a
/// p := ((x ⋅ n) / (n ⋅ n)) * n
/// q := x - p
/// distance := norm(q)
/// ```
pub fn point_segment_distance_2d(a: &Point2D, b: &Point2D, c: &Point2D) -> Result<f64, StrError> {
    let n = Vector2D::new_from_points(a, b); // b - a
    let denominator = n.dot(&n); // n ⋅ n
    if denominator <= f64::EPSILON {
        return Err("segment is too short");
    }
    let x = Vector2D::new_from_points(a, c); // c - a
    let scale = x.dot(&n) / denominator; // (x ⋅ n) / (n ⋅ n)
    let p = Vector2D::new_scaled(n.u, n.v, scale);
    let q = x.get_subtracted(&p); // x - p
    Ok(q.norm())
}

/// Computes the distance between a point and a segment in 3D
///
/// ```text
///                 c
///                /^
/// ⇀             / | ⇀   ⇀   ⇀
/// x = vec(c-a) /  | q = x - p
///             /   |
///            /    |
///           a----->-------------b
///             ⇀              ⇀
///             p = projection(x)
///
///           a-------------------b
///               ⇀
///               n = vec(b-c)
/// ```
///
/// ```text
/// x := c - a
/// n := b - a
/// p := ((x ⋅ n) / (n ⋅ n)) * n
/// q := x - p
/// distance := norm(q)
/// ```
pub fn point_segment_distance_3d(a: &Point3D, b: &Point3D, c: &Point3D) -> Result<f64, StrError> {
    let n = Vector3D::new_from_points(a, b); // b - a
    let denominator = n.dot(&n); // n ⋅ n
    if denominator <= f64::EPSILON {
        return Err("segment is too short");
    }
    let x = Vector3D::new_from_points(a, c); // c - a
    let scale = x.dot(&n) / denominator; // (x ⋅ n) / (n ⋅ n)
    let p = Vector3D::new_scaled(n.u, n.v, n.w, scale);
    let q = x.get_subtracted(&p); // x - p
    Ok(q.norm())
}

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

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{SQRT_2, SQRT_2_BY_3};
    use russell_chk::assert_approx_eq;

    #[test]
    fn point_segment_distance_2d_fails_on_short_segment() -> Result<(), StrError> {
        let a = Point2D { x: 0.0, y: 0.0 };
        let b = Point2D {
            x: f64::EPSILON,
            y: f64::EPSILON,
        };
        let c = Point2D { x: 1.0, y: 1.0 };
        assert_eq!(
            point_segment_distance_2d(&a, &b, &c).err(),
            Some("segment is too short")
        );
        Ok(())
    }

    #[test]
    fn point_segment_distance_2d_works() -> Result<(), StrError> {
        let a = Point2D { x: 0.0, y: 0.0 };
        let b = Point2D { x: 1.0, y: 1.0 };
        let c = a.clone();
        let distance = point_segment_distance_2d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let c = b.clone();
        let distance = point_segment_distance_2d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let c = Point2D { x: 1.0, y: 0.0 };
        let distance = point_segment_distance_2d(&a, &b, &c)?;
        assert_approx_eq!(distance, SQRT_2 / 2.0, 1e-15);

        let c = Point2D { x: 0.0, y: 1.0 };
        let distance = point_segment_distance_2d(&a, &b, &c)?;
        assert_approx_eq!(distance, SQRT_2 / 2.0, 1e-15);

        let c = Point2D { x: 0.5, y: 0.5 };
        let distance = point_segment_distance_2d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let a = Point2D { x: 0.0, y: 0.0 };
        let b = Point2D { x: 1.0, y: 0.0 };
        let c = Point2D { x: 1.0, y: 0.5 };
        let distance = point_segment_distance_2d(&a, &b, &c)?;
        assert_eq!(distance, 0.5);

        let a = Point2D { x: 0.0, y: 0.0 };
        let b = Point2D { x: 0.0, y: 1.0 };
        let c = Point2D { x: 0.5, y: 1.0 };
        let distance = point_segment_distance_2d(&a, &b, &c)?;
        assert_eq!(distance, 0.5);
        Ok(())
    }

    #[test]
    fn point_segment_distance_3d_fails_on_short_segment() -> Result<(), StrError> {
        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D {
            x: f64::EPSILON,
            y: f64::EPSILON,
            z: f64::EPSILON,
        };
        let c = Point3D { x: 1.0, y: 1.0, z: 1.0 };
        assert_eq!(
            point_segment_distance_3d(&a, &b, &c).err(),
            Some("segment is too short")
        );
        Ok(())
    }

    #[test]
    fn point_segment_distance_3d_works() -> Result<(), StrError> {
        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D { x: 1.0, y: 1.0, z: 1.0 };
        let c = a.clone();
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let c = b.clone();
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let c = Point3D { x: 1.0, y: 1.0, z: 0.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_approx_eq!(distance, SQRT_2_BY_3, 1e-15);

        let c = Point3D { x: 0.0, y: 1.0, z: 1.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_approx_eq!(distance, SQRT_2_BY_3, 1e-15);

        let c = Point3D { x: 1.0, y: 0.0, z: 1.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_approx_eq!(distance, SQRT_2_BY_3, 1e-15);

        let c = Point3D { x: 0.5, y: 0.5, z: 0.5 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.0);

        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D { x: 1.0, y: 0.0, z: 0.0 };
        let c = Point3D { x: 1.0, y: 0.5, z: 0.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.5);

        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D { x: 0.0, y: 1.0, z: 0.0 };
        let c = Point3D { x: 0.5, y: 1.0, z: 0.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.5);

        let a = Point3D { x: 0.0, y: 0.0, z: 0.0 };
        let b = Point3D { x: 0.0, y: 0.0, z: 1.0 };
        let c = Point3D { x: 0.0, y: 0.5, z: 1.0 };
        let distance = point_segment_distance_3d(&a, &b, &c)?;
        assert_eq!(distance, 0.5);
        Ok(())
    }
}
<|endoftext|>


<commit_before>use libc::{c_int, c_longlong, c_char, c_void};
use std::mem;
use std::sync::{Arc, Once, ONCE_INIT};
use std::cell::Cell;

/// Typedef for initialization function.
type EnergyMonInitFn = extern fn(*mut EMImpl) -> c_int;
/// Typedef for read function.
type EnergyMonReadTotalFn = extern fn(*mut EMImpl) -> c_longlong;
/// Typedef for cleanup function.
type EnergyMonFinishFn = extern fn(*mut EMImpl) -> c_int;
/// Typedef for function to get human-readable name.
type EnergyMonGetSourceFn = extern fn(*mut c_char) -> *mut c_char;

#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
#[repr(C)]
/// Representation of native C struct `em_impl`.
struct EMImpl {
    /// Native C function type signature that initializes the `EMImpl`.
    finit: EnergyMonInitFn,
    /// Native C function type signature that reads energy data from the `EMImpl`.
    fread: EnergyMonReadTotalFn,
    /// Native C function type signature that cleans up the `EMImpl`.
    ffinish: EnergyMonFinishFn,
    /// Native C function type signature that gets the `EMImpl`'s human-readable name.
    fsource: EnergyMonGetSourceFn,
    /// Native C pointer used by the underlying `EMImpl` implementation for storing state.
    state: *mut c_void,
}

extern {
    /// Native C function that fills in the EMImpl struct values and may allocate other resources.
    fn em_impl_get(em: *mut EMImpl) -> c_int;
}

impl EMImpl {
    /// Create an `EMImpl` which represents a C struct.
    fn new() -> Result<EMImpl, &'static str> {
        unsafe {
            let mut em: EMImpl = mem::uninitialized();
            match em_impl_get(&mut em) {
                0 => Ok(em),
                _ => Err("Failed to create EMImpl"),
            }
        }
    }

    /// Initialize the `EMImpl` - may allocate more resources and/or start threads.
    fn init(&mut self) -> Result<(), &'static str> {
        match (self.finit)(self) {
            0 => Ok(()),
            _ => Err("Failed to initialize EMImpl"),
        }
    }

    /// Read the total energy from the `EMImpl`.
    fn read(&mut self) -> i64 {
        (self.fread)(self)
    }

    /// Cleanup the `EMImpl` - may deallocate associated resources and/or stop threads.
    fn finish(&mut self) -> Result<(), &'static str> {
        match (self.ffinish)(self) {
            0 => Ok(()),
            _ => Err("Failed to cleanup EMImpl"),
        }
    }

    /// Utility function to get a human-readable name of the `EMImpl`'s source.
    fn source(&mut self) -> String {
        const BUFSIZE: usize = 100;
        let mut buf: [c_char; BUFSIZE] = [0; BUFSIZE];
        let ret: *mut c_char = (self.fsource)(buf.as_mut_ptr());
        if ret.is_null() {
            return "UNKNOWN".to_owned();
        }
        let buf: &[u8] = unsafe {
            mem::transmute::<&[c_char], &[u8]>(&buf)
        };
        String::from_utf8_lossy(buf).into_owned()
    }
}

/// A basic energy monitor.
pub struct EnergyMon {
    /// The native C struct.
    em: EMImpl,
}

impl EnergyMon {
    /// Create and initialize an `EnergyMon`.
    pub fn new() -> Result<EnergyMon, &'static str> {
        println!("Initializing energy monitor");
        let mut em = try!{EMImpl::new()};
        try!{em.init()};
        Ok(EnergyMon { em: em })
    }

    /// Read the total energy from the `EnergyMon`.
    pub fn read(&mut self) -> i64 {
        self.em.read()
    }

    /// Get a human-readable name of the `EnergyMon`'s source.
    pub fn source(&mut self) -> String {
        self.em.source()
    }
}

impl Drop for EnergyMon {
    fn drop(&mut self) {
        println!("Finishing energy monitor");
        let _ = self.em.finish();
    }
}

#[derive(Clone)]
pub struct SingletonEnergyMon {
    em: Arc<Cell<EMImpl>>,
}

impl SingletonEnergyMon {
    pub fn instance() -> Option<SingletonEnergyMon> {
        static mut EM: *const SingletonEnergyMon = 0 as *const SingletonEnergyMon;
        static ONCE: Once = ONCE_INIT;

        unsafe {
            ONCE.call_once(|| {
                println!("Initializing singleton energy monitor");
                let mut em = match EMImpl::new() {
                    Ok(e) => e,
                    Err(e) => {
                        println!("{}", e);
                        return;
                    },
                };
                match em.init() {
                    Ok(_) => (),
                    Err(e) => {
                        println!("{}", e);
                        let _ = em.finish();
                        return;
                    },
                }
                let sem: SingletonEnergyMon = SingletonEnergyMon {
                    em: Arc::new(Cell::new(em))
                };
                // put it on the heap
                EM = mem::transmute(Box::new(sem));
            });
            Some((*EM).clone())
        }
    }

    pub fn read(&self) -> i64 {
        self.em.get().read()
    }

    pub fn source(&self) -> String {
        self.em.get().source()
    }

    pub unsafe fn destroy(&self) {
        println!("Finishing singleton energy monitor");
        let _ = self.em.get().finish();
    }
}

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

    #[test]
    fn test_interface() {
        let mut em: EnergyMon = EnergyMon::new().unwrap();
        let val = em.read();
        assert!(val >= 0);
        println!("Read {} from {}", val, em.source());
    }

    #[test]
    fn test_singleton() {
        for _ in 0..2 {
            let sem: SingletonEnergyMon = SingletonEnergyMon::instance().unwrap();
            let val = sem.read();
            println!("Read {} from {} singleton", val, sem.source());
        }
        unsafe {
            SingletonEnergyMon::instance().unwrap().destroy();
        }
    }

}
<commit_msg>Check for null before returning Option<commit_after>use libc::{c_int, c_longlong, c_char, c_void};
use std::mem;
use std::sync::{Arc, Once, ONCE_INIT};
use std::cell::Cell;

/// Typedef for initialization function.
type EnergyMonInitFn = extern fn(*mut EMImpl) -> c_int;
/// Typedef for read function.
type EnergyMonReadTotalFn = extern fn(*mut EMImpl) -> c_longlong;
/// Typedef for cleanup function.
type EnergyMonFinishFn = extern fn(*mut EMImpl) -> c_int;
/// Typedef for function to get human-readable name.
type EnergyMonGetSourceFn = extern fn(*mut c_char) -> *mut c_char;

#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
#[repr(C)]
/// Representation of native C struct `em_impl`.
struct EMImpl {
    /// Native C function type signature that initializes the `EMImpl`.
    finit: EnergyMonInitFn,
    /// Native C function type signature that reads energy data from the `EMImpl`.
    fread: EnergyMonReadTotalFn,
    /// Native C function type signature that cleans up the `EMImpl`.
    ffinish: EnergyMonFinishFn,
    /// Native C function type signature that gets the `EMImpl`'s human-readable name.
    fsource: EnergyMonGetSourceFn,
    /// Native C pointer used by the underlying `EMImpl` implementation for storing state.
    state: *mut c_void,
}

extern {
    /// Native C function that fills in the EMImpl struct values and may allocate other resources.
    fn em_impl_get(em: *mut EMImpl) -> c_int;
}

impl EMImpl {
    /// Create an `EMImpl` which represents a C struct.
    fn new() -> Result<EMImpl, &'static str> {
        unsafe {
            let mut em: EMImpl = mem::uninitialized();
            match em_impl_get(&mut em) {
                0 => Ok(em),
                _ => Err("Failed to create EMImpl"),
            }
        }
    }

    /// Initialize the `EMImpl` - may allocate more resources and/or start threads.
    fn init(&mut self) -> Result<(), &'static str> {
        match (self.finit)(self) {
            0 => Ok(()),
            _ => Err("Failed to initialize EMImpl"),
        }
    }

    /// Read the total energy from the `EMImpl`.
    fn read(&mut self) -> i64 {
        (self.fread)(self)
    }

    /// Cleanup the `EMImpl` - may deallocate associated resources and/or stop threads.
    fn finish(&mut self) -> Result<(), &'static str> {
        match (self.ffinish)(self) {
            0 => Ok(()),
            _ => Err("Failed to cleanup EMImpl"),
        }
    }

    /// Utility function to get a human-readable name of the `EMImpl`'s source.
    fn source(&mut self) -> String {
        const BUFSIZE: usize = 100;
        let mut buf: [c_char; BUFSIZE] = [0; BUFSIZE];
        let ret: *mut c_char = (self.fsource)(buf.as_mut_ptr());
        if ret.is_null() {
            return "UNKNOWN".to_owned();
        }
        let buf: &[u8] = unsafe {
            mem::transmute::<&[c_char], &[u8]>(&buf)
        };
        String::from_utf8_lossy(buf).into_owned()
    }
}

/// A basic energy monitor.
pub struct EnergyMon {
    /// The native C struct.
    em: EMImpl,
}

impl EnergyMon {
    /// Create and initialize an `EnergyMon`.
    pub fn new() -> Result<EnergyMon, &'static str> {
        println!("Initializing energy monitor");
        let mut em = try!{EMImpl::new()};
        try!{em.init()};
        Ok(EnergyMon { em: em })
    }

    /// Read the total energy from the `EnergyMon`.
    pub fn read(&mut self) -> i64 {
        self.em.read()
    }

    /// Get a human-readable name of the `EnergyMon`'s source.
    pub fn source(&mut self) -> String {
        self.em.source()
    }
}

impl Drop for EnergyMon {
    fn drop(&mut self) {
        println!("Finishing energy monitor");
        let _ = self.em.finish();
    }
}

#[derive(Clone)]
pub struct SingletonEnergyMon {
    em: Arc<Cell<EMImpl>>,
}

impl SingletonEnergyMon {
    pub fn instance() -> Option<SingletonEnergyMon> {
        static mut EM: *const SingletonEnergyMon = 0 as *const SingletonEnergyMon;
        static ONCE: Once = ONCE_INIT;

        unsafe {
            ONCE.call_once(|| {
                println!("Initializing singleton energy monitor");
                let mut em = match EMImpl::new() {
                    Ok(e) => e,
                    Err(e) => {
                        println!("{}", e);
                        return;
                    },
                };
                match em.init() {
                    Ok(_) => (),
                    Err(e) => {
                        println!("{}", e);
                        let _ = em.finish();
                        return;
                    },
                }
                let sem: SingletonEnergyMon = SingletonEnergyMon {
                    em: Arc::new(Cell::new(em))
                };
                // put it on the heap
                EM = mem::transmute(Box::new(sem));
            });
            if EM.is_null() {
                None
            } else {
                Some((*EM).clone())
            }
        }
    }

    pub fn read(&self) -> i64 {
        self.em.get().read()
    }

    pub fn source(&self) -> String {
        self.em.get().source()
    }

    pub unsafe fn destroy(&self) {
        println!("Finishing singleton energy monitor");
        let _ = self.em.get().finish();
    }
}

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

    #[test]
    fn test_interface() {
        let mut em: EnergyMon = EnergyMon::new().unwrap();
        let val = em.read();
        assert!(val >= 0);
        println!("Read {} from {}", val, em.source());
    }

    #[test]
    fn test_singleton() {
        for _ in 0..2 {
            let sem: SingletonEnergyMon = SingletonEnergyMon::instance().unwrap();
            let val = sem.read();
            println!("Read {} from {} singleton", val, sem.source());
        }
        unsafe {
            SingletonEnergyMon::instance().unwrap().destroy();
        }
    }

}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

// Use a hashmap which contains an error level and a string
pub type ErrorStack = Vec<(ErrorLevel, &'static str)>;
<commit_msg>Add display to the error stack and convert the type alias to a struct.<commit_after>use std::fmt;

#[derive(Debug)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

// Use a hashmap which contains an error level and a string
pub struct ErrorStack(Vec<(ErrorLevel, &'static str)>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0
            .iter()
            .map(|e| write!(f, "[{:?}] {}\n", e.0, e.1))

            // We must consume the closure
            .collect::<Vec<fmt::Result>>();

        write!(f, "")
    }
}<|endoftext|>


<commit_before>/*
    This file is a part of cargo-esr.

    Copyright (C) 2017 Mohammad AlSaleh <CE.Mohammad.AlSaleh at gmail.com>
    https://github.com/rust-alt/cargo-esr

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at <http://mozilla.org/MPL/2.0/>.
*/

use pipeliner::Pipeline;

use esr_crate::{CrateInfoWithScore, CrateGeneralInfo};
use esr_github::RepoInfoWithScore;
use esr_printer::{EsrPrinter, EsrFormatter};
use esr_errors::*;

use std::f64;

pub struct CrateScores {
    crate_full: CrateInfoWithScore,
    repo_full: Option<Result<RepoInfoWithScore>>,
}

impl CrateScores {
    pub fn from_id_with_token(id: &str, gh_token: &str) -> Result<Self> {
        let crate_full = CrateInfoWithScore::from_id(id)?;
        let repo_full =crate_full.get_info().github_id()
            .map(|gh_id| RepoInfoWithScore::from_id_with_token(&gh_id, gh_token));

        Ok(Self {
            crate_full,
            repo_full,
        })
    }

    pub fn from_id_crate_only(id: &str) -> Result<Self> {
        let crate_full = CrateInfoWithScore::from_id(id)?;

        Ok(Self {
            crate_full,
            repo_full: None,
        })
    }

    // ====================
    fn score_crate(&self) -> [EsrFormatter; 4] {
        let (pos, neg) = self.crate_full.get_score_tuple();
        EsrPrinter::score_overview("Crate Score", pos, neg)
    }

    fn score_repo(&self) -> Vec<EsrFormatter> {
        if let Some(ref repo_full_res) = self.repo_full {
            if let Ok(ref repo_full) = *repo_full_res {
                let (pos, neg) = repo_full.get_score_tuple();
                EsrPrinter::score_overview("Repo Score ", pos, neg).to_vec()
            } else {
                EsrPrinter::score_error("Repo Score ").to_vec()
            }
        } else {
            EsrPrinter::score_na("Repo Score ").to_vec()
        }
    }

    pub fn print_detailed_scores(&self, formatted: bool) {
        let table = self.crate_full.get_score_table();
        EsrFormatter::print_grp(&EsrPrinter::score_details("Crate Score Details", table), formatted);
        EsrFormatter::print_grp(&self.score_crate(), formatted);

        if let Some(ref repo_full_res) = self.repo_full {
            if let Ok(ref repo_full) = *repo_full_res {
                let table = repo_full.get_score_table();
                EsrFormatter::print_grp(&EsrPrinter::score_details("Repo Score Details", table), formatted);
            }
        }
        EsrFormatter::print_grp(&*self.score_repo(), formatted);
    }

    // =================

    pub fn collect_scores(crates: &[CrateGeneralInfo], token: &str, crate_only: bool, limit: usize) -> Vec<(String, Result<Self>)> {
        let id_token_pair: Vec<_> = crates.iter()
            .map(|cr| (String::from(cr.get_id()), String::from(token)))
            .collect();

        if crate_only {
            id_token_pair.into_iter()
                .with_threads(limit)
                .map(move |(id, _)| (id.clone(), CrateScores::from_id_crate_only(&id)))
                .collect()
        } else {
            id_token_pair.into_iter()
                .with_threads(limit)
                .map(move |(id, token)| (id.clone(), CrateScores::from_id_with_token(&id, &token)))
                .collect()
        }
    }

    fn info_pair(&self, id: &str, sort_positive: bool) -> (f64, Vec<EsrFormatter>) {
        let cr_info = self.crate_full.get_info();
        let (pos, neg) = self.crate_full.get_score_tuple();

        let empty_or_all_yanked_formatted = match cr_info.empty_or_all_yanked() {
            true => EsrPrinter::all_yanked(),
            false => EsrFormatter::trail_only("\n "),
        };

        let sort_score = match sort_positive {
            true => pos,
            false => pos + neg,
        };

        let releases = self.crate_full.get_score_info().get_releases();
        let non_yanked = self.crate_full.get_score_info().get_non_yanked_releases();
        let stable = self.crate_full.get_score_info().get_stable_releases();
        let yanked = releases - non_yanked;
        let non_yanked_pre = non_yanked - stable;
        let releases_formatted = EsrPrinter::releases(stable, non_yanked_pre, yanked);

        let max_ver = Some(cr_info.get_max_version());
        let max_ver_age = cr_info.max_version_age();
        let max_ver_msg = EsrPrinter::release(max_ver, max_ver_age);

        let last_stable_version = cr_info.last_stable_version();
        let last_stable_version_age = cr_info.last_stable_version_age();
        let last_stable_version_msg = EsrPrinter::release(last_stable_version, last_stable_version_age);

        let dependants = self.crate_full.get_score_info().get_dependants();
        let d_b_n_o = self.crate_full.get_score_info().get_dependants_from_non_owners();
        let dependants_msg = format!("{} ({} from non owners)", dependants, d_b_n_o);

        let desc = EsrPrinter::desc(cr_info.get_description().unwrap_or("N/A"));

        let mut info_formatter = Vec::with_capacity(32);
        info_formatter.push(EsrPrinter::id(id));
        info_formatter.push(empty_or_all_yanked_formatted);
        info_formatter.extend_from_slice(&self.score_crate());
        info_formatter.extend_from_slice(&self.score_repo());
        info_formatter.extend_from_slice(&*EsrPrinter::msg_pair_complex("Releases   ", &releases_formatted));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Max Version", &max_ver_msg));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Last Stable", &last_stable_version_msg));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Dependants ", &dependants_msg));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("License    ", cr_info.get_license().unwrap_or("N/A")));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Repository ", cr_info.get_repository().unwrap_or("N/A")));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Description", &desc));

        (sort_score, info_formatter)
    }

    pub fn print_search_results(results: &[(String, Result<Self>)], sort_positive: bool, limit: usize, formatted: bool) {
        let mut results_vec = Vec::with_capacity(32);
        for res in results {
            match *res {
                (ref id, Ok(ref score_info)) => {
                    results_vec.push(score_info.info_pair(id, sort_positive));
                },
                (ref id, Err(_)) => {
                    results_vec.push((f64::MIN, vec![EsrPrinter::err(&format!("{}: Failed to get score info.", id))]));
                },
            }
        }

        // Negation to get scores in reverse.
        // `* 10000.0` to not lose order accuracy after casting.
        results_vec.sort_by_key(|&(sort_score, _)| -(sort_score * 10000.0) as i64);
        for (num, result) in results_vec.iter().take(limit).enumerate() {
            EsrPrinter::id(&format!("({})", num + 1)).print(formatted);
            EsrFormatter::print_grp(&result.1, formatted);
        }
    }
}
<commit_msg>Print crate info before score details<commit_after>/*
    This file is a part of cargo-esr.

    Copyright (C) 2017 Mohammad AlSaleh <CE.Mohammad.AlSaleh at gmail.com>
    https://github.com/rust-alt/cargo-esr

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at <http://mozilla.org/MPL/2.0/>.
*/

use pipeliner::Pipeline;

use esr_crate::{CrateInfoWithScore, CrateGeneralInfo};
use esr_github::RepoInfoWithScore;
use esr_printer::{EsrPrinter, EsrFormatter};
use esr_errors::*;

use std::f64;

pub struct CrateScores {
    crate_full: CrateInfoWithScore,
    repo_full: Option<Result<RepoInfoWithScore>>,
}

impl CrateScores {
    pub fn from_id_with_token(id: &str, gh_token: &str) -> Result<Self> {
        let crate_full = CrateInfoWithScore::from_id(id)?;
        let repo_full =crate_full.get_info().github_id()
            .map(|gh_id| RepoInfoWithScore::from_id_with_token(&gh_id, gh_token));

        Ok(Self {
            crate_full,
            repo_full,
        })
    }

    pub fn from_id_crate_only(id: &str) -> Result<Self> {
        let crate_full = CrateInfoWithScore::from_id(id)?;

        Ok(Self {
            crate_full,
            repo_full: None,
        })
    }

    // ====================
    fn score_crate(&self) -> [EsrFormatter; 4] {
        let (pos, neg) = self.crate_full.get_score_tuple();
        EsrPrinter::score_overview("Crate Score", pos, neg)
    }

    fn score_repo(&self) -> Vec<EsrFormatter> {
        if let Some(ref repo_full_res) = self.repo_full {
            if let Ok(ref repo_full) = *repo_full_res {
                let (pos, neg) = repo_full.get_score_tuple();
                EsrPrinter::score_overview("Repo Score ", pos, neg).to_vec()
            } else {
                EsrPrinter::score_error("Repo Score ").to_vec()
            }
        } else {
            EsrPrinter::score_na("Repo Score ").to_vec()
        }
    }

    pub fn print_detailed_scores(&self, formatted: bool) {
        let id = self.crate_full.get_info().get_id();
        EsrFormatter::print_grp(&self.info_pair(id, false).1, formatted);

        let table = self.crate_full.get_score_table();
        EsrFormatter::print_grp(&EsrPrinter::score_details("Crate Score Details", table), formatted);
        EsrFormatter::print_grp(&self.score_crate(), formatted);

        if let Some(ref repo_full_res) = self.repo_full {
            if let Ok(ref repo_full) = *repo_full_res {
                let table = repo_full.get_score_table();
                EsrFormatter::print_grp(&EsrPrinter::score_details("Repo Score Details", table), formatted);
            }
        }
        EsrFormatter::print_grp(&*self.score_repo(), formatted);
    }

    // =================

    pub fn collect_scores(crates: &[CrateGeneralInfo], token: &str, crate_only: bool, limit: usize) -> Vec<(String, Result<Self>)> {
        let id_token_pair: Vec<_> = crates.iter()
            .map(|cr| (String::from(cr.get_id()), String::from(token)))
            .collect();

        if crate_only {
            id_token_pair.into_iter()
                .with_threads(limit)
                .map(move |(id, _)| (id.clone(), CrateScores::from_id_crate_only(&id)))
                .collect()
        } else {
            id_token_pair.into_iter()
                .with_threads(limit)
                .map(move |(id, token)| (id.clone(), CrateScores::from_id_with_token(&id, &token)))
                .collect()
        }
    }

    fn info_pair(&self, id: &str, sort_positive: bool) -> (f64, Vec<EsrFormatter>) {
        let cr_info = self.crate_full.get_info();
        let (pos, neg) = self.crate_full.get_score_tuple();

        let empty_or_all_yanked_formatted = match cr_info.empty_or_all_yanked() {
            true => EsrPrinter::all_yanked(),
            false => EsrFormatter::trail_only("\n "),
        };

        let sort_score = match sort_positive {
            true => pos,
            false => pos + neg,
        };

        let releases = self.crate_full.get_score_info().get_releases();
        let non_yanked = self.crate_full.get_score_info().get_non_yanked_releases();
        let stable = self.crate_full.get_score_info().get_stable_releases();
        let yanked = releases - non_yanked;
        let non_yanked_pre = non_yanked - stable;
        let releases_formatted = EsrPrinter::releases(stable, non_yanked_pre, yanked);

        let max_ver = Some(cr_info.get_max_version());
        let max_ver_age = cr_info.max_version_age();
        let max_ver_msg = EsrPrinter::release(max_ver, max_ver_age);

        let last_stable_version = cr_info.last_stable_version();
        let last_stable_version_age = cr_info.last_stable_version_age();
        let last_stable_version_msg = EsrPrinter::release(last_stable_version, last_stable_version_age);

        let dependants = self.crate_full.get_score_info().get_dependants();
        let d_b_n_o = self.crate_full.get_score_info().get_dependants_from_non_owners();
        let dependants_msg = format!("{} ({} from non owners)", dependants, d_b_n_o);

        let desc = EsrPrinter::desc(cr_info.get_description().unwrap_or("N/A"));

        let mut info_formatter = Vec::with_capacity(32);
        info_formatter.push(EsrPrinter::id(id));
        info_formatter.push(empty_or_all_yanked_formatted);
        info_formatter.extend_from_slice(&self.score_crate());
        info_formatter.extend_from_slice(&self.score_repo());
        info_formatter.extend_from_slice(&*EsrPrinter::msg_pair_complex("Releases   ", &releases_formatted));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Max Version", &max_ver_msg));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Last Stable", &last_stable_version_msg));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Dependants ", &dependants_msg));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("License    ", cr_info.get_license().unwrap_or("N/A")));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Repository ", cr_info.get_repository().unwrap_or("N/A")));
        info_formatter.extend_from_slice(&EsrPrinter::msg_pair("Description", &desc));

        (sort_score, info_formatter)
    }

    pub fn print_search_results(results: &[(String, Result<Self>)], sort_positive: bool, limit: usize, formatted: bool) {
        let mut results_vec = Vec::with_capacity(32);
        for res in results {
            match *res {
                (ref id, Ok(ref score_info)) => {
                    results_vec.push(score_info.info_pair(id, sort_positive));
                },
                (ref id, Err(_)) => {
                    results_vec.push((f64::MIN, vec![EsrPrinter::err(&format!("{}: Failed to get score info.", id))]));
                },
            }
        }

        // Negation to get scores in reverse.
        // `* 10000.0` to not lose order accuracy after casting.
        results_vec.sort_by_key(|&(sort_score, _)| -(sort_score * 10000.0) as i64);
        for (num, result) in results_vec.iter().take(limit).enumerate() {
            EsrPrinter::id(&format!("({})", num + 1)).print(formatted);
            EsrFormatter::print_grp(&result.1, formatted);
        }
    }
}
<|endoftext|>


<commit_before>use glutin::Window;

use event::{Event, PollEvents, Reactor};
use render::{Context, GlutinContext, MetaContext};

pub struct Harness<C>
    where C: MetaContext
{
    context: Context<C>,
}

impl Harness<GlutinContext> {
    pub fn from_glutin_window(window: Window) -> Self {
        Harness {
            context: Context::from_glutin_window(window),
        }
    }
}

impl<C> Harness<C>
    where C: MetaContext
{
    pub fn start<A>(&mut self)
        where A: Application<C>
    {
        let mut application = A::start(&mut self.context);
        'main: loop {
            self.context.clear();
            for event in self.context.window.poll_events() {
                match event {
                    Event::Closed => {
                        break 'main;
                    }
                    Event::Resized(..) => {
                        self.context.update_frame_buffer_view();
                    }
                    _ => {}
                }
                application.react(&event);
            }
            application.update(&mut self.context);
            application.draw(&mut self.context);
            self.context.flush().unwrap();
        }
        application.stop();
    }
}

pub trait Application<C>: Reactor + Sized
    where C: MetaContext
{
    fn start(context: &mut Context<C>) -> Self;
    fn update(&mut self, context: &mut Context<C>);
    // TODO: Do not accept the entire `Context`. Maybe `Context` can emit a
    //       more limited type that can be used for rendering.
    fn draw(&mut self, context: &mut Context<C>);
    fn stop(self);
}
<commit_msg>Avoid spurious frame buffer view updates.<commit_after>use glutin::Window;

use event::{Event, PollEvents, Reactor};
use math::UScalar;
use render::{AspectRatio, Context, GlutinContext, MetaContext};

pub struct Harness<C>
    where C: MetaContext
{
    context: Context<C>,
    dimensions: (UScalar, UScalar),
}

impl Harness<GlutinContext> {
    pub fn from_glutin_window(window: Window) -> Self {
        Harness {
            dimensions: window.dimensions(),
            context: Context::from_glutin_window(window),
        }
    }
}

impl<C> Harness<C>
    where C: MetaContext
{
    pub fn start<A>(&mut self)
        where A: Application<C>
    {
        let mut application = A::start(&mut self.context);
        'main: loop {
            self.context.clear();
            for event in self.context.window.poll_events() {
                match event {
                    Event::Closed => {
                        break 'main;
                    }
                    Event::Resized(width, height) => {
                        if self.dimensions.0 != width || self.dimensions.1 != height {
                            self.context.update_frame_buffer_view();
                        }
                    }
                    _ => {}
                }
                application.react(&event);
            }
            application.update(&mut self.context);
            application.draw(&mut self.context);
            self.dimensions = self.context.window.dimensions();
            self.context.flush().unwrap();
        }
        application.stop();
    }
}

pub trait Application<C>: Reactor + Sized
    where C: MetaContext
{
    fn start(context: &mut Context<C>) -> Self;
    fn update(&mut self, context: &mut Context<C>);
    // TODO: Do not accept the entire `Context`. Maybe `Context` can emit a
    //       more limited type that can be used for rendering.
    fn draw(&mut self, context: &mut Context<C>);
    fn stop(self);
}
<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

extern crate libc;

use std::mem;

use constants::LINE_SIZE;

#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct GCHeader {
    reference_count: libc::size_t,
    spans_lines: bool,
    forwarded: bool,
    logged: bool,
    marked: bool,
    new: bool,
}

#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct GCRTTI {
    object_size: libc::size_t,
    variables: libc::size_t,
}

#[repr(C)]
pub struct GCObject {
    header: GCHeader,
    rtti: *const GCRTTI
}

pub type GCObjectRef = *mut GCObject;

impl GCRTTI {
    pub fn new(object_size: uint, variables: uint) -> GCRTTI {
        return GCRTTI {
            object_size: object_size as libc::size_t,
            variables: variables as libc::size_t,
        };
    }

    pub fn object_size(&self) -> uint {
        return self.object_size as uint;
    }

    pub fn variables(&self) -> uint {
        return self.variables as uint;
    }
}

impl GCObject {
    pub fn new(rtti: *const GCRTTI, mark: bool) -> GCObject {
        debug!("GCobject::new(rtti={}, mark={}", rtti, mark);
        let size = unsafe{ (*rtti).object_size() };
        return GCObject {
            header: GCHeader {
                reference_count: 0,
                spans_lines: size > LINE_SIZE,
                forwarded: false,
                logged: false,
                marked: mark,
                new: true,
            },
            rtti: rtti,
        }
    }

    pub fn set_logged(&mut self, new: bool) -> bool {
        debug!("Set object {:p} logged={}", self, new);
        let logged = self.header.logged;
        self.header.logged = new;
        return logged;
    }

    pub fn set_marked(&mut self, next: bool) -> bool {
        debug!("Set object {:p} marked={}", self, next);
        let marked = self.header.marked;
        self.header.marked = next;
        return marked == next;
    }

    pub fn is_marked(&self, next: bool) -> bool {
        return self.header.marked == next;
    }

    pub fn spans_lines(&self) -> bool {
        return self.header.spans_lines;
    }

    pub fn object_size(&self) -> uint {
        return unsafe{ (*self.rtti).object_size() };
    }

    pub fn decrement(&mut self) -> bool {
        if self.header.reference_count == 0 {
            return false;
        }
        self.header.reference_count -= 1;
        debug!("Decrement object {:p} to {}", self, self.header.reference_count);
        return self.header.reference_count == 0;
    }

    pub fn increment(&mut self) -> bool {
        self.header.reference_count += 1;
        debug!("Increment object {:p} to {} (new={})", self,
            self.header.reference_count, self.header.new);
        if self.header.new {
            self.header.new = false;
            return true;
        }
        return false;
    }

    pub fn children(&mut self) -> Vec<GCObjectRef> {
        let base: *const GCObjectRef = unsafe{ mem::transmute(&self.rtti) };
        let variables = unsafe{ (*self.rtti).variables() };
        return range(1, variables + 1).map(|i| unsafe{ *base.offset(i as int) })
                                      .collect();
    }

}

<commit_msg>Implement pinning/forwarding in CGObject<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

extern crate libc;

use std::mem;

use constants::LINE_SIZE;

#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct GCHeader {
    reference_count: libc::size_t,
    spans_lines: bool,
    forwarded: bool,
    logged: bool,
    marked: bool,
    pinned: bool,
    new: bool,
}

#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct GCRTTI {
    object_size: libc::size_t,
    variables: libc::size_t,
}

#[repr(C)]
pub struct GCObject {
    header: GCHeader,
    rtti: *const GCRTTI
}

pub type GCObjectRef = *mut GCObject;

impl GCRTTI {
    pub fn new(object_size: uint, variables: uint) -> GCRTTI {
        return GCRTTI {
            object_size: object_size as libc::size_t,
            variables: variables as libc::size_t,
        };
    }

    pub fn object_size(&self) -> uint {
        return self.object_size as uint;
    }

    pub fn variables(&self) -> uint {
        return self.variables as uint;
    }
}

impl GCObject {
    pub fn new(rtti: *const GCRTTI, mark: bool) -> GCObject {
        debug!("GCobject::new(rtti={}, mark={}", rtti, mark);
        let size = unsafe{ (*rtti).object_size() };
        return GCObject {
            header: GCHeader {
                reference_count: 0,
                spans_lines: size > LINE_SIZE,
                forwarded: false,
                logged: false,
                marked: mark,
                pinned: false,
                new: true,
            },
            rtti: rtti,
        }
    }

    pub fn set_logged(&mut self, new: bool) -> bool {
        debug!("Set object {:p} logged={}", self, new);
        let logged = self.header.logged;
        self.header.logged = new;
        return logged;
    }

    pub fn set_marked(&mut self, next: bool) -> bool {
        debug!("Set object {:p} marked={}", self, next);
        let marked = self.header.marked;
        self.header.marked = next;
        return marked == next;
    }

    pub fn is_marked(&self, next: bool) -> bool {
        return self.header.marked == next;
    }

    pub fn set_pinned(&mut self, pinned: bool) {
        debug!("Set object {:p} pinned={}", self, pinned);
        self.header.pinned = pinned;
    }

    pub fn is_pinned(&self) -> bool {
        return self.header.pinned;
    }

    pub fn set_forwarded(&mut self, new: GCObjectRef) {
        debug!("Set object {:p} forwarded to {}", self, new);
        self.header.forwarded = true;
        self.rtti = new as *const GCRTTI;
    }

    pub fn is_forwarded(&self) -> Option<GCObjectRef> {
        if self.header.forwarded {
            return Some(self.rtti as GCObjectRef);
        }
        return None;
    }

    pub fn spans_lines(&self) -> bool {
        return self.header.spans_lines;
    }

    pub fn object_size(&self) -> uint {
        return unsafe{ (*self.rtti).object_size() };
    }

    pub fn decrement(&mut self) -> bool {
        if self.header.reference_count == 0 {
            return false;
        }
        self.header.reference_count -= 1;
        debug!("Decrement object {:p} to {}", self, self.header.reference_count);
        return self.header.reference_count == 0;
    }

    pub fn increment(&mut self) -> bool {
        self.header.reference_count += 1;
        debug!("Increment object {:p} to {} (new={})", self,
            self.header.reference_count, self.header.new);
        if self.header.new {
            self.header.new = false;
            return true;
        }
        return false;
    }

    pub fn children(&mut self) -> Vec<GCObjectRef> {
        let base: *const GCObjectRef = unsafe{ mem::transmute(&self.rtti) };
        let variables = unsafe{ (*self.rtti).variables() };
        return range(1, variables + 1).map(|i| unsafe{ *base.offset(i as int) })
                                      .collect();
    }

}

<|endoftext|>


<commit_before>use super::number::Number;
use super::point::Point;

pub enum LineIntersection<T> {
   Point(Point<T>),
   Parallel,
   Overlapping,
}

#[derive(Debug)]
pub struct Line<T> {
   a: T,
   b: T,
   c: T
}

impl<T> Line<T> where T: Number {
   pub fn new(x1: T, y1: T, x2: T, y2: T) -> Self {
      let (a, b, c) = Self::calc_abc(x1, y1, x2, y2);
      Line {
         a: a,
         b: b,
         c: c
      }
   }

   pub fn update(&mut self, x1: T, y1: T, x2: T, y2: T) {
      let (a, b, c) = Self::calc_abc(x1, y1, x2, y2);
      self.a = a;
      self.b = b;
      self.c = c;
   }

   #[inline]
   fn calc_abc(x1: T, y1: T, x2: T, y2: T) -> (T, T, T) {
      let mut a = y2 - y1;
      let mut b = x1 - x2;
      let mut c = -(x1 * y2 - x2 * y1);

      let mut norm = (T::one() / (a * a + b * b)).sqrt();
      if a != T::zero() {
         if a < T::zero() {
            norm = -norm;
         }
      } else {
         if b < T::zero() {
            norm = -norm;
         }
      }

      a = a * norm;
      b = b * norm;
      c = c * norm;
      (a, b, c)
   }

   pub fn intersect(&self, line: &Self) -> LineIntersection<T> {
      let denominator = self.a * line.b - line.a * self.b;

      if denominator == T::zero() {
         return LineIntersection::Overlapping;
      }

      let x = (line.c * self.b - self.c * line.b) / denominator;
      let y = (line.a * self.c - self.a * line.c) / denominator;

      LineIntersection::Point(Point::new(x, y))
   }
}

#[derive(Debug)]
pub struct LineSegment<T> {
   p1: Point<T>,
   p2: Point<T>,
   line: Line<T>
}

impl<T> LineSegment<T> where T: Number {
   pub fn new(x1: T, y1: T, x2: T, y2: T) -> Self {
      let p1 = Point::new(x1, y1);
      let p2 = Point::new(x2, y2);
      let line = Line::new(x1, y1, x2, y2);

      LineSegment {
         p1: p1,
         p2: p2,
         line: line
      }
   }

   pub fn update(&mut self, x1: T, y1: T, x2: T, y2: T) {
      self.p1.x = x1;
      self.p1.y = y1;
      self.p2.x = x2;
      self.p2.y = y2;

      self.line.update(x1, y1, x2, y2);
   }

   #[inline]
   pub fn x1(&self) -> T {
      self.p1.x
   }

   #[inline]
   pub fn y1(&self) -> T {
      self.p1.y
   }

   #[inline]
   pub fn x2(&self) -> T {
      self.p2.x
   }

   #[inline]
   pub fn y2(&self) -> T {
      self.p2.y
   }

   #[inline]
   pub fn line(&self) -> &Line<T> {
      &self.line
   }
}

impl<T> Default for LineSegment<T> where T: Number {
   fn default() -> LineSegment<T> {
      LineSegment::new(T::zero(), T::zero(), T::zero(), T::zero())
   }
}

#[cfg(test)]
mod tests {
   use test::{Bencher, black_box};

   use super::*;

   #[test]
   fn test_new_f64() {
      let line = LineSegment::new(
         10_f64, 20_f64,
         -100_f64, 0_f64
      );
      assert_eq!(line.p1.x, 10_f64);
      assert_eq!(line.p1.y, 20_f64);
      assert_eq!(line.p2.x, -100_f64);
      assert_eq!(line.p2.y, 0_f64);
   }

   #[test]
   fn test_new_f32() {
      let line = LineSegment::new(
         10_f32, 20_f32,
         -100_f32, 0_f32
      );
      assert_eq!(line.p1.x, 10_f32);
      assert_eq!(line.p1.y, 20_f32);
      assert_eq!(line.p2.x, -100_f32);
      assert_eq!(line.p2.y, 0_f32);
   }

   #[bench]
   fn bench_line_new_f64(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(
               Line::new(5_f64, 7_f64, 3_f64, 2_f64)
            );
         }
      });
   }
}
<commit_msg>Fixing the Line::new benchmark<commit_after>use super::number::Number;
use super::point::Point;

pub enum LineIntersection<T> {
   Point(Point<T>),
   Parallel,
   Overlapping,
}

#[derive(Debug)]
pub struct Line<T> {
   a: T,
   b: T,
   c: T
}

impl<T> Line<T> where T: Number {
   pub fn new(x1: T, y1: T, x2: T, y2: T) -> Self {
      let (a, b, c) = Self::calc_abc(x1, y1, x2, y2);
      Line {
         a: a,
         b: b,
         c: c
      }
   }

   pub fn update(&mut self, x1: T, y1: T, x2: T, y2: T) {
      let (a, b, c) = Self::calc_abc(x1, y1, x2, y2);
      self.a = a;
      self.b = b;
      self.c = c;
   }

   #[inline]
   fn calc_abc(x1: T, y1: T, x2: T, y2: T) -> (T, T, T) {
      let mut a = y2 - y1;
      let mut b = x1 - x2;
      let mut c = -(x1 * y2 - x2 * y1);

      let mut norm = (T::one() / (a * a + b * b)).sqrt();
      if a != T::zero() {
         if a < T::zero() {
            norm = -norm;
         }
      } else {
         if b < T::zero() {
            norm = -norm;
         }
      }

      a = a * norm;
      b = b * norm;
      c = c * norm;

      (a, b, c)
   }

   pub fn intersect(&self, line: &Self) -> LineIntersection<T> {
      let denominator = self.a * line.b - line.a * self.b;

      if denominator == T::zero() {
         return LineIntersection::Overlapping;
      }

      let x = (line.c * self.b - self.c * line.b) / denominator;
      let y = (line.a * self.c - self.a * line.c) / denominator;

      LineIntersection::Point(Point::new(x, y))
   }
}

#[derive(Debug)]
pub struct LineSegment<T> {
   p1: Point<T>,
   p2: Point<T>,
   line: Line<T>
}

impl<T> LineSegment<T> where T: Number {
   pub fn new(x1: T, y1: T, x2: T, y2: T) -> Self {
      let p1 = Point::new(x1, y1);
      let p2 = Point::new(x2, y2);
      let line = Line::new(x1, y1, x2, y2);

      LineSegment {
         p1: p1,
         p2: p2,
         line: line
      }
   }

   pub fn update(&mut self, x1: T, y1: T, x2: T, y2: T) {
      self.p1.x = x1;
      self.p1.y = y1;
      self.p2.x = x2;
      self.p2.y = y2;

      self.line.update(x1, y1, x2, y2);
   }

   #[inline]
   pub fn x1(&self) -> T {
      self.p1.x
   }

   #[inline]
   pub fn y1(&self) -> T {
      self.p1.y
   }

   #[inline]
   pub fn x2(&self) -> T {
      self.p2.x
   }

   #[inline]
   pub fn y2(&self) -> T {
      self.p2.y
   }

   #[inline]
   pub fn line(&self) -> &Line<T> {
      &self.line
   }
}

impl<T> Default for LineSegment<T> where T: Number {
   fn default() -> LineSegment<T> {
      LineSegment::new(T::zero(), T::zero(), T::zero(), T::zero())
   }
}

#[cfg(test)]
mod tests {
   use test::{Bencher, black_box};

   use super::*;

   #[test]
   fn test_new_f64() {
      let line = LineSegment::new(
         10_f64, 20_f64,
         -100_f64, 0_f64
      );
      assert_eq!(line.p1.x, 10_f64);
      assert_eq!(line.p1.y, 20_f64);
      assert_eq!(line.p2.x, -100_f64);
      assert_eq!(line.p2.y, 0_f64);
   }

   #[test]
   fn test_new_f32() {
      let line = LineSegment::new(
         10_f32, 20_f32,
         -100_f32, 0_f32
      );
      assert_eq!(line.p1.x, 10_f32);
      assert_eq!(line.p1.y, 20_f32);
      assert_eq!(line.p2.x, -100_f32);
      assert_eq!(line.p2.y, 0_f32);
   }

   #[bench]
   fn bench_line_new_f64(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(
               Line::new(
                  black_box(5_f64),
                  black_box(7_f64),
                  black_box(3_f64),
                  black_box(2_f64)
               )
            );
         }
      });
   }
}
<|endoftext|>


<commit_before>//! OpenSSL support through the openssl crate.
//! Note that private keys can only be used for signing and that public keys
//! can only be used for verification.
//! ## Examples
//! ```
//! extern crate jwt;
//! extern crate openssl;
//!
//! use jwt::PKeyWithDigest;
//! use openssl::hash::MessageDigest;
//! use openssl::pkey::PKey;
//! let pem = include_bytes!("../../test/rs256-public.pem");
//! let rs256_public_key = PKeyWithDigest {
//!     digest: MessageDigest::sha256(),
//!     key: PKey::public_key_from_pem(pem).unwrap(),
//! };
//!
//! ```

use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::SEPARATOR;
use openssl::bn::BigNum;
use openssl::ecdsa::EcdsaSig;
use openssl::hash::MessageDigest;
use openssl::nid::Nid;
use openssl::pkey::{Id, PKey, Private, Public};
use openssl::sign::{Signer, Verifier};

/// A wrapper class around [PKey](../../../openssl/pkey/struct.PKey.html) that
/// associates the key with a
/// [MessageDigest](../../../openssl/hash/struct.MessageDigest.html).
pub struct PKeyWithDigest<T> {
    pub digest: MessageDigest,
    pub key: PKey<T>,
}

impl<T> PKeyWithDigest<T> {
    fn algorithm_type(&self) -> AlgorithmType {
        match (self.key.id(), self.digest.type_()) {
            (Id::RSA, Nid::SHA256) => AlgorithmType::Rs256,
            (Id::RSA, Nid::SHA384) => AlgorithmType::Rs384,
            (Id::RSA, Nid::SHA512) => AlgorithmType::Rs512,
            (Id::EC, Nid::SHA256) => AlgorithmType::Es256,
            (Id::EC, Nid::SHA384) => AlgorithmType::Es384,
            (Id::EC, Nid::SHA512) => AlgorithmType::Es512,
            _ => panic!("Invalid algorithm type"),
        }
    }
}

impl SigningAlgorithm for PKeyWithDigest<Private> {
    fn algorithm_type(&self) -> AlgorithmType {
        PKeyWithDigest::algorithm_type(self)
    }

    fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
        let mut signer = Signer::new(self.digest.clone(), &self.key)?;
        signer.update(header.as_bytes())?;
        signer.update(SEPARATOR.as_bytes())?;
        signer.update(claims.as_bytes())?;
        let signer_signature = signer.sign_to_vec()?;

        let signature = if self.key.id() == Id::EC {
            der_to_jose(&signer_signature)?
        } else {
            signer_signature
        };

        Ok(base64::encode_config(&signature, base64::URL_SAFE_NO_PAD))
    }
}

impl VerifyingAlgorithm for PKeyWithDigest<Public> {
    fn algorithm_type(&self) -> AlgorithmType {
        PKeyWithDigest::algorithm_type(self)
    }

    fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
        let mut verifier = Verifier::new(self.digest.clone(), &self.key)?;
        verifier.update(header.as_bytes())?;
        verifier.update(SEPARATOR.as_bytes())?;
        verifier.update(claims.as_bytes())?;

        let verified = if self.key.id() == Id::EC {
            let der = jose_to_der(signature)?;
            verifier.verify(&der)?
        } else {
            verifier.verify(signature)?
        };

        Ok(verified)
    }
}

/// OpenSSL by default signs ECDSA in DER, but JOSE expects them in a concatenated (R, S) format
fn der_to_jose(der: &[u8]) -> Result<Vec<u8>, Error> {
    let signature = EcdsaSig::from_der(&der)?;
    let r = signature.r().to_vec();
    let s = signature.s().to_vec();
    Ok([r, s].concat())
}

/// OpenSSL by default verifies ECDSA in DER, but JOSE parses out a concatenated (R, S) format
fn jose_to_der(jose: &[u8]) -> Result<Vec<u8>, Error> {
    let (r, s) = jose.split_at(jose.len() / 2);
    let ecdsa_signature =
        EcdsaSig::from_private_components(BigNum::from_slice(r)?, BigNum::from_slice(s)?)?;
    Ok(ecdsa_signature.to_der()?)
}

#[cfg(test)]
mod tests {
    use crate::algorithm::openssl::PKeyWithDigest;
    use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
    use openssl::hash::MessageDigest;
    use openssl::pkey::PKey;

    // {"alg":"RS256","typ":"JWT"}
    const RS256_HEADER: &'static str = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9";
    // {"alg":"ES256","typ":"JWT"}
    const ES256_HEADER: &'static str = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9";
    // {"sub":"1234567890","name":"John Doe","admin":true}
    const CLAIMS: &'static str =
        "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";

    const RS256_SIGNATURE: &'static str =
    "EkN-DOsnsuRjRO6BxXemmJDm3HbxrbRzXglbN2S4sOkopdU4IsDxTI8jO19W_A4K8ZPJijNLis4EZsHeY559a4DFOd50_OqgHGuERTqYZyuhtF39y\
    xJPAjUESwxk2J5k_4zM3O-vtd1Ghyo4IbqKKSy6J9mTniYJPenn5-HIirE";

    #[test]
    fn rs256_sign() {
        let pem = include_bytes!("../../test/rs256-private.pem");

        let algorithm = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::private_key_from_pem(pem).unwrap(),
        };

        let result = algorithm.sign(RS256_HEADER, CLAIMS).unwrap();
        assert_eq!(result, RS256_SIGNATURE);
    }

    #[test]
    fn rs256_verify() {
        let pem = include_bytes!("../../test/rs256-public.pem");

        let algorithm = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::public_key_from_pem(pem).unwrap(),
        };

        assert!(algorithm
            .verify(RS256_HEADER, CLAIMS, RS256_SIGNATURE)
            .unwrap_or(false));
    }

    #[test]
    fn es256() {
        let private_pem = include_bytes!("../../test/es256-private.pem");
        let private_key = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::private_key_from_pem(private_pem).unwrap(),
        };

        let signature = private_key.sign(ES256_HEADER, CLAIMS).unwrap();

        let public_pem = include_bytes!("../../test/es256-public.pem");

        let public_key = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::public_key_from_pem(public_pem).unwrap(),
        };

        assert!(public_key
            .verify(ES256_HEADER, CLAIMS, &*signature)
            .unwrap_or(false));
    }
}
<commit_msg>Simplify openssl tests<commit_after>//! OpenSSL support through the openssl crate.
//! Note that private keys can only be used for signing and that public keys
//! can only be used for verification.
//! ## Examples
//! ```
//! extern crate jwt;
//! extern crate openssl;
//!
//! use jwt::PKeyWithDigest;
//! use openssl::hash::MessageDigest;
//! use openssl::pkey::PKey;
//! let pem = include_bytes!("../../test/rs256-public.pem");
//! let rs256_public_key = PKeyWithDigest {
//!     digest: MessageDigest::sha256(),
//!     key: PKey::public_key_from_pem(pem).unwrap(),
//! };
//!
//! ```

use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::SEPARATOR;
use openssl::bn::BigNum;
use openssl::ecdsa::EcdsaSig;
use openssl::hash::MessageDigest;
use openssl::nid::Nid;
use openssl::pkey::{Id, PKey, Private, Public};
use openssl::sign::{Signer, Verifier};

/// A wrapper class around [PKey](../../../openssl/pkey/struct.PKey.html) that
/// associates the key with a
/// [MessageDigest](../../../openssl/hash/struct.MessageDigest.html).
pub struct PKeyWithDigest<T> {
    pub digest: MessageDigest,
    pub key: PKey<T>,
}

impl<T> PKeyWithDigest<T> {
    fn algorithm_type(&self) -> AlgorithmType {
        match (self.key.id(), self.digest.type_()) {
            (Id::RSA, Nid::SHA256) => AlgorithmType::Rs256,
            (Id::RSA, Nid::SHA384) => AlgorithmType::Rs384,
            (Id::RSA, Nid::SHA512) => AlgorithmType::Rs512,
            (Id::EC, Nid::SHA256) => AlgorithmType::Es256,
            (Id::EC, Nid::SHA384) => AlgorithmType::Es384,
            (Id::EC, Nid::SHA512) => AlgorithmType::Es512,
            _ => panic!("Invalid algorithm type"),
        }
    }
}

impl SigningAlgorithm for PKeyWithDigest<Private> {
    fn algorithm_type(&self) -> AlgorithmType {
        PKeyWithDigest::algorithm_type(self)
    }

    fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
        let mut signer = Signer::new(self.digest.clone(), &self.key)?;
        signer.update(header.as_bytes())?;
        signer.update(SEPARATOR.as_bytes())?;
        signer.update(claims.as_bytes())?;
        let signer_signature = signer.sign_to_vec()?;

        let signature = if self.key.id() == Id::EC {
            der_to_jose(&signer_signature)?
        } else {
            signer_signature
        };

        Ok(base64::encode_config(&signature, base64::URL_SAFE_NO_PAD))
    }
}

impl VerifyingAlgorithm for PKeyWithDigest<Public> {
    fn algorithm_type(&self) -> AlgorithmType {
        PKeyWithDigest::algorithm_type(self)
    }

    fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
        let mut verifier = Verifier::new(self.digest.clone(), &self.key)?;
        verifier.update(header.as_bytes())?;
        verifier.update(SEPARATOR.as_bytes())?;
        verifier.update(claims.as_bytes())?;

        let verified = if self.key.id() == Id::EC {
            let der = jose_to_der(signature)?;
            verifier.verify(&der)?
        } else {
            verifier.verify(signature)?
        };

        Ok(verified)
    }
}

/// OpenSSL by default signs ECDSA in DER, but JOSE expects them in a concatenated (R, S) format
fn der_to_jose(der: &[u8]) -> Result<Vec<u8>, Error> {
    let signature = EcdsaSig::from_der(&der)?;
    let r = signature.r().to_vec();
    let s = signature.s().to_vec();
    Ok([r, s].concat())
}

/// OpenSSL by default verifies ECDSA in DER, but JOSE parses out a concatenated (R, S) format
fn jose_to_der(jose: &[u8]) -> Result<Vec<u8>, Error> {
    let (r, s) = jose.split_at(jose.len() / 2);
    let ecdsa_signature =
        EcdsaSig::from_private_components(BigNum::from_slice(r)?, BigNum::from_slice(s)?)?;
    Ok(ecdsa_signature.to_der()?)
}

#[cfg(test)]
mod tests {
    use crate::algorithm::openssl::PKeyWithDigest;
    use crate::algorithm::AlgorithmType::{self, *};
    use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
    use crate::header::PrecomputedAlgorithmOnlyHeader as AlgOnly;
    use crate::ToBase64;
    use openssl::hash::MessageDigest;
    use openssl::pkey::PKey;

    // {"sub":"1234567890","name":"John Doe","admin":true}
    const CLAIMS: &'static str =
        "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";

    const RS256_SIGNATURE: &'static str =
    "cQsAHF2jHvPGFP5zTD8BgoJrnzEx6JNQCpupebWLFnOc2r_punDDTylI6Ia4JZNkvy2dQP-7W-DEbFQ3oaarHsDndqUgwf9iYlDQxz4Rr2nEZX1FX0-FMEgFPeQpdwveCgjtTYUbVy37ijUySN_rW-xZTrsh_Ug-ica8t-zHRIw";

    #[test]
    fn rs256_sign() {
        let pem = include_bytes!("../../test/rs256-private.pem");

        let algorithm = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::private_key_from_pem(pem).unwrap(),
        };

        let result = algorithm
            .sign(&AlgOnly(Rs256).to_base64().unwrap(), CLAIMS)
            .unwrap();
        assert_eq!(result, RS256_SIGNATURE);
    }

    #[test]
    fn rs256_verify() {
        let pem = include_bytes!("../../test/rs256-public.pem");

        let algorithm = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::public_key_from_pem(pem).unwrap(),
        };

        assert!(algorithm
            .verify(
                &AlgOnly(Rs256).to_base64().unwrap(),
                CLAIMS,
                RS256_SIGNATURE
            )
            .unwrap_or(false));
    }

    #[test]
    fn es256() {
        let private_pem = include_bytes!("../../test/es256-private.pem");
        let private_key = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::private_key_from_pem(private_pem).unwrap(),
        };

        let signature = private_key
            .sign(&AlgOnly(Es256).to_base64().unwrap(), CLAIMS)
            .unwrap();

        let public_pem = include_bytes!("../../test/es256-public.pem");

        let public_key = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::public_key_from_pem(public_pem).unwrap(),
        };

        assert!(public_key
            .verify(&AlgOnly(Es256).to_base64().unwrap(), CLAIMS, &*signature)
            .unwrap_or(false));
    }
}
<|endoftext|>