<commit_before>
use std::sync::Mutex;
use nalgebra::*;
use std::path;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::f32;

lazy_static! {
    static ref CORNELL_MESH: Mutex<Mesh> = {
        Mutex::new(
            load_mesh(&String::from("data/cornell_radiosity.dat"), MeshFileType::XyzRgbXx))
    };
}

lazy_static! {
    static ref HEAD_MESH: Mutex<Mesh> = {
        Mutex::new(
            load_mesh(&String::from("data/head_ao.dat"), MeshFileType:: XyzNxnynzAoao))
    };
}

#[derive(Clone, Copy)]
struct Vertex {
    p:   Vec3<f32>,
    n:   Vec3<f32>,
    col: Vec3<f32>
}

impl Vertex {
    fn new(px: f32, py: f32, pz: f32,
           nx: f32, ny: f32, nz: f32,
           r:  f32, g:  f32, b:  f32) -> Vertex {
        Vertex {
            p:   Vec3::new(px, py, pz),
            n:   Vec3::new(nx, ny, nz),
            col: Vec3::new(r , g , b)
        }
    }
}

// Fully inlined triangle representation
#[derive(Clone, Copy)]
struct Triangle {
    v0: Vertex,
    v1: Vertex,
    v2: Vertex
}

impl Triangle {
    fn new(v0: &Vertex, v1: &Vertex, v2: &Vertex) -> Triangle {
        Triangle { v0: *v0, v1: *v1, v2: *v2 }
    }

    fn face_normal(&self) -> Vec3<f32> {
        (self.v1.p - self.v0.p).cross(&(self.v2.p - self.v0.p)).normalize()
    }
}

struct Mesh {
    tri:      Vec<Triangle>,
    aabb_min: Vec3<f32>,
    aabb_max: Vec3<f32>
}

impl Mesh {
    fn new(tri: Vec<Triangle>) -> Mesh {
        // Compute AABB
        let mut aabb_min = Vec3::new(f32::MAX, f32::MAX, f32::MAX);
        let mut aabb_max = Vec3::new(f32::MIN, f32::MIN, f32::MIN);
        for t in &tri {
            for v in &[t.v0.p, t.v1.p, t.v2.p] {
                aabb_min.x = if aabb_min.x < v.x { aabb_min.x } else { v.x };
                aabb_min.y = if aabb_min.y < v.y { aabb_min.y } else { v.y };
                aabb_min.z = if aabb_min.z < v.z { aabb_min.z } else { v.z };
                aabb_max.x = if aabb_max.x > v.x { aabb_max.x } else { v.x };
                aabb_max.y = if aabb_max.y > v.y { aabb_max.y } else { v.y };
                aabb_max.z = if aabb_max.z > v.z { aabb_max.z } else { v.z };
            }
        }

        Mesh { tri: tri, aabb_min: aabb_min, aabb_max: aabb_max }
    }
}

// We either have 'Px Py Pz ColR ColB ColG UVx UVy' with bogus UVs and radiosity data
// in the color channel or 'Px Py Pz Nx Ny Nz UVx UVy' with ambient occlusion in both
// texture coordinates
#[derive(PartialEq)]
enum MeshFileType { XyzRgbXx, XyzNxnynzAoao }

fn load_mesh(file_name: &String, mesh_file_type: MeshFileType) -> Mesh {
    // Load a text format mesh from disk

    let path = path::Path::new(file_name);
    let display = path.display();

    // Open mesh file
    let mut file = match File::open(&path) {
        Err(why) => panic!("load_mesh(): Couldn't open {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file
    };

    // Read entire mesh file into memory
    let mut data_str = String::new();
    match file.read_to_string(&mut data_str) {
        Err(why) => panic!("load_mesh(): Couldn't read {}: {}",
                           display,
                           Error::description(&why)),
        Ok(_)    => ()
    };

    // Parse mesh format line-by-line
    let mut lines = data_str.lines();

    // Comment header / vertex count
    let vtx_cnt;
    loop {
        match lines.next() {
            Some("") => (), // Skip empty lines
            Some(ln) => {
                let words: Vec<&str> = ln.split(" ").collect();
                if words[0] == "#" { continue } // Skip comments
                // First non-empty, non-comment line should contain the vertex count
                vtx_cnt = match words[0].parse::<u32>() {
                    Err(why) => panic!("load_mesh(): Can't parse vertex count: {}: {}",
                                       Error::description(&why),
                                       display),
                    Ok(n)    => n
                };
                break;
            }
            None => panic!("load_mesh(): EOF while parsing vertex count: {}", display)
        }
    }

    // Vertices
    let mut vtx: Vec<Vertex> = Vec::new();
    loop {
        match lines.next() {
            Some("") => (), // Skip empty lines
            Some(ln) => {
                let mut words = ln.split(" ");
                let words_collect: Vec<&str> = words.clone().collect();
                if words_collect.len() != 8 {
                    panic!("load_mesh(): Expected 8 component vertices: {}", display);
                }
                let mut components: Vec<f32> = Vec::new();
                for _ in 0..8 {
                    components.push(words.next().unwrap().parse::<f32>().unwrap());
                }
                match mesh_file_type {
                    MeshFileType::XyzRgbXx =>
                        vtx.push(Vertex::new(components[0],
                                             components[1],
                                             components[2],
                                             0.0, 0.0, 0.0, // Compute the normal later
                                             components[3],
                                             components[4],
                                             components[5]
                                            )),
                    MeshFileType::XyzNxnynzAoao =>
                        vtx.push(Vertex::new(components[0],
                                             components[1],
                                             components[2],
                                             components[3],
                                             components[4],
                                             components[5],
                                             components[6],
                                             components[6],
                                             components[6]
                                            ))
                }
                // Done?
                if vtx.len() == vtx_cnt as usize { break }
            }
            None => panic!("load_mesh(): EOF while parsing vertices: {}", display)
        }
    }
    if vtx_cnt < 3 {
        panic!("load_mesh(): Bogus vertex count: {}: {}", vtx_cnt, display)
    }

    // Index count
    let idx_cnt;
    loop {
        match lines.next() {
            Some("") => (), // Skip empty lines
            Some(ln) => {
                // First non-empty, non-comment line should contain the index count
                idx_cnt = match ln.parse::<u32>() {
                    Err(why) => panic!("load_mesh(): Can't parse index count: {}: {}",
                                       Error::description(&why),
                                       display),
                    Ok(n)    => n
                };
                break;
            }
            None => panic!("load_mesh(): EOF while parsing index count: {}", display)
        }
    }
    if idx_cnt % 3 != 0 {
        panic!("load_mesh(): Bogus index count: {}: {}", idx_cnt, display)
    }

    // Indices
    let mut idx: Vec<(u32, u32, u32)> = Vec::new();
    loop {
        match lines.next() {
            Some("") => (), // Skip empty lines
            Some(ln) => {
                let mut words = ln.split(" ");
                let words_collect: Vec<&str> = words.clone().collect();
                if words_collect.len() != 3 {
                    panic!("load_mesh(): Expected 3 component indexed triangles: {}", display);
                }
                let mut components: Vec<u32> = Vec::new();
                for _ in 0..3 {
                    components.push(words.next().unwrap().parse::<u32>().unwrap());
                }
                idx.push((components[0], components[1], components[2]));
                // Done?
                if idx.len() * 3 == idx_cnt as usize { break }
            }
            None => panic!("load_mesh(): EOF while parsing indices: {}", display)
        }
    }

    // Assemble triangle vector and mesh
    let mut triangles = Vec::new();
    for tri_idx in idx {
        let mut ntri = Triangle::new(&vtx[tri_idx.0 as usize],
                                     &vtx[tri_idx.1 as usize],
                                     &vtx[tri_idx.2 as usize]);
        if mesh_file_type == MeshFileType::XyzRgbXx {
            // Set vertex normals from face normal
            let n = ntri.face_normal();
            ntri.v0.n = n;
            ntri.v1.n = n;
            ntri.v2.n = n;
        }
        triangles.push(ntri);
    }
    let mesh = Mesh::new(triangles);

    // Print some mesh information
    println!("load_mesh(): Loaded {} tri and {} vtx from {}, AABB ({}, {}, {}) - ({}, {}, {})",
        mesh.tri.len(), vtx.len(), display,
        mesh.aabb_min.x, mesh.aabb_min.y, mesh.aabb_min.z,
        mesh.aabb_max.x, mesh.aabb_max.y, mesh.aabb_max.z);

    mesh
}

#[no_mangle]
pub extern fn rast_draw(tick: f64, w: i32, h: i32, fb: *mut u32) -> () {
    let cornell_mesh = CORNELL_MESH.lock().unwrap();
    let head_mesh = HEAD_MESH.lock().unwrap();
}

<commit_msg>Background gradient for the rasterizer<commit_after>
use std::sync::Mutex;
use nalgebra::*;
use std::path;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::f32;

lazy_static! {
    static ref CORNELL_MESH: Mutex<Mesh> = {
        Mutex::new(
            load_mesh(&String::from("data/cornell_radiosity.dat"), MeshFileType::XyzRgbXx))
    };
}

lazy_static! {
    static ref HEAD_MESH: Mutex<Mesh> = {
        Mutex::new(
            load_mesh(&String::from("data/head_ao.dat"), MeshFileType:: XyzNxnynzAoao))
    };
}

#[derive(Clone, Copy)]
struct Vertex {
    p:   Vec3<f32>,
    n:   Vec3<f32>,
    col: Vec3<f32>
}

impl Vertex {
    fn new(px: f32, py: f32, pz: f32,
           nx: f32, ny: f32, nz: f32,
           r:  f32, g:  f32, b:  f32) -> Vertex {
        Vertex {
            p:   Vec3::new(px, py, pz),
            n:   Vec3::new(nx, ny, nz),
            col: Vec3::new(r , g , b)
        }
    }
}

// Fully inlined triangle representation
#[derive(Clone, Copy)]
struct Triangle {
    v0: Vertex,
    v1: Vertex,
    v2: Vertex
}

impl Triangle {
    fn new(v0: &Vertex, v1: &Vertex, v2: &Vertex) -> Triangle {
        Triangle { v0: *v0, v1: *v1, v2: *v2 }
    }

    fn face_normal(&self) -> Vec3<f32> {
        (self.v1.p - self.v0.p).cross(&(self.v2.p - self.v0.p)).normalize()
    }
}

struct Mesh {
    tri:      Vec<Triangle>,
    aabb_min: Vec3<f32>,
    aabb_max: Vec3<f32>
}

impl Mesh {
    fn new(tri: Vec<Triangle>) -> Mesh {
        // Compute AABB
        let mut aabb_min = Vec3::new(f32::MAX, f32::MAX, f32::MAX);
        let mut aabb_max = Vec3::new(f32::MIN, f32::MIN, f32::MIN);
        for t in &tri {
            for v in &[t.v0.p, t.v1.p, t.v2.p] {
                aabb_min.x = if aabb_min.x < v.x { aabb_min.x } else { v.x };
                aabb_min.y = if aabb_min.y < v.y { aabb_min.y } else { v.y };
                aabb_min.z = if aabb_min.z < v.z { aabb_min.z } else { v.z };
                aabb_max.x = if aabb_max.x > v.x { aabb_max.x } else { v.x };
                aabb_max.y = if aabb_max.y > v.y { aabb_max.y } else { v.y };
                aabb_max.z = if aabb_max.z > v.z { aabb_max.z } else { v.z };
            }
        }

        Mesh { tri: tri, aabb_min: aabb_min, aabb_max: aabb_max }
    }
}

// We either have 'Px Py Pz ColR ColB ColG UVx UVy' with bogus UVs and radiosity data
// in the color channel or 'Px Py Pz Nx Ny Nz UVx UVy' with ambient occlusion in both
// texture coordinates
#[derive(PartialEq)]
enum MeshFileType { XyzRgbXx, XyzNxnynzAoao }

fn load_mesh(file_name: &String, mesh_file_type: MeshFileType) -> Mesh {
    // Load a text format mesh from disk

    let path = path::Path::new(file_name);
    let display = path.display();

    // Open mesh file
    let mut file = match File::open(&path) {
        Err(why) => panic!("load_mesh(): Couldn't open {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file
    };

    // Read entire mesh file into memory
    let mut data_str = String::new();
    match file.read_to_string(&mut data_str) {
        Err(why) => panic!("load_mesh(): Couldn't read {}: {}",
                           display,
                           Error::description(&why)),
        Ok(_)    => ()
    };

    // Parse mesh format line-by-line
    let mut lines = data_str.lines();

    // Comment header / vertex count
    let vtx_cnt;
    loop {
        match lines.next() {
            Some("") => (), // Skip empty lines
            Some(ln) => {
                let words: Vec<&str> = ln.split(" ").collect();
                if words[0] == "#" { continue } // Skip comments
                // First non-empty, non-comment line should contain the vertex count
                vtx_cnt = match words[0].parse::<u32>() {
                    Err(why) => panic!("load_mesh(): Can't parse vertex count: {}: {}",
                                       Error::description(&why),
                                       display),
                    Ok(n)    => n
                };
                break;
            }
            None => panic!("load_mesh(): EOF while parsing vertex count: {}", display)
        }
    }

    // Vertices
    let mut vtx: Vec<Vertex> = Vec::new();
    loop {
        match lines.next() {
            Some("") => (), // Skip empty lines
            Some(ln) => {
                let mut words = ln.split(" ");
                let words_collect: Vec<&str> = words.clone().collect();
                if words_collect.len() != 8 {
                    panic!("load_mesh(): Expected 8 component vertices: {}", display);
                }
                let mut components: Vec<f32> = Vec::new();
                for _ in 0..8 {
                    components.push(words.next().unwrap().parse::<f32>().unwrap());
                }
                match mesh_file_type {
                    MeshFileType::XyzRgbXx =>
                        vtx.push(Vertex::new(components[0],
                                             components[1],
                                             components[2],
                                             0.0, 0.0, 0.0, // Compute the normal later
                                             components[3],
                                             components[4],
                                             components[5]
                                            )),
                    MeshFileType::XyzNxnynzAoao =>
                        vtx.push(Vertex::new(components[0],
                                             components[1],
                                             components[2],
                                             components[3],
                                             components[4],
                                             components[5],
                                             components[6],
                                             components[6],
                                             components[6]
                                            ))
                }
                // Done?
                if vtx.len() == vtx_cnt as usize { break }
            }
            None => panic!("load_mesh(): EOF while parsing vertices: {}", display)
        }
    }
    if vtx_cnt < 3 {
        panic!("load_mesh(): Bogus vertex count: {}: {}", vtx_cnt, display)
    }

    // Index count
    let idx_cnt;
    loop {
        match lines.next() {
            Some("") => (), // Skip empty lines
            Some(ln) => {
                // First non-empty, non-comment line should contain the index count
                idx_cnt = match ln.parse::<u32>() {
                    Err(why) => panic!("load_mesh(): Can't parse index count: {}: {}",
                                       Error::description(&why),
                                       display),
                    Ok(n)    => n
                };
                break;
            }
            None => panic!("load_mesh(): EOF while parsing index count: {}", display)
        }
    }
    if idx_cnt % 3 != 0 {
        panic!("load_mesh(): Bogus index count: {}: {}", idx_cnt, display)
    }

    // Indices
    let mut idx: Vec<(u32, u32, u32)> = Vec::new();
    loop {
        match lines.next() {
            Some("") => (), // Skip empty lines
            Some(ln) => {
                let mut words = ln.split(" ");
                let words_collect: Vec<&str> = words.clone().collect();
                if words_collect.len() != 3 {
                    panic!("load_mesh(): Expected 3 component indexed triangles: {}", display);
                }
                let mut components: Vec<u32> = Vec::new();
                for _ in 0..3 {
                    components.push(words.next().unwrap().parse::<u32>().unwrap());
                }
                idx.push((components[0], components[1], components[2]));
                // Done?
                if idx.len() * 3 == idx_cnt as usize { break }
            }
            None => panic!("load_mesh(): EOF while parsing indices: {}", display)
        }
    }

    // Assemble triangle vector and mesh
    let mut triangles = Vec::new();
    for tri_idx in idx {
        let mut ntri = Triangle::new(&vtx[tri_idx.0 as usize],
                                     &vtx[tri_idx.1 as usize],
                                     &vtx[tri_idx.2 as usize]);
        if mesh_file_type == MeshFileType::XyzRgbXx {
            // Set vertex normals from face normal
            let n = ntri.face_normal();
            ntri.v0.n = n;
            ntri.v1.n = n;
            ntri.v2.n = n;
        }
        triangles.push(ntri);
    }
    let mesh = Mesh::new(triangles);

    // Print some mesh information
    println!("load_mesh(): Loaded {} tri and {} vtx from {}, AABB ({}, {}, {}) - ({}, {}, {})",
        mesh.tri.len(), vtx.len(), display,
        mesh.aabb_min.x, mesh.aabb_min.y, mesh.aabb_min.z,
        mesh.aabb_max.x, mesh.aabb_max.y, mesh.aabb_max.z);

    mesh
}

#[no_mangle]
pub extern fn rast_draw(tick: f64, w: i32, h: i32, fb: *mut u32) -> () {
    let cornell_mesh = CORNELL_MESH.lock().unwrap();
    let head_mesh = HEAD_MESH.lock().unwrap();

    // Background gradient
    // let start = Vec3::new(1.0, 0.4, 0.0);
    // let end   = Vec3::new(0.0, 0.5, 0.5);
    let start = Vec3::new(0.3, 0.3, 0.3);
    let end   = Vec3::new(0.7, 0.7, 0.7);
    for y in 0..h {
        let pos   = y as f32 / (h - 1) as f32;
        let col   = start * (1.0 - pos) + end * pos;
        let col32 = rgbf_to_abgr32(col.x, col.y, col.z);
        for x in 0..w {
            unsafe {
                * fb.offset((x + y * w) as isize) = col32;
            }
        }
    }
}

fn rgbf_to_abgr32(r: f32, g: f32, b: f32) -> u32 {
    let r8 = (clamp(r, 0.0, 1.0) * 255.0) as u32;
    let g8 = (clamp(g, 0.0, 1.0) * 255.0) as u32;
    let b8 = (clamp(b, 0.0, 1.0) * 255.0) as u32;
    r8 | (g8 << 8) | (b8 << 16)
}

<|endoftext|>


<commit_before>use std::rc::Rc;

#[derive(Debug, Clone)]
struct ListNode {
    val: i32,
    next: Option<Box<ListNode>>,
}

impl ListNode {
    fn new(i: i32) -> Self {
        ListNode { val: i, next: None }
    }

    //:= https://stackoverflow.com/questions/50957738/how-to-copy-a-raw-pointer-in-rust?noredirect=1#comment88913158_50957738
    /*
    fn add_l(&mut self, l: &Vec<i32>) {
        //let mut p: *mut ListNode = self as *mut ListNode;
        let org = self;
        let mut p: *mut ListNode = org as *mut ListNode;

        for i in l {
            unsafe {
                //println!("{:?}", *p);
                (*p).next = Some(Box::new(ListNode::new(*i)));
                let temp_b = Box::from_raw(p);
                p = Box::into_raw(temp_b.next.unwrap());
            };
        }
    }*/

    //https://stackoverflow.com/questions/50957738/how-to-copy-a-raw-pointer-when-implementing-a-linked-list-in-rust/50970414#50970414
    fn add_l(&mut self, l: &[i32]) {
        let mut head = self;

        for &val in l {
            head.next = Some(Box::new(ListNode::new(val)));
            head = { head }.next.as_mut().unwrap();
        }
    }

    fn add(&mut self, i: &i32) {
        self.next = Some(Box::new(ListNode::new(*i)));
    }

    fn add_head(self, i: i32) -> Self {
        ListNode {
            val: i,
            next: Some(Box::new(self)),
        }
    }

    fn new_l(l: Vec<i32>) -> Self {
        let mut inner_l = l;
        let mut temp = Self::new(*&inner_l.pop().unwrap());
        for i in inner_l.into_iter().rev() {
            temp = temp.add_head(i)
        }
        temp
    }

    fn removeNthFromEnd(&mut self, n: i32) {
        //let mut head_1 = { self }.next.as_ref().unwrap();
        let mut head_2 = { self }.next.as_ref().unwrap();
        let mut n_h = 0;

        for _ in 1..n {
            head_2 = { head_2 }.next.as_ref().unwrap();
        }

        while let Some(_) = { &head_2 }.next {
            //head_1 = { head_1 }.next.as_mut().unwrap();
            n_h += 1;
            head_2 = { head_2 }.next.as_ref().unwrap();
        }
    }
}
fn main() {
    //let mut a = ListNode::new(1);
    //a.add_l(&vec![2, 3, 4, 5]);

    let mut a = ListNode::new_l(vec![1, 2, 3, 4, 5]);
    a.removeNthFromEnd(1);
    println!("{:?}", a);
}
<commit_msg>a lot of bugs, but at least finished<commit_after>#[derive(Debug, Clone)]
struct ListNode {
    val: i32,
    next: Option<Box<ListNode>>,
}

impl Default for ListNode {
    fn default() -> ListNode {
        ListNode { val: 0, next: None }
    }
}

impl ListNode {
    fn new(i: i32) -> Self {
        ListNode { val: i, next: None }
    }

    //:= https://stackoverflow.com/questions/50957738/how-to-copy-a-raw-pointer-in-rust?noredirect=1#comment88913158_50957738
    /*
    fn add_l(&mut self, l: &Vec<i32>) {
        //let mut p: *mut ListNode = self as *mut ListNode;
        let org = self;
        let mut p: *mut ListNode = org as *mut ListNode;

        for i in l {
            unsafe {
                //println!("{:?}", *p);
                (*p).next = Some(Box::new(ListNode::new(*i)));
                let temp_b = Box::from_raw(p);
                p = Box::into_raw(temp_b.next.unwrap());
            };
        }
    }*/

    //https://stackoverflow.com/questions/50957738/how-to-copy-a-raw-pointer-when-implementing-a-linked-list-in-rust/50970414#50970414
    fn add_l(&mut self, l: &[i32]) {
        let mut head = self;

        for &val in l {
            head.next = Some(Box::new(ListNode::new(val)));
            head = { head }.next.as_mut().unwrap();
        }
    }

    fn add(&mut self, i: &i32) {
        self.next = Some(Box::new(ListNode::new(*i)));
    }

    fn add_head(self, i: i32) -> Self {
        ListNode {
            val: i,
            next: Some(Box::new(self)),
        }
    }

    fn new_l(l: Vec<i32>) -> Self {
        let mut inner_l = l;
        let mut temp = Self::new(*&inner_l.pop().unwrap());
        for i in inner_l.into_iter().rev() {
            temp = temp.add_head(i)
        }
        temp
    }

    fn removeNthFromEnd(&mut self, n: i32) {
        let mut n_h = 1;
        {
            let mut head_2 = self.next.as_ref().unwrap();

            for _ in 1..n {
                head_2 = { head_2 }.next.as_ref().unwrap_or(head_2);
            }

            while let Some(_) = { &head_2 }.next {
                n_h += 1;
                head_2 = { head_2 }.next.as_ref().unwrap();
            }
        }
        println!("number is {}", n_h);

        let mut temp: Option<Box<ListNode>>;
        {
            let mut head_2 = self.next.as_mut().unwrap();
            for _ in 1..n_h {
                head_2 = { head_2 }.next.as_mut().unwrap();
            }
            temp = head_2.next.clone()
        }

        let mut head_2 = self;

        for _ in 1..n_h {
            head_2 = { head_2 }.next.as_mut().unwrap();
        }
        head_2.next = temp;
    }
}

fn main() {
    //Known bug: cannot delete first element.
    //Of course cannot move list which own only one element (will panic)

    let mut a = ListNode::new_l(vec![1, 2, 3, 4, 5]);
    a.removeNthFromEnd(2);
    println!("{:?}", a);

    let mut b = ListNode::new_l(vec![1, 2]);
    b.removeNthFromEnd(1);
    println!("{:?}", b);

    //Failed! Panic
    //let mut c = ListNode::new_l(vec![1]);
    //c.removeNthFromEnd(1);
    //println!("{:?}", c);
}
<|endoftext|>


<commit_before>#![deny(warnings)]

use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    if let Some(channel) = version_check::Channel::read() {
        if channel.supports_features() {
            println!("cargo:rustc-cfg=feature=\"specialize\"");
            println!("cargo:rustc-cfg=feature=\"stdsimd\"");
        }
    }
    let os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set");
    if os.eq_ignore_ascii_case("linux")
        || os.eq_ignore_ascii_case("android")
        || os.eq_ignore_ascii_case("windows")
        || os.eq_ignore_ascii_case("macos")
        || os.eq_ignore_ascii_case("ios")
        || os.eq_ignore_ascii_case("freebsd")
        || os.eq_ignore_ascii_case("openbsd")
        || os.eq_ignore_ascii_case("dragonfly")
        || os.eq_ignore_ascii_case("solaris")
        || os.eq_ignore_ascii_case("illumos")
        || os.eq_ignore_ascii_case("fuchsia")
        || os.eq_ignore_ascii_case("redox")
        || os.eq_ignore_ascii_case("cloudabi")
        || os.eq_ignore_ascii_case("haiku")
        || os.eq_ignore_ascii_case("vxworks")
        || os.eq_ignore_ascii_case("emscripten")
        || os.eq_ignore_ascii_case("wasi")
    {
        println!("cargo:rustc-cfg=feature=\"runtime-rng\"");
    }
    let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set");
    if arch.eq_ignore_ascii_case("x86_64")
        || arch.eq_ignore_ascii_case("aarch64")
        || arch.eq_ignore_ascii_case("mips64")
        || arch.eq_ignore_ascii_case("powerpc64")
        || arch.eq_ignore_ascii_case("riscv64gc")
        || arch.eq_ignore_ascii_case("s390x")
    {
        println!("cargo:rustc-cfg=feature=\"folded_multiply\"");
    }

}
<commit_msg>Issue #117: Support compiling without min_specialization and stdsimd<commit_after>#![deny(warnings)]

use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    if let Some(true) = version_check::supports_feature("specialize") {
        println!("cargo:rustc-cfg=feature=\"specialize\"");
    }
    if let Some(true) = version_check::supports_feature("stdsimd") {
        println!("cargo:rustc-cfg=feature=\"stdsimd\"");
    }
    let os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set");
    if os.eq_ignore_ascii_case("linux")
        || os.eq_ignore_ascii_case("android")
        || os.eq_ignore_ascii_case("windows")
        || os.eq_ignore_ascii_case("macos")
        || os.eq_ignore_ascii_case("ios")
        || os.eq_ignore_ascii_case("freebsd")
        || os.eq_ignore_ascii_case("openbsd")
        || os.eq_ignore_ascii_case("dragonfly")
        || os.eq_ignore_ascii_case("solaris")
        || os.eq_ignore_ascii_case("illumos")
        || os.eq_ignore_ascii_case("fuchsia")
        || os.eq_ignore_ascii_case("redox")
        || os.eq_ignore_ascii_case("cloudabi")
        || os.eq_ignore_ascii_case("haiku")
        || os.eq_ignore_ascii_case("vxworks")
        || os.eq_ignore_ascii_case("emscripten")
        || os.eq_ignore_ascii_case("wasi")
    {
        println!("cargo:rustc-cfg=feature=\"runtime-rng\"");
    }
    let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set");
    if arch.eq_ignore_ascii_case("x86_64")
        || arch.eq_ignore_ascii_case("aarch64")
        || arch.eq_ignore_ascii_case("mips64")
        || arch.eq_ignore_ascii_case("powerpc64")
        || arch.eq_ignore_ascii_case("riscv64gc")
        || arch.eq_ignore_ascii_case("s390x")
    {
        println!("cargo:rustc-cfg=feature=\"folded_multiply\"");
    }

}
<|endoftext|>


<commit_before>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

struct Ignore;

impl<E> From<E> for Ignore where E: Error
{
    fn from(_: E) -> Ignore { Ignore }
}

fn main() {
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    File::create(out_dir.join("commit-info.txt")).unwrap()
                                                 .write_all(commit_info().as_bytes())
                                                 .unwrap();
    println!("cargo:rerun-if-changed=build.rs");
}

fn commit_info() -> String {
    match (commit_date(), commit_hash()) {
        (Ok(date), Ok(hash)) => format!(" {} {}", date.trim_right(), hash.trim_right(),),
        _ => String::new(),
    }
}

fn commit_hash() -> Result<String, Ignore> {
    Ok(String::from_utf8(Command::new("git").args(&["rev-parse",
                                                    "--short=10",
                                                    "HEAD"])
                                            .output()?
                                            .stdout)?)
}

fn commit_date() -> Result<String, Ignore> {
    Ok(String::from_utf8(Command::new("git").args(&["log",
                                                    "-1",
                                                    "--date=short",
                                                    "--pretty=format:%cd"])
                                            .output()?
                                            .stdout)?)
}
<commit_msg>Use trim_end instead of trim_right<commit_after>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

struct Ignore;

impl<E> From<E> for Ignore where E: Error
{
    fn from(_: E) -> Ignore { Ignore }
}

fn main() {
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    File::create(out_dir.join("commit-info.txt")).unwrap()
                                                 .write_all(commit_info().as_bytes())
                                                 .unwrap();
    println!("cargo:rerun-if-changed=build.rs");
}

fn commit_info() -> String {
    match (commit_date(), commit_hash()) {
        (Ok(date), Ok(hash)) => format!(" {} {}", date.trim_end(), hash.trim_end(),),
        _ => String::new(),
    }
}

fn commit_hash() -> Result<String, Ignore> {
    Ok(String::from_utf8(Command::new("git").args(&["rev-parse",
                                                    "--short=10",
                                                    "HEAD"])
                                            .output()?
                                            .stdout)?)
}

fn commit_date() -> Result<String, Ignore> {
    Ok(String::from_utf8(Command::new("git").args(&["log",
                                                    "-1",
                                                    "--date=short",
                                                    "--pretty=format:%cd"])
                                            .output()?
                                            .stdout)?)
}
<|endoftext|>


<commit_before>extern crate pkg_config;

use std::process::Command;
use std::fs;
use std::path::Path;
use std::env;
use std::path::PathBuf;

fn main() {
    let wcd = env::current_dir().unwrap();
    let build = PathBuf::from(&wcd.join("ext/libqmlrswrapper/build"));

    let _ = fs::create_dir_all(&build);

    let mut myargs = vec![".."] ;

    /*
     * Support Qt installed via the Ports system on BSD-like systems.
     *
     * The native libs are in `/usr/local/lib`, which is not linked against by default.
     * This means that either the user or every package has to add this if they want to link
     * against something that is not part of the core distribution in `/usr/lib`.
     *
     * See https://wiki.freebsd.org/WarnerLosh/UsrLocal for the line of reasoning & how this will
     * change in the future.
     */
    if cfg!(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",
                target_os = "dragonfly", target_os = "bitrig")) {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    /*
     * Prameters for supporting QT on OS X installed via homebres
     *
     * Because QT5 conflicts with QT4 the homebrew package manager won't link
     * the QT5 package into the default search paths for libraries, to deal
     * with this we need to give pkg-config and cmake a nudge in the right
     * direction.
     */
    if cfg!(target_os = "macos") {
        // Point at homebrew's QT5 install location, this will likely fail if
        // another package manager was used.
        let qt5_lib_path = Path::new("/usr/local/opt/qt5/lib");

        if Path::exists(qt5_lib_path) {
            // First nudge cmake in the direction of the .cmake files added by
            // homebrew. This clobbers the existing value if present, it's
            // unlikely to be present though.
            env::set_var("CMAKE_PREFIX_PATH", qt5_lib_path.join("cmake"));

            // Nudge pkg-config in the direction of the brewed QT to ensure the
            // correct compiler flags get found for the project.
            env::set_var("PKG_CONFIG_PATH", qt5_lib_path.join("pkgconfig"));
        } else {
            panic!("The QT5 was not found at the expected location ({}) please install it via homebrew.", qt5_lib_path.display());
        }
    }

    let is_msys = env::var("MSYSTEM").is_ok() ;
    if cfg!(windows) && is_msys {
        myargs.push("-GMSYS Makefiles") ;
    }
    Command::new("cmake").args(&myargs).current_dir(&build).output().unwrap_or_else(|e| {
        panic!("Failed to run cmake: {}", e);
    });

    Command::new("make").current_dir(&build).output().unwrap_or_else(|e| {
        panic!("Failed to run make: {}", e);
    });

    if cfg!(windows) && is_msys {
        println!("cargo:rustc-link-search=native={}\\system32",env::var("WINDIR").unwrap());
    }
    println!("cargo:rustc-link-lib=static=qmlrswrapper");
    println!("cargo:rustc-link-lib=dylib=stdc++");
    println!("cargo:rustc-link-search=native={}",build.display());
    pkg_config::find_library("Qt5Core Qt5Gui Qt5Qml Qt5Quick").unwrap();
}
<commit_msg>Panic if cmake produces output<commit_after>extern crate pkg_config;

use std::process::Command;
use std::fs;
use std::path::Path;
use std::env;
use std::path::PathBuf;

fn main() {
    let wcd = env::current_dir().unwrap();
    let build = PathBuf::from(&wcd.join("ext/libqmlrswrapper/build"));

    let _ = fs::create_dir_all(&build);

    let mut myargs = vec![".."] ;

    /*
     * Support Qt installed via the Ports system on BSD-like systems.
     *
     * The native libs are in `/usr/local/lib`, which is not linked against by default.
     * This means that either the user or every package has to add this if they want to link
     * against something that is not part of the core distribution in `/usr/lib`.
     *
     * See https://wiki.freebsd.org/WarnerLosh/UsrLocal for the line of reasoning & how this will
     * change in the future.
     */
    if cfg!(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",
                target_os = "dragonfly", target_os = "bitrig")) {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    /*
     * Prameters for supporting QT on OS X installed via homebres
     *
     * Because QT5 conflicts with QT4 the homebrew package manager won't link
     * the QT5 package into the default search paths for libraries, to deal
     * with this we need to give pkg-config and cmake a nudge in the right
     * direction.
     */
    if cfg!(target_os = "macos") {
        // Point at homebrew's QT5 install location, this will likely fail if
        // another package manager was used.
        let qt5_lib_path = Path::new("/usr/local/opt/qt5/lib");

        if Path::exists(qt5_lib_path) {
            // First nudge cmake in the direction of the .cmake files added by
            // homebrew. This clobbers the existing value if present, it's
            // unlikely to be present though.
            env::set_var("CMAKE_PREFIX_PATH", qt5_lib_path.join("cmake"));

            // Nudge pkg-config in the direction of the brewed QT to ensure the
            // correct compiler flags get found for the project.
            env::set_var("PKG_CONFIG_PATH", qt5_lib_path.join("pkgconfig"));
        } else {
            panic!("The QT5 was not found at the expected location ({}) please install it via homebrew.", qt5_lib_path.display());
        }
    }

    let is_msys = env::var("MSYSTEM").is_ok() ;
    if cfg!(windows) && is_msys {
        myargs.push("-GMSYS Makefiles") ;
    }

    let cmake_output = Command::new("cmake").args(&myargs).current_dir(&build).output().unwrap_or_else(|e| {
        panic!("Failed to run cmake: {}", e);
    });
    let cmake_stderr = String::from_utf8(cmake_output.stderr).unwrap();
    if !cmake_stderr.is_empty() {
        panic!("cmake produced stderr: {}", cmake_stderr);
    }

    Command::new("make").current_dir(&build).output().unwrap_or_else(|e| {
        panic!("Failed to run make: {}", e);
    });

    if cfg!(windows) && is_msys {
        println!("cargo:rustc-link-search=native={}\\system32",env::var("WINDIR").unwrap());
    }
    println!("cargo:rustc-link-lib=static=qmlrswrapper");
    println!("cargo:rustc-link-lib=dylib=stdc++");
    println!("cargo:rustc-link-search=native={}",build.display());
    pkg_config::find_library("Qt5Core Qt5Gui Qt5Qml Qt5Quick").unwrap();
}
<|endoftext|>


<commit_before>use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    let target = env::var("TARGET").unwrap();
    let target_quad = target.split("-").collect::<Vec<_>>();
    let (arch, _, os, compiler) = (target_quad[0], target_quad[1], target_quad[2], target_quad[3]);
    let bitness = if arch == "x86_64" { 64 } else { 32 };

    // Windows
    if os == "windows" {
        // Currently only supporting mingw
        if compiler != "gnu" {
            panic!("Unsupported compiler");
        }

        // projects
        {
            Command::new("make.exe")
                .current_dir("bgfx")
                .arg(".build/projects/gmake-mingw-gcc")
                .output()
                .unwrap();
        }

        // lib
        {
            Command::new("make.exe")
                .current_dir("bgfx")
                .arg("-R")
                .arg("-C")
                .arg(".build/projects/gmake-mingw-gcc")
                .arg(format!("config=release{}", bitness))
                .arg("bgfx")
                .output()
                .unwrap();
        }

        // link config
        {
            let mut path = PathBuf::from(env::current_dir().unwrap());
            path.push("bgfx");
            path.push(".build");
            path.push(format!("win{}_mingw-gcc", bitness));
            path.push("bin");

            println!("cargo:rustc-link-lib=static=bgfxRelease");
            println!("cargo:rustc-link-search={}", path.as_os_str().to_str().unwrap());
        }
    }
}
<commit_msg>Adding linux to the build script<commit_after>use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    let target = env::var("TARGET").unwrap();
    let target_quad = target.split("-").collect::<Vec<_>>();
    let (arch, _, os, compiler) = (target_quad[0], target_quad[1], target_quad[2], target_quad[3]);
    let bitness = if arch == "x86_64" { 64 } else { 32 };

    match os {
        "windows" => build_windows(bitness, compiler),
        "linux"   => build_linux(bitness, compiler),
        _         => panic!("Unsupported platform"),
    }
}

fn build_windows(bitness: u32, compiler: &str) {
    if compiler != "gnu" {
        panic!("Unsupported compiler");
    }

    // projects
    {
        Command::new("make.exe")
            .current_dir("bgfx")
            .arg(".build/projects/gmake-mingw-gcc")
            .output()
            .unwrap();
    }

    // lib
    {
        Command::new("make.exe")
            .current_dir("bgfx")
            .arg("-R")
            .arg("-C")
            .arg(".build/projects/gmake-mingw-gcc")
            .arg(format!("config=release{}", bitness))
            .arg("bgfx")
            .output()
            .unwrap();
    }

    // link config
    {
        let mut path = PathBuf::from(env::current_dir().unwrap());
        path.push("bgfx");
        path.push(".build");
        path.push(format!("win{}_mingw-gcc", bitness));
        path.push("bin");

        println!("cargo:rustc-link-lib=static=bgfxRelease");
        println!("cargo:rustc-link-search={}", path.as_os_str().to_str().unwrap());
    }
}

fn build_linux(bitness: u32, compiler: &str) {
    if compiler != "gnu" {
        panic!("Unsupported compiler");
    }

    // Generate makefiles
    Command::new("make")
        .current_dir("bgfx")
        .arg(".build/projects/gmake-linux")
        .output()
        .unwrap();

    // Build bgfx
    let status = Command::new("make")
        .current_dir("bgfx")
        .arg("-R")
        .arg("-C")
        .arg(".build/projects/gmake-linux")
        .arg(format!("config=release{}", bitness))
        .arg("bgfx")
        .status()
        .unwrap_or_else(|e| panic!("Failed to build bgfx: {}", e));

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx.");
    }

    // Output linker config
    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("linux{}_gcc", bitness));
    path.push("bin");

    println!("cargo:rustc-link-lib=static=bgfxRelease");
    println!("cargo:rustc-link-search={}", path.as_os_str().to_str().unwrap());
}<|endoftext|>


<commit_before>fn env(name: &str) -> Option<std::ffi::OsString> {
    let target = std::env::var("TARGET").expect("Cargo didn't provide `TARGET` environment var");
    let target = target.to_uppercase().replace("-", "_");
    let prefixed_name = format!("{}_{}", target, name);
    println!("cargo:rerun-if-env-changed={}", prefixed_name);
    match std::env::var_os(prefixed_name) {
        Some(v) => Some(v),
        None => {
            println!("cargo:rerun-if-env-changed={}", name);
            std::env::var_os(name)
        }
    }
}

fn main() {
    if let Some(magic_dir) = env("MAGIC_DIR").map(std::path::PathBuf::from) {
        if !std::path::Path::new(&magic_dir).exists() {
            panic!("Magic library directory {:?} does not exist", magic_dir);
        }
        println!("cargo:rustc-link-search=native={}", magic_dir.to_string_lossy());

        let static_lib = magic_dir.join("libmagic.a");
        let shared_lib = magic_dir.join("libmagic.so");
        match env("MAGIC_STATIC").as_ref().and_then(|s| s.to_str()) {
            Some("false") | Some("FALSE") | Some("0") => {
                if !shared_lib.exists() {
                    panic!("No libmagic.so found in {:?}", magic_dir);
                }
                println!("cargo:rustc-link-lib=dylib=magic");
            }
            Some(_) => {
                if !static_lib.exists() {
                    panic!("No libmagic.a found in {:?}", magic_dir);
                }
                println!("cargo:rustc-link-lib=static=magic");
            }
            None => {
                match (static_lib.exists(), shared_lib.exists()) {
                    (false, false) => panic!("Neither libmagic.so, nor libmagic.a was found in {:?}", magic_dir),
                    (true, false) => println!("cargo:rustc-link-lib=static=magic"),
                    (false, true) => println!("cargo:rustc-link-lib=dylib=magic"),
                    (true, true) => panic!("Both a static and a shared library were found in {:?}\nspecify a choice with `MAGIC_STATIC=true|false`", magic_dir),
                }
            }
        }
    } else {
        if let Err(err) = vcpkg::find_package("libmagic") {
            println!("Could not find vcpkg package: {}", err);
        }

        println!("cargo:rustc-link-lib=dylib=magic");
    }
}
<commit_msg>Apply `rustfmt` to all code<commit_after>fn env(name: &str) -> Option<std::ffi::OsString> {
    let target = std::env::var("TARGET").expect("Cargo didn't provide `TARGET` environment var");
    let target = target.to_uppercase().replace("-", "_");
    let prefixed_name = format!("{}_{}", target, name);
    println!("cargo:rerun-if-env-changed={}", prefixed_name);
    match std::env::var_os(prefixed_name) {
        Some(v) => Some(v),
        None => {
            println!("cargo:rerun-if-env-changed={}", name);
            std::env::var_os(name)
        }
    }
}

fn main() {
    if let Some(magic_dir) = env("MAGIC_DIR").map(std::path::PathBuf::from) {
        if !std::path::Path::new(&magic_dir).exists() {
            panic!("Magic library directory {:?} does not exist", magic_dir);
        }
        println!(
            "cargo:rustc-link-search=native={}",
            magic_dir.to_string_lossy()
        );

        let static_lib = magic_dir.join("libmagic.a");
        let shared_lib = magic_dir.join("libmagic.so");
        match env("MAGIC_STATIC").as_ref().and_then(|s| s.to_str()) {
            Some("false") | Some("FALSE") | Some("0") => {
                if !shared_lib.exists() {
                    panic!("No libmagic.so found in {:?}", magic_dir);
                }
                println!("cargo:rustc-link-lib=dylib=magic");
            }
            Some(_) => {
                if !static_lib.exists() {
                    panic!("No libmagic.a found in {:?}", magic_dir);
                }
                println!("cargo:rustc-link-lib=static=magic");
            }
            None => {
                match (static_lib.exists(), shared_lib.exists()) {
                    (false, false) => panic!("Neither libmagic.so, nor libmagic.a was found in {:?}", magic_dir),
                    (true, false) => println!("cargo:rustc-link-lib=static=magic"),
                    (false, true) => println!("cargo:rustc-link-lib=dylib=magic"),
                    (true, true) => panic!("Both a static and a shared library were found in {:?}\nspecify a choice with `MAGIC_STATIC=true|false`", magic_dir),
                }
            }
        }
    } else {
        if let Err(err) = vcpkg::find_package("libmagic") {
            println!("Could not find vcpkg package: {}", err);
        }

        println!("cargo:rustc-link-lib=dylib=magic");
    }
}
<|endoftext|>


<commit_before>fn main() {
    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]
    println!("cargo:rustc-link-search=framework={}", "/System/Library/PrivateFrameworks");
}
<commit_msg>Use xcode-select to find PrivateFramework directory<commit_after>fn main() {
    #[cfg(target_os = "macos")]
    #[cfg(feature = "private_api")]

    // PrivateFramework dir:
    // `xcode-select -p`/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/
    let xcode_dir = std::process::Command::new("xcode-select")
        .arg("-p")
        .output()
        .expect("Failed to run xcode-select");
    let mut xcode_dir = String::from_utf8(xcode_dir.stdout).unwrap();
    xcode_dir.pop(); // remove trailing newline
    let framework_dir = format!("{}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/",
                                xcode_dir);
    println!("XCode PrivateFramework dir: {}", framework_dir);
    println!("cargo:rustc-link-search=framework={}", framework_dir);
}
<|endoftext|>


<commit_before>use crate::{config, convert, open, plugins, serve, upgrade, util::dirs};
use anyhow::{bail, Result};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(
    about = "Stencila command line tool",
    setting = structopt::clap::AppSettings::NoBinaryName,
    setting = structopt::clap::AppSettings::ColoredHelp,
    setting = structopt::clap::AppSettings::VersionlessSubcommands
)]
pub struct Line {
    #[structopt(subcommand)]
    pub command: Command,
}

#[derive(Debug, StructOpt)]
#[structopt(
    setting = structopt::clap::AppSettings::DeriveDisplayOrder
)]
pub enum Command {
    Open(open::cli::Args),
    Convert(convert::cli::Args),
    Serve(serve::cli::Args),
    Plugins(plugins::cli::Args),
    Config(config::cli::Args),
    Upgrade(upgrade::cli::Args),
}

/// Run the interactive REPL
#[cfg(feature = "interact")]
#[tracing::instrument]
pub async fn run(config: &config::Config) -> Result<()> {
    use rustyline::{error::ReadlineError, Editor};

    let history_file = dirs::config(true)?.join("history.txt");

    let mut rl = Editor::<()>::new();
    if rl.load_history(&history_file).is_err() {
        tracing::debug!("No previous history found")
    }

    let mut config = config.clone();

    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(line.as_str());
                let clap = Line::clap();
                let line = line.split_whitespace().collect::<Vec<&str>>();
                match clap.get_matches_from_safe(line) {
                    Ok(matches) => {
                        let Line { command } = Line::from_clap(&matches);
                        if let Err(error) = match command {
                            Command::Open(args) => open::cli::run(args).await,
                            Command::Convert(args) => convert::cli::run(args),
                            Command::Serve(args) => serve::cli::run(args, &config.serve).await,
                            Command::Plugins(args) => {
                                plugins::cli::run(args, &config.plugins).await
                            }
                            Command::Upgrade(args) => upgrade::cli::run(args, &config.upgrade),
                            Command::Config(args) => match config::cli::run(args, &config) {
                                Ok(config_changed) => {
                                    // Update the configuration (may have been changed by `set` and `reset`)
                                    config = config_changed;
                                    Ok(())
                                }
                                Err(err) => Err(err),
                            },
                        } {
                            eprintln!("{}", error)
                        }
                    }
                    Err(error) => {
                        if error.kind == structopt::clap::ErrorKind::VersionDisplayed {
                            print!("{}", error)
                        } else if error.kind == structopt::clap::ErrorKind::HelpDisplayed
                            || error.kind == structopt::clap::ErrorKind::MissingArgumentOrSubcommand
                        {
                            // Remove the unnecessary command / version line at the start
                            let lines = error
                                .to_string()
                                .lines()
                                .skip(1)
                                .map(str::to_string)
                                .collect::<Vec<String>>()
                                .join("\n");
                            print!("{}", lines)
                        } else {
                            tracing::debug!("{:?}", error.kind);
                            eprintln!("{}", error)
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                tracing::info!("Ctrl-C pressed, interrupting current command");
                // TODO
            }
            Err(ReadlineError::Eof) => {
                tracing::info!("Ctrl-D pressed, ending session");
                break;
            }
            Err(error) => bail!(error),
        }
    }
    rl.save_history(&history_file)?;

    Ok(())
}
<commit_msg>fix(Interact): Do not drop last line of help<commit_after>use crate::{config, convert, open, plugins, serve, upgrade, util::dirs};
use anyhow::{bail, Result};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(
    about = "Stencila command line tool",
    setting = structopt::clap::AppSettings::NoBinaryName,
    setting = structopt::clap::AppSettings::ColoredHelp,
    setting = structopt::clap::AppSettings::VersionlessSubcommands
)]
pub struct Line {
    #[structopt(subcommand)]
    pub command: Command,
}

#[derive(Debug, StructOpt)]
#[structopt(
    setting = structopt::clap::AppSettings::DeriveDisplayOrder
)]
pub enum Command {
    Open(open::cli::Args),
    Convert(convert::cli::Args),
    Serve(serve::cli::Args),
    Plugins(plugins::cli::Args),
    Config(config::cli::Args),
    Upgrade(upgrade::cli::Args),
}

/// Run the interactive REPL
#[cfg(feature = "interact")]
#[tracing::instrument]
pub async fn run(config: &config::Config) -> Result<()> {
    use rustyline::{error::ReadlineError, Editor};

    let history_file = dirs::config(true)?.join("history.txt");

    let mut rl = Editor::<()>::new();
    if rl.load_history(&history_file).is_err() {
        tracing::debug!("No previous history found")
    }

    let mut config = config.clone();

    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(line.as_str());
                let clap = Line::clap();
                let line = line.split_whitespace().collect::<Vec<&str>>();
                match clap.get_matches_from_safe(line) {
                    Ok(matches) => {
                        let Line { command } = Line::from_clap(&matches);
                        if let Err(error) = match command {
                            Command::Open(args) => open::cli::run(args).await,
                            Command::Convert(args) => convert::cli::run(args),
                            Command::Serve(args) => serve::cli::run(args, &config.serve).await,
                            Command::Plugins(args) => {
                                plugins::cli::run(args, &config.plugins).await
                            }
                            Command::Upgrade(args) => upgrade::cli::run(args, &config.upgrade),
                            Command::Config(args) => match config::cli::run(args, &config) {
                                Ok(config_changed) => {
                                    // Update the configuration (may have been changed by `set` and `reset`)
                                    config = config_changed;
                                    Ok(())
                                }
                                Err(err) => Err(err),
                            },
                        } {
                            eprintln!("{}", error)
                        }
                    }
                    Err(error) => {
                        if error.kind == structopt::clap::ErrorKind::VersionDisplayed {
                            print!("{}", error)
                        } else if error.kind == structopt::clap::ErrorKind::HelpDisplayed
                            || error.kind == structopt::clap::ErrorKind::MissingArgumentOrSubcommand
                        {
                            // Remove the unnecessary command / version line at the start
                            let lines = format!("{}\n", error)
                                .to_string()
                                .lines()
                                .skip(1)
                                .map(str::to_string)
                                .collect::<Vec<String>>()
                                .join("\n");
                            print!("{}", lines)
                        } else {
                            tracing::debug!("{:?}", error.kind);
                            eprintln!("{}", error)
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                tracing::info!("Ctrl-C pressed, interrupting current command");
                // TODO
            }
            Err(ReadlineError::Eof) => {
                tracing::info!("Ctrl-D pressed, ending session");
                break;
            }
            Err(error) => bail!(error),
        }
    }
    rl.save_history(&history_file)?;

    Ok(())
}
<|endoftext|>


<commit_before>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::fs;
use std::fs::File;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};

use serde::{Deserialize, Serialize};

use crate::files::get_cache_folder;

const METADATA_FILE: &str = "selenium-manager.json";
const TTL_BROWSERS_SEC: u64 = 3600;
const TTL_DRIVERS_SEC: u64 = 86400;

#[derive(Serialize, Deserialize)]
pub struct Browser {
    pub browser_name: String,
    pub browser_version: String,
    pub browser_ttl: u64,
}

#[derive(Serialize, Deserialize)]
pub struct Driver {
    pub browser_version: String,
    pub driver_name: String,
    pub driver_version: String,
    pub driver_ttl: u64,
}

#[derive(Serialize, Deserialize)]
pub struct Metadata {
    pub browsers: Vec<Browser>,
    pub drivers: Vec<Driver>,
}

fn get_metadata_path() -> PathBuf {
    get_cache_folder().join(METADATA_FILE)
}

fn now_unix_timestamp() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs()
}

fn new_metadata() -> Metadata {
    log::trace!("Metadata file does not exist. Creating a new one");
    Metadata {
        browsers: Vec::new(),
        drivers: Vec::new(),
    }
}

pub fn get_metadata() -> Metadata {
    let metadata_path = get_cache_folder().join(METADATA_FILE);
    log::trace!("Reading metadata from {}", metadata_path.display());

    if metadata_path.exists() {
        let metadata_file = File::open(&metadata_path).unwrap();
        let metadata: Metadata = match serde_json::from_reader(&metadata_file) {
            Ok::<Metadata, serde_json::Error>(mut meta) => {
                let now = now_unix_timestamp();
                meta.browsers.retain(|b| b.browser_ttl > now);
                meta.drivers.retain(|d| d.driver_ttl > now);
                meta
            }
            Err(_e) => new_metadata(),
        };
        metadata
    } else {
        new_metadata()
    }
}

pub fn get_browser_version_from_metadata(
    browsers_metadata: &[Browser],
    browser_name: &str,
) -> Option<String> {
    let browser: Vec<&Browser> = browsers_metadata
        .iter()
        .filter(|b| b.browser_name.eq(browser_name))
        .collect();
    if browser.is_empty() {
        None
    } else {
        Some(browser.get(0).unwrap().browser_version.to_string())
    }
}

pub fn get_driver_version_from_metadata(
    drivers_metadata: &[Driver],
    driver_name: &str,
    browser_version: &str,
) -> Option<String> {
    let driver: Vec<&Driver> = drivers_metadata
        .iter()
        .filter(|d| d.driver_name.eq(driver_name) && d.browser_version.eq(browser_version))
        .collect();
    if driver.is_empty() {
        None
    } else {
        Some(driver.get(0).unwrap().driver_version.to_string())
    }
}

pub fn create_browser_metadata(browser_name: &str, browser_version: &String) -> Browser {
    Browser {
        browser_name: browser_name.to_string(),
        browser_version: browser_version.to_string(),
        browser_ttl: now_unix_timestamp() + TTL_BROWSERS_SEC,
    }
}

pub fn create_driver_metadata(
    browser_version: &str,
    driver_name: &str,
    driver_version: &str,
) -> Driver {
    Driver {
        browser_version: browser_version.to_string(),
        driver_name: driver_name.to_string(),
        driver_version: driver_version.to_string(),
        driver_ttl: now_unix_timestamp() + TTL_DRIVERS_SEC,
    }
}

pub fn write_metadata(metadata: &Metadata) {
    let metadata_path = get_metadata_path();
    log::trace!("Writing metadata to {}", metadata_path.display());
    fs::write(
        metadata_path,
        serde_json::to_string_pretty(metadata).unwrap(),
    )
    .unwrap();
}
<commit_msg>[rust] Disable TTL for browsers in Selenium Manager (#11209) (#11278)<commit_after>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::fs;
use std::fs::File;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};

use serde::{Deserialize, Serialize};

use crate::files::get_cache_folder;

const METADATA_FILE: &str = "selenium-manager.json";
const TTL_BROWSERS_SEC: u64 = 0;
const TTL_DRIVERS_SEC: u64 = 86400;

#[derive(Serialize, Deserialize)]
pub struct Browser {
    pub browser_name: String,
    pub browser_version: String,
    pub browser_ttl: u64,
}

#[derive(Serialize, Deserialize)]
pub struct Driver {
    pub browser_version: String,
    pub driver_name: String,
    pub driver_version: String,
    pub driver_ttl: u64,
}

#[derive(Serialize, Deserialize)]
pub struct Metadata {
    pub browsers: Vec<Browser>,
    pub drivers: Vec<Driver>,
}

fn get_metadata_path() -> PathBuf {
    get_cache_folder().join(METADATA_FILE)
}

fn now_unix_timestamp() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs()
}

fn new_metadata() -> Metadata {
    log::trace!("Metadata file does not exist. Creating a new one");
    Metadata {
        browsers: Vec::new(),
        drivers: Vec::new(),
    }
}

pub fn get_metadata() -> Metadata {
    let metadata_path = get_cache_folder().join(METADATA_FILE);
    log::trace!("Reading metadata from {}", metadata_path.display());

    if metadata_path.exists() {
        let metadata_file = File::open(&metadata_path).unwrap();
        let metadata: Metadata = match serde_json::from_reader(&metadata_file) {
            Ok::<Metadata, serde_json::Error>(mut meta) => {
                let now = now_unix_timestamp();
                meta.browsers.retain(|b| b.browser_ttl > now);
                meta.drivers.retain(|d| d.driver_ttl > now);
                meta
            }
            Err(_e) => new_metadata(),
        };
        metadata
    } else {
        new_metadata()
    }
}

pub fn get_browser_version_from_metadata(
    browsers_metadata: &[Browser],
    browser_name: &str,
) -> Option<String> {
    let browser: Vec<&Browser> = browsers_metadata
        .iter()
        .filter(|b| b.browser_name.eq(browser_name))
        .collect();
    if browser.is_empty() {
        None
    } else {
        Some(browser.get(0).unwrap().browser_version.to_string())
    }
}

pub fn get_driver_version_from_metadata(
    drivers_metadata: &[Driver],
    driver_name: &str,
    browser_version: &str,
) -> Option<String> {
    let driver: Vec<&Driver> = drivers_metadata
        .iter()
        .filter(|d| d.driver_name.eq(driver_name) && d.browser_version.eq(browser_version))
        .collect();
    if driver.is_empty() {
        None
    } else {
        Some(driver.get(0).unwrap().driver_version.to_string())
    }
}

pub fn create_browser_metadata(browser_name: &str, browser_version: &String) -> Browser {
    Browser {
        browser_name: browser_name.to_string(),
        browser_version: browser_version.to_string(),
        browser_ttl: now_unix_timestamp() + TTL_BROWSERS_SEC,
    }
}

pub fn create_driver_metadata(
    browser_version: &str,
    driver_name: &str,
    driver_version: &str,
) -> Driver {
    Driver {
        browser_version: browser_version.to_string(),
        driver_name: driver_name.to_string(),
        driver_version: driver_version.to_string(),
        driver_ttl: now_unix_timestamp() + TTL_DRIVERS_SEC,
    }
}

pub fn write_metadata(metadata: &Metadata) {
    let metadata_path = get_metadata_path();
    log::trace!("Writing metadata to {}", metadata_path.display());
    fs::write(
        metadata_path,
        serde_json::to_string_pretty(metadata).unwrap(),
    )
    .unwrap();
}
<|endoftext|>


<commit_before>use nth_prime as np;

#[test]
fn test_first_prime() {
    assert_eq!(np::nth(1), 2);
}

#[test]
#[ignore]
fn test_second_prime() {
    assert_eq!(np::nth(2), 3);
}

#[test]
#[ignore]
fn test_sixth_prime() {
    assert_eq!(np::nth(6), 13);
}

#[test]
#[ignore]
fn test_big_prime() {
    assert_eq!(np::nth(10001), 104743);
}
<commit_msg>Revert "Wrong tests"<commit_after>use nth_prime as np;

#[test]
fn test_first_prime() {
    assert_eq!(np::nth(0), 2);
}

#[test]
#[ignore]
fn test_second_prime() {
    assert_eq!(np::nth(1), 3);
}

#[test]
#[ignore]
fn test_sixth_prime() {
    assert_eq!(np::nth(5), 13);
}

#[test]
#[ignore]
fn test_big_prime() {
    assert_eq!(np::nth(10000), 104743);
}
<|endoftext|>


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

pub struct CodonInfo<'a> {
    actual_codons: HashMap<&'a str, &'a str>
}

pub fn parse<'a>(pairs: Vec<(&'a str, &'a str)>) -> CodonInfo<'a> {
    let mut info = CodonInfo{
        // Allocate once for the worst case, shrink later.
        actual_codons: HashMap::with_capacity(pairs.len())
    };
    for (codon, name) in pairs.into_iter() {
        info.actual_codons.insert(codon, name);
    };
    info.actual_codons.shrink_to_fit();
    info
}

impl<'a> CodonInfo<'a> {
    pub fn name_for(&self, codon: &str) -> Result<&'a str, &'static str> {
        if codon.len() != 3 {
            return Err("invalid length")
        }

        let mut valid = true;
        let lookup: String = codon.chars().map(|l| {
            // Get an example of a "letter" represented by the possibly encoded letter.
            // Since every codon represented by the compressed notation has to be of
            // the desired amino acid just picking one at random will do.
            match l {
                'A' | 'W' | 'M' | 'R' | 'D' | 'H' | 'V' | 'N' => 'A',
                'C' | 'S' | 'Y' | 'B' => 'C',
                'G' | 'K' => 'G',
                'T' => 'T',
                _ => { valid = false; ' ' }
            }
        }).collect();
        if !valid {
            return Err("invalid char")
        }

        // If the input table is correct (which it is) every valid codon is in it
        // so unwrap() shouldn't panic.
        Ok(self.actual_codons.get(&lookup.as_ref()).unwrap())
    }
}
<commit_msg>nucleotide-codons: Use collect<commit_after>use std::collections::HashMap;

pub struct CodonInfo<'a> {
    actual_codons: HashMap<&'a str, &'a str>
}

pub fn parse<'a>(pairs: Vec<(&'a str, &'a str)>) -> CodonInfo<'a> {
    CodonInfo{
        actual_codons: pairs.into_iter().collect()
    }
}

impl<'a> CodonInfo<'a> {
    pub fn name_for(&self, codon: &str) -> Result<&'a str, &'static str> {
        if codon.len() != 3 {
            return Err("invalid length")
        }

        let mut valid = true;
        let lookup: String = codon.chars().map(|l| {
            // Get an example of a "letter" represented by the possibly encoded letter.
            // Since every codon represented by the compressed notation has to be of
            // the desired amino acid just picking one at random will do.
            match l {
                'A' | 'W' | 'M' | 'R' | 'D' | 'H' | 'V' | 'N' => 'A',
                'C' | 'S' | 'Y' | 'B' => 'C',
                'G' | 'K' => 'G',
                'T' => 'T',
                _ => { valid = false; ' ' }
            }
        }).collect();
        if !valid {
            return Err("invalid char")
        }

        // If the input table is correct (which it is) every valid codon is in it
        // so unwrap() shouldn't panic.
        Ok(self.actual_codons.get(&lookup.as_ref()).unwrap())
    }
}
<|endoftext|>


<commit_before>use super::{Result, Specifier, SpecifierClass, SpecifierStack};
use std::rc::Rc;

pub fn spec(s: &str) -> Result<Rc<Specifier>> {
    Specifier::from_stack(SpecifierStack::from_str(s)?)
}

fn some_checks(s:&str) -> Result<()> {
    #[cfg(not(feature = "ssl"))]
    {
        if s.starts_with("wss://") {
            Err("SSL is not compiled in. Use ws:// or get/make another Websocat build.\nYou can also try to workaround missing SSL by using ws-c:cmd:socat trick (see some ws-c: example)")?
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    {
        if s.starts_with("abstract") {
            warn!("Abstract-namespaced UNIX sockets are unlikely to be supported here");
        }
    }

    if s.starts_with("open:") {
        return Err("There is no `open:` address type. Consider `open-async:` or `readfile:` or `writefile:` or `appendfile:`")?;
    }

    #[cfg(not(unix))]
    {
        if s.starts_with("unix") || s.starts_with("abstract") {
            Err("`unix*:` or `abstract*:` are not supported in this Websocat build")?
        }
    }

    #[cfg(not(feature = "tokio-process"))]
    {
        if s.starts_with("sh-c:") {
            Err("`sh-c:` is not supported in this Websocat build")?
        } else if s.starts_with("exec:") {
            Err("`exec:` is not supported in this Websocat build")?
        }
    }

    Ok(())
}

impl SpecifierStack {
    pub fn from_str(s: &str) -> Result<SpecifierStack> {
        some_checks(s)?;

        let mut s = s.to_string();
        let mut overlays = vec![];
        let addrtype;
        let addr;
        let mut found = false;

        'a: loop {
            macro_rules! my {
                ($x:expr) => {
                    for pre in $x.get_prefixes() {
                        if s.starts_with(pre) {
                            let rest = &s[pre.len()..].to_string();
                            if let Some(a) = $x.alias_info() {
                                s = format!("{}{}", a, rest);
                                continue 'a;
                            } else if $x.is_overlay() {
                                overlays.push(Rc::new($x) as Rc<SpecifierClass>);
                                s = rest.to_string();
                                continue 'a;
                            } else {
                                addr = rest.to_string();
                                addrtype = Rc::new($x) as Rc<SpecifierClass>;
                                #[allow(unused_assignments)] {
                                    found = true;
                                }
                                break 'a;
                            }
                        }
                    }
                };
            }
            list_of_all_specifier_classes!(my);
            if ! found {
                Err(format!("Unknown address or overlay type of `{}`", s))?;
            }
        }

        Ok(SpecifierStack { addr, addrtype, overlays })
    }
}

impl Specifier {
    pub fn from_stack(st: SpecifierStack) -> Result<Rc<Specifier>> {
        let mut x = st.addrtype.construct(st.addr.as_str())?;
        for overlay in st.overlays {
            x = overlay.construct_overlay(x)?;
        }
        Ok(x)
    }
}
<commit_msg>Fix order of overlays<commit_after>use super::{Result, Specifier, SpecifierClass, SpecifierStack};
use std::rc::Rc;

pub fn spec(s: &str) -> Result<Rc<Specifier>> {
    Specifier::from_stack(SpecifierStack::from_str(s)?)
}

fn some_checks(s:&str) -> Result<()> {
    #[cfg(not(feature = "ssl"))]
    {
        if s.starts_with("wss://") {
            Err("SSL is not compiled in. Use ws:// or get/make another Websocat build.\nYou can also try to workaround missing SSL by using ws-c:cmd:socat trick (see some ws-c: example)")?
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    {
        if s.starts_with("abstract") {
            warn!("Abstract-namespaced UNIX sockets are unlikely to be supported here");
        }
    }

    if s.starts_with("open:") {
        return Err("There is no `open:` address type. Consider `open-async:` or `readfile:` or `writefile:` or `appendfile:`")?;
    }

    #[cfg(not(unix))]
    {
        if s.starts_with("unix") || s.starts_with("abstract") {
            Err("`unix*:` or `abstract*:` are not supported in this Websocat build")?
        }
    }

    #[cfg(not(feature = "tokio-process"))]
    {
        if s.starts_with("sh-c:") {
            Err("`sh-c:` is not supported in this Websocat build")?
        } else if s.starts_with("exec:") {
            Err("`exec:` is not supported in this Websocat build")?
        }
    }

    Ok(())
}

impl SpecifierStack {
    pub fn from_str(s: &str) -> Result<SpecifierStack> {
        some_checks(s)?;

        let mut s = s.to_string();
        let mut overlays = vec![];
        let addrtype;
        let addr;
        let mut found = false;

        'a: loop {
            macro_rules! my {
                ($x:expr) => {
                    for pre in $x.get_prefixes() {
                        if s.starts_with(pre) {
                            let rest = &s[pre.len()..].to_string();
                            if let Some(a) = $x.alias_info() {
                                s = format!("{}{}", a, rest);
                                continue 'a;
                            } else if $x.is_overlay() {
                                overlays.push(Rc::new($x) as Rc<SpecifierClass>);
                                s = rest.to_string();
                                continue 'a;
                            } else {
                                addr = rest.to_string();
                                addrtype = Rc::new($x) as Rc<SpecifierClass>;
                                #[allow(unused_assignments)] {
                                    found = true;
                                }
                                break 'a;
                            }
                        }
                    }
                };
            }
            list_of_all_specifier_classes!(my);
            if ! found {
                Err(format!("Unknown address or overlay type of `{}`", s))?;
            }
        }

        Ok(SpecifierStack { addr, addrtype, overlays })
    }
}

impl Specifier {
    pub fn from_stack(st: SpecifierStack) -> Result<Rc<Specifier>> {
        let mut x = st.addrtype.construct(st.addr.as_str())?;
        for overlay in st.overlays.iter().rev() {
            x = overlay.construct_overlay(x)?;
        }
        Ok(x)
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(debug_assertions, allow(unused_imports, dead_code))]

use std::collections::HashSet;
use std::time::{UNIX_EPOCH, Duration};

use trust_dns::op::{Message, MessageType, ResponseCode, Query, OpCode, Edns};
use trust_dns::rr::{DNSClass, RecordType, Record, RData, Name};
use trust_dns::rr::rdata::sig::SIG;
use trust_dns::rr::dnssec::Signer;
use openssl::crypto::pkey::Role;
use itertools::Itertools;

use resolver::RcResolver;
use utils::Result;
use recursive::RecursiveResolver;

#[derive(Eq, PartialEq, Debug)]
enum ValidationResult {
    NonAuthenticated,
    Authenticated,
    Bogus,
}
pub trait ResponseValidator {
    fn is_valid(&mut self, msg: &Message) -> bool;
}
pub struct DummyValidator;
impl ResponseValidator for DummyValidator {
    fn is_valid(&mut self, _: &Message) -> bool {
        true
    }
}
pub trait SubqueryResolver {
    fn resolve_sub(&self, q: Query) -> Result<Message>;
}
impl SubqueryResolver for RcResolver {
    fn resolve_sub(&self, q: Query) -> Result<Message> {
        RecursiveResolver::resolve(&q, self.clone())
    }
}
pub struct DnssecValidator<T: SubqueryResolver> {
    resolver: T,
}
impl<T: SubqueryResolver> DnssecValidator<T> {
    pub fn new(resolver: T) -> Self {
        DnssecValidator {
            resolver: resolver,
        }
    }
    fn verify_sig_time(sig: &SIG) -> bool {
        let mut cur_time = UNIX_EPOCH.elapsed()
        .unwrap_or_else(|_| Duration::new(0, 0)).as_secs() as u64;
        cur_time &= 0xffff_ffff;
        let inception = sig.get_sig_inception() as u64;
        if cur_time < inception {
            cur_time += 0x1_0000_0000;
        }
        let expiration = {
            let t = sig.get_sig_expiration() as u64;
            if t < inception {
                t + 0x1_0000_0000
            } else {
                t
            }
        };
        cur_time < expiration
    }
    fn verify_rrsig(&self, rrset: &[Record], rrsigs: &[SIG]) -> Result<ValidationResult> {
        assert!(!rrset.is_empty());
        let rr_name = rrset[0].get_name();
        let rr_class = rrset[0].get_dns_class();
        let rr_type = rrset[0].get_rr_type();
        if rrsigs.is_empty() {
            debug!("No RRSIG for {} {:?} {:?}", rr_name, rr_class, rr_type);
            return Ok(ValidationResult::Bogus);
        }
        debug_assert!(rrset.iter().all(|x| x.get_rr_type() == rr_type));
        debug_assert!(rrset.iter().all(|x| x.get_name() == rr_name));
        debug_assert!(rrsigs.iter().all(|x| x.get_type_covered() == rr_type));
        for sig in rrsigs {
            if !Self::verify_sig_time(sig) {
                debug!("Not in validity time ({} -> {}).",
                       sig.get_sig_inception(), sig.get_sig_expiration());
                continue;
            }
            let signer_name = sig.get_signer_name();
            // The number of labels in the RRset owner name MUST be greater than
            // or equal to the value in the RRSIG RR's Labels field.
            if rr_name.num_labels() < sig.get_num_labels() {
                debug!("Number of labels: name = {} ({}), sig = {}",
                       rr_name.num_labels(), rr_name, sig.get_num_labels());
                continue;
            }
            if !signer_name.zone_of(rr_name) {
                debug!("Signer's name ({}) is not zone of RRset owner name ({})",
                       signer_name, rr_name);
                continue;
            }
            let dnskeys = if rr_type == RecordType::DNSKEY && signer_name == rr_name {
                // TODO: Self-signed, verify DS
                rrset.iter().map(|rec| if let RData::DNSKEY(ref dnskey) = *rec.get_rdata() {
                    dnskey.clone()
                } else {
                    panic!("Invalid record type")
                }).collect_vec()
            } else {
                let mut q = Query::new();
                q.name(signer_name.clone())
                .query_class(rr_class)
                .query_type(RecordType::DNSKEY);
                let resp = try!(self.resolver.resolve_sub(q));
                resp.get_answers().iter().filter_map(|rec| match *rec.get_rdata() {
                    RData::DNSKEY(ref dnskey) => Some(dnskey.clone()),
                    _ => None,
                }).collect_vec()
            };
            for key in dnskeys {
                if key.is_revoke() {
                    debug!("DNSKEY is revoked: {:?}", key);
                    continue;
                }
                if !key.is_zone_key() {
                    continue;
                }
                if *key.get_algorithm() != sig.get_algorithm() {
                    continue;
                }
                let pkey = key.get_algorithm().public_key_from_vec(key.get_public_key());
                let pkey = match pkey {
                    Ok(k) => k,
                    Err(e) => {
                        warn!("Failed to get public key from DNSKEY: {:?}", e);
                        continue
                    },
                };
                if !pkey.can(Role::Verify) {
                    debug!("PKey can't be used to verify: {:?}", key);
                }
                let signer = Signer::new_verifier(
                    *key.get_algorithm(), pkey, signer_name.clone(),
                );
                let rrset_hash: Vec<u8> = signer.hash_rrset(
                    rr_name, rr_class,
                    sig.get_num_labels(), sig.get_type_covered(), sig.get_algorithm(),
                    sig.get_original_ttl(), sig.get_sig_expiration(), sig.get_sig_inception(),
                    sig.get_key_tag(), signer_name, rrset,
                );
                if signer.verify(&rrset_hash, sig.get_sig()) {
                    return Ok(ValidationResult::Authenticated);
                } else {
                    trace!("Failed to verify {} {:?} with {:?}", rr_name, rr_type, key);
                }
            }
        }
        debug!("No valid RRSIG for {} {:?} {:?}", rr_name, rr_class, rr_type);
        Ok(ValidationResult::Bogus)
    }
    // Largely stolen from trust-dns
    fn verify_rrsigs(&self, msg: &Message) -> Result<ValidationResult> {
        let rrsigs = msg.get_answers().iter()
        .chain(msg.get_name_servers())
        .filter(|rr| rr.get_rr_type() == RecordType::RRSIG)
        .collect_vec();

        if rrsigs.is_empty() {
            // TODO: Check whether this zone is really not signed
            debug!("No Sig");
            return Ok(ValidationResult::NonAuthenticated);
        }
        // Group the record sets by name and type
        let mut rrset_types: HashSet<(Name, RecordType)> = HashSet::new();
        msg.get_answers().iter()
        .chain(msg.get_name_servers())
        .filter(|rr| rr.get_rr_type() != RecordType::RRSIG)
        .map(|rr| (rr.get_name().clone(), rr.get_rr_type()))
        .foreach(|rr| { rrset_types.insert(rr); });

        for (name, rr_type) in rrset_types {
            let rrset = msg.get_answers().iter()
            .chain(msg.get_name_servers())
            .filter(|rr| rr.get_rr_type() == rr_type && *rr.get_name() == name)
            .cloned()
            .collect_vec();
            let rrsig = rrsigs.iter()
            .filter(|rr| *rr.get_name() == name)
            .filter_map(|rr| if let RData::SIG(ref sig) = *rr.get_rdata() {
                if sig.get_type_covered() == rr_type {
                    Some(sig.clone())
                } else {
                    None
                }
            } else {
                panic!("Unexpected RData: {:?}", rr)
            })
            .collect_vec();
            if rr_type == RecordType::NS && rrsig.is_empty() && msg.get_answers().is_empty() {
                // NS records are not signed in referral
                continue;
            }
            if try!(self.verify_rrsig(&rrset, &rrsig)) != ValidationResult::Authenticated {
                return Ok(ValidationResult::Bogus);
            }
        }

        // TODO: Verify NSEC/NSEC3
        Ok(ValidationResult::Authenticated)
    }
}
impl<T: SubqueryResolver> ResponseValidator for DnssecValidator<T> {
    fn is_valid(&mut self, msg: &Message) -> bool {
        self.verify_rrsigs(msg).unwrap_or(ValidationResult::Bogus) != ValidationResult::Bogus
    }
}

#[cfg(test)]
mod tests {
    extern crate env_logger;
    use std::time::Duration;
    use trust_dns::op::*;
    use trust_dns::rr::*;
    use super::*;
    use ::query::query;
    use ::resolver::*;
    use ::mioco_config_start;

    fn test_query(domain: &str) -> Message {
        let mut q = Query::new();
        q.name(Name::parse(domain, Some(&Name::root())).unwrap())
        .query_class(DNSClass::IN)
        .query_type(RecordType::A);
        let msg = query(q, "8.8.8.8".parse().unwrap(), Duration::from_secs(5)).unwrap();
        assert!(msg.get_answers().iter().any(|r| r.get_rr_type() == RecordType::RRSIG));
        msg
    }

    #[test]
    fn test_dnssec_valid() {
        env_logger::init().is_ok();
        mioco_config_start(move || {
            let resolver = RcResolver::default();
            let msg = test_query("sigok.verteiltesysteme.net");
            let mut validator = DnssecValidator::new(resolver.clone());
            assert!(validator.is_valid(&msg));
        }).unwrap();
    }
    #[test]
    fn test_dnssec_invalid() {
        env_logger::init().is_ok();
        mioco_config_start(move || {
            let resolver = RcResolver::default();
            let msg = test_query("sigfail.verteiltesysteme.net");
            let mut validator = DnssecValidator::new(resolver.clone());
            assert!(!validator.is_valid(&msg));
        }).unwrap();
    }
}
<commit_msg>DNSSEC: Verify DS<commit_after>#![cfg_attr(debug_assertions, allow(unused_imports, dead_code))]

use std::collections::HashSet;
use std::time::{UNIX_EPOCH, Duration};

use trust_dns::op::{Message, MessageType, ResponseCode, Query, OpCode, Edns};
use trust_dns::rr::{DNSClass, RecordType, Record, RData, Name};
use trust_dns::rr::rdata::sig::SIG;
use trust_dns::rr::dnssec::{Signer, TrustAnchor};
use trust_dns::serialize::binary::{BinEncoder, BinSerializable};
use openssl::crypto::pkey::Role;
use itertools::Itertools;

use resolver::RcResolver;
use utils::Result;
use recursive::RecursiveResolver;

lazy_static! {
    static ref TRUST_ANCHOR: TrustAnchor = TrustAnchor::default();
}

#[derive(Eq, PartialEq, Debug)]
enum ValidationResult {
    NonAuthenticated,
    Authenticated,
    Bogus,
}
pub trait ResponseValidator {
    fn is_valid(&mut self, msg: &Message) -> bool;
}
pub struct DummyValidator;
impl ResponseValidator for DummyValidator {
    fn is_valid(&mut self, _: &Message) -> bool {
        true
    }
}
pub trait SubqueryResolver {
    fn resolve_sub(&self, q: Query) -> Result<Message>;
}
impl SubqueryResolver for RcResolver {
    fn resolve_sub(&self, q: Query) -> Result<Message> {
        RecursiveResolver::resolve(&q, self.clone())
    }
}
pub struct DnssecValidator<T: SubqueryResolver> {
    resolver: T,
}
impl<T: SubqueryResolver> DnssecValidator<T> {
    pub fn new(resolver: T) -> Self {
        DnssecValidator {
            resolver: resolver,
        }
    }
    fn verify_sig_time(sig: &SIG) -> bool {
        let mut cur_time = UNIX_EPOCH.elapsed()
        .unwrap_or_else(|_| Duration::new(0, 0)).as_secs() as u64;
        cur_time &= 0xffff_ffff;
        let inception = sig.get_sig_inception() as u64;
        if cur_time < inception {
            cur_time += 0x1_0000_0000;
        }
        let expiration = {
            let t = sig.get_sig_expiration() as u64;
            if t < inception {
                t + 0x1_0000_0000
            } else {
                t
            }
        };
        cur_time < expiration
    }
    fn verify_ds(&self, dnskey: &Record) -> Result<bool> {
        let (public_key, algorithm) = if let RData::DNSKEY(ref rdata) = *dnskey.get_rdata() {
            (rdata.get_public_key(), rdata.get_algorithm())
        } else {
            panic!("Invalid record type")
        };
        if TRUST_ANCHOR.contains(public_key) {
            return Ok(true);
        }
        let name = dnskey.get_name();
        if name.is_root() {
            // Avoid infinite loop
            return Ok(false);
        }
        let mut q = Query::new();
        q.name(dnskey.get_name().clone());
        q.query_type(RecordType::DS);
        q.query_class(dnskey.get_dns_class());
        let ds_resp = try!(self.resolver.resolve_sub(q));
        let mut buf = Vec::<u8>::new();
        {
            let mut encoder = BinEncoder::new(&mut buf);
            encoder.set_canonical_names(true);
            try!(dnskey.get_name().emit(&mut encoder));
            try!(dnskey.get_rdata().emit(&mut encoder));
        }
        Ok(ds_resp.get_answers().iter().any(|x| match *x.get_rdata() {
            RData::DS(ref ds) if ds.get_algorithm() == algorithm => {
                let hash = ds.get_digest_type().hash(&buf);
                hash == ds.get_digest()
            },
            _ => false,
        }))
    }
    fn verify_rrsig(&self, rrset: &[Record], rrsigs: &[SIG]) -> Result<ValidationResult> {
        assert!(!rrset.is_empty());
        let rr_name = rrset[0].get_name();
        let rr_class = rrset[0].get_dns_class();
        let rr_type = rrset[0].get_rr_type();
        if rrsigs.is_empty() {
            debug!("No RRSIG for {} {:?} {:?}", rr_name, rr_class, rr_type);
            return Ok(ValidationResult::Bogus);
        }
        debug_assert!(rrset.iter().all(|x| x.get_rr_type() == rr_type));
        debug_assert!(rrset.iter().all(|x| x.get_name() == rr_name));
        debug_assert!(rrsigs.iter().all(|x| x.get_type_covered() == rr_type));
        for sig in rrsigs {
            if !Self::verify_sig_time(sig) {
                debug!("Not in validity time ({} -> {}).",
                       sig.get_sig_inception(), sig.get_sig_expiration());
                continue;
            }
            let signer_name = sig.get_signer_name();
            // The number of labels in the RRset owner name MUST be greater than
            // or equal to the value in the RRSIG RR's Labels field.
            if rr_name.num_labels() < sig.get_num_labels() {
                debug!("Number of labels: name = {} ({}), sig = {}",
                       rr_name.num_labels(), rr_name, sig.get_num_labels());
                continue;
            }
            if !signer_name.zone_of(rr_name) {
                debug!("Signer's name ({}) is not zone of RRset owner name ({})",
                       signer_name, rr_name);
                continue;
            }
            let dnskeys = if rr_type == RecordType::DNSKEY && signer_name == rr_name {
                rrset.iter()
                .filter(|rec| self.verify_ds(rec).unwrap_or(false))
                .map(|rec| if let RData::DNSKEY(ref dnskey) = *rec.get_rdata() {
                    dnskey.clone()
                } else {
                    panic!("Invalid record type")
                }).collect_vec()
            } else {
                let mut q = Query::new();
                q.name(signer_name.clone())
                .query_class(rr_class)
                .query_type(RecordType::DNSKEY);
                let resp = try!(self.resolver.resolve_sub(q));
                resp.get_answers().iter().filter_map(|rec| match *rec.get_rdata() {
                    RData::DNSKEY(ref dnskey) => Some(dnskey.clone()),
                    _ => None,
                }).collect_vec()
            };
            for key in dnskeys {
                if key.is_revoke() {
                    debug!("DNSKEY is revoked: {:?}", key);
                    continue;
                }
                if !key.is_zone_key() {
                    continue;
                }
                if *key.get_algorithm() != sig.get_algorithm() {
                    continue;
                }
                let pkey = key.get_algorithm().public_key_from_vec(key.get_public_key());
                let pkey = match pkey {
                    Ok(k) => k,
                    Err(e) => {
                        warn!("Failed to get public key from DNSKEY: {:?}", e);
                        continue
                    },
                };
                if !pkey.can(Role::Verify) {
                    debug!("PKey can't be used to verify: {:?}", key);
                }
                let signer = Signer::new_verifier(
                    *key.get_algorithm(), pkey, signer_name.clone(),
                );
                let rrset_hash: Vec<u8> = signer.hash_rrset(
                    rr_name, rr_class,
                    sig.get_num_labels(), sig.get_type_covered(), sig.get_algorithm(),
                    sig.get_original_ttl(), sig.get_sig_expiration(), sig.get_sig_inception(),
                    sig.get_key_tag(), signer_name, rrset,
                );
                if signer.verify(&rrset_hash, sig.get_sig()) {
                    return Ok(ValidationResult::Authenticated);
                } else {
                    trace!("Failed to verify {} {:?} with {:?}", rr_name, rr_type, key);
                }
            }
        }
        debug!("No valid RRSIG for {} {:?} {:?}", rr_name, rr_class, rr_type);
        Ok(ValidationResult::Bogus)
    }
    // Largely stolen from trust-dns
    fn verify_rrsigs(&self, msg: &Message) -> Result<ValidationResult> {
        let rrsigs = msg.get_answers().iter()
        .chain(msg.get_name_servers())
        .filter(|rr| rr.get_rr_type() == RecordType::RRSIG)
        .collect_vec();

        if rrsigs.is_empty() {
            // TODO: Check whether this zone is really not signed
            debug!("No Sig");
            return Ok(ValidationResult::NonAuthenticated);
        }
        // Group the record sets by name and type
        let mut rrset_types: HashSet<(Name, RecordType)> = HashSet::new();
        msg.get_answers().iter()
        .chain(msg.get_name_servers())
        .filter(|rr| rr.get_rr_type() != RecordType::RRSIG)
        .map(|rr| (rr.get_name().clone(), rr.get_rr_type()))
        .foreach(|rr| { rrset_types.insert(rr); });

        for (name, rr_type) in rrset_types {
            let rrset = msg.get_answers().iter()
            .chain(msg.get_name_servers())
            .filter(|rr| rr.get_rr_type() == rr_type && *rr.get_name() == name)
            .cloned()
            .collect_vec();
            let rrsig = rrsigs.iter()
            .filter(|rr| *rr.get_name() == name)
            .filter_map(|rr| if let RData::SIG(ref sig) = *rr.get_rdata() {
                if sig.get_type_covered() == rr_type {
                    Some(sig.clone())
                } else {
                    None
                }
            } else {
                panic!("Unexpected RData: {:?}", rr)
            })
            .collect_vec();
            if rr_type == RecordType::NS && rrsig.is_empty() && msg.get_answers().is_empty() {
                // NS records are not signed in referral
                continue;
            }
            if try!(self.verify_rrsig(&rrset, &rrsig)) != ValidationResult::Authenticated {
                return Ok(ValidationResult::Bogus);
            }
        }

        // TODO: Verify NSEC/NSEC3
        Ok(ValidationResult::Authenticated)
    }
}
impl<T: SubqueryResolver> ResponseValidator for DnssecValidator<T> {
    fn is_valid(&mut self, msg: &Message) -> bool {
        self.verify_rrsigs(msg).unwrap_or(ValidationResult::Bogus) != ValidationResult::Bogus
    }
}

#[cfg(test)]
mod tests {
    extern crate env_logger;
    use std::time::Duration;
    use trust_dns::op::*;
    use trust_dns::rr::*;
    use super::*;
    use ::query::query;
    use ::resolver::*;
    use ::mioco_config_start;

    fn test_query(domain: &str) -> Message {
        let mut q = Query::new();
        q.name(Name::parse(domain, Some(&Name::root())).unwrap())
        .query_class(DNSClass::IN)
        .query_type(RecordType::A);
        let msg = query(q, "8.8.8.8".parse().unwrap(), Duration::from_secs(5)).unwrap();
        assert!(msg.get_answers().iter().any(|r| r.get_rr_type() == RecordType::RRSIG));
        msg
    }

    #[test]
    fn test_dnssec_valid() {
        env_logger::init().is_ok();
        mioco_config_start(move || {
            let resolver = RcResolver::default();
            let msg = test_query("sigok.verteiltesysteme.net");
            let mut validator = DnssecValidator::new(resolver.clone());
            assert!(validator.is_valid(&msg));
        }).unwrap();
    }
    #[test]
    fn test_dnssec_invalid() {
        env_logger::init().is_ok();
        mioco_config_start(move || {
            let resolver = RcResolver::default();
            let msg = test_query("sigfail.verteiltesysteme.net");
            let mut validator = DnssecValidator::new(resolver.clone());
            assert!(!validator.is_valid(&msg));
        }).unwrap();
    }
}
<|endoftext|>