<commit_before>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    And,
    Ge,
    Gt,
    Eql,
    Le,
    Lt,
    Minus,
    Neq,
    Or,
    Plus,
    Slash,
    Star,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Equality = 50,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Eql | BinOp::Le | BinOp::Lt |
            BinOp::Neq => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Box<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    Method(Box<Exp>, String, Vec<Box<Exp>>),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Bool(_) | Exp::Call(..) | Exp::Defun(..) | Exp::Float(_) | Exp::InstanceVar(..) |
            Exp::Method(..) | Exp::NewObject(..) | Exp::Null | Exp::Object(_) | Exp::Undefined |
            Exp::Var(_) => Precedence::Const,
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                try!(body.fmt_helper(&mut fmt, indent_level + 2));

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::Method(ref obj, ref name, ref args) => {
                try!(write!(fmt, "{}.{}(", obj, name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

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

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    Empty,
    If(Exp, Box<Stmt>, Option<Box<Stmt>>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    While(Exp, Box<Stmt>),
}

impl Stmt {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! indented_stmt {
            ($stmt:expr) => {
                try!($stmt.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::Empty => Ok(()),
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                indented_stmt!(s);

                if let &Some(ref stmt) = els {
                    try!(write!(fmt, "{}else {{\n", indent));
                    indented_stmt!(stmt);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                try!(stmt.fmt_helper(&mut fmt, indent_level + 2));
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<commit_msg>remove unnecessary AST nodes<commit_after>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    And,
    Ge,
    Gt,
    Eql,
    Le,
    Lt,
    Minus,
    Neq,
    Or,
    Plus,
    Slash,
    Star,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Equality = 50,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Eql | BinOp::Le | BinOp::Lt |
            BinOp::Neq => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Box<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Bool(_) | Exp::Call(..) | Exp::Defun(..) | Exp::Float(_) | Exp::InstanceVar(..) |
            Exp::NewObject(..) | Exp::Null | Exp::Object(_) | Exp::Undefined |
            Exp::Var(_) => Precedence::Const,
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                try!(body.fmt_helper(&mut fmt, indent_level + 2));

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

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

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    If(Exp, Box<Stmt>, Option<Box<Stmt>>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    While(Exp, Box<Stmt>),
}

impl Stmt {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! indented_stmt {
            ($stmt:expr) => {
                try!($stmt.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                indented_stmt!(s);

                if let &Some(ref stmt) = els {
                    try!(write!(fmt, "{}else {{\n", indent));
                    indented_stmt!(stmt);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                try!(stmt.fmt_helper(&mut fmt, indent_level + 2));
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

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


<commit_before>/*
 * chamkho - a word breaker written in Rust
 * Copyright (C) 2015  Vee Satayamas
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
#[macro_use]
extern crate clap;

mod lib;

use clap::App;
use std::io;
use std::io::BufRead;
use std::path::Path;

fn main() {
    let yaml = load_yaml!("cli.yaml");
    let matches = App::from_yaml(yaml).get_matches();
    let lang = matches.value_of("lang");
    let dict_path = match matches.value_of("dict_path") {
        Some(_dict_path) => Path::new(_dict_path),
        None => match lang {
            Some("lao") => lib::lao_path(),
            Some("thai") | Some(_) | None => lib::default_path(),
        },
    };
    let word_delim = match matches.value_of("word_delimiter") {
        Some(word_delim) => word_delim,
        None => "|",
    };
    let dict = lib::load_dict(dict_path).unwrap();

    let cluster_rule_path = match lang {
        Some("lao") => lib::lao_clusters_path(),
        Some("thai") | Some(_) | None => lib::thai_cluster_path(),
    };

    let wordcut = match cluster_rule_path {
        Some(cluster_rule_path) => {
            let cluster_re =
                lib::wordcut_engine::load_cluster_rules(Path::new(&cluster_rule_path)).unwrap();
            lib::Wordcut::new_with_cluster_re(dict, cluster_re)
        }
        None => lib::Wordcut::new(dict),
    };

    for line_opt in io::BufReader::new(io::stdin()).lines() {
        let cleaned_line = match line_opt {
            Ok(line) => line.trim_end_matches('\n').to_string(),
            Err(e) => panic!("Cannot read line {}", e),
        };

        let segmented_string = wordcut.put_delimiters(&cleaned_line, word_delim);
        println!("{}", segmented_string);
    }
}
<commit_msg>Remove LGPL term<commit_after>#[macro_use]
extern crate clap;

mod lib;

use clap::App;
use std::io;
use std::io::BufRead;
use std::path::Path;

fn main() {
    let yaml = load_yaml!("cli.yaml");
    let matches = App::from_yaml(yaml).get_matches();
    let lang = matches.value_of("lang");
    let dict_path = match matches.value_of("dict_path") {
        Some(_dict_path) => Path::new(_dict_path),
        None => match lang {
            Some("lao") => lib::lao_path(),
            Some("thai") | Some(_) | None => lib::default_path(),
        },
    };
    let word_delim = match matches.value_of("word_delimiter") {
        Some(word_delim) => word_delim,
        None => "|",
    };
    let dict = lib::load_dict(dict_path).unwrap();

    let cluster_rule_path = match lang {
        Some("lao") => lib::lao_clusters_path(),
        Some("thai") | Some(_) | None => lib::thai_cluster_path(),
    };

    let wordcut = match cluster_rule_path {
        Some(cluster_rule_path) => {
            let cluster_re =
                lib::wordcut_engine::load_cluster_rules(Path::new(&cluster_rule_path)).unwrap();
            lib::Wordcut::new_with_cluster_re(dict, cluster_re)
        }
        None => lib::Wordcut::new(dict),
    };

    for line_opt in io::BufReader::new(io::stdin()).lines() {
        let cleaned_line = match line_opt {
            Ok(line) => line.trim_end_matches('\n').to_string(),
            Err(e) => panic!("Cannot read line {}", e),
        };

        let segmented_string = wordcut.put_delimiters(&cleaned_line, word_delim);
        println!("{}", segmented_string);
    }
}
<|endoftext|>


<commit_before>use std::ops::Index;

use cgmath::Point3;

use crate::aabb::AABB;
use crate::pt_renderer::{Intersect, Ray};
use crate::stats;
use crate::triangle::RTTriangle;

const MAX_LEAF_SIZE: usize = 8;

#[allow(dead_code)]
#[derive(Clone, Copy)]
pub enum SplitMode {
    Object,
    Spatial,
    SAH,
}

pub struct BVHNode {
    aabb: AABB,
    pub start_i: usize,
    pub end_i: usize,
    left_child_i: Option<usize>,
    right_child_i: Option<usize>,
}

impl BVHNode {
    fn new(triangles: &Triangles) -> BVHNode {
        let start_i = triangles.start_i;
        let end_i = start_i + triangles.len();
        BVHNode {
            aabb: triangles.aabb.clone(),
            start_i,
            end_i,
            left_child_i: None,
            right_child_i: None,
        }
    }

    fn n_tris(&self) -> usize {
        self.end_i - self.start_i
    }

    pub fn is_leaf(&self) -> bool {
        self.left_child_i.is_none()
    }
}

impl Intersect<'_, f32> for BVHNode {
    fn intersect(&self, ray: &Ray) -> Option<f32> {
        self.aabb.intersect(ray)
    }
}

struct Triangles<'a> {
    triangles: &'a [RTTriangle],
    centers: &'a [Point3<f32>],
    indices: &'a mut [usize],
    aabb: AABB,
    /// Node contains indices [start_i, start_i + len) from the main indices array
    start_i: usize,
    /// Axis along which the indices have been sorted
    sorted_axis: usize,
}

impl<'a> Triangles<'a> {
    fn new(
        triangles: &'a [RTTriangle],
        centers: &'a [Point3<f32>],
        indices: &'a mut [usize],
        start_i: usize,
    ) -> Triangles<'a> {
        let mut aabb = AABB::empty();
        for i in indices.iter() {
            let tri = &triangles[*i];
            aabb.add_aabb(&tri.aabb());
        }
        Triangles {
            triangles,
            centers,
            indices,
            aabb,
            start_i,
            // Use bogus value since nothing has been sorted
            sorted_axis: 42,
        }
    }

    fn sort_longest_axis(&mut self) {
        let axis_i = self.aabb.longest_edge_i();
        self.sort(axis_i);
    }

    fn sort(&mut self, axis_i: usize) {
        // The indices are already sorted along the requested axis
        if axis_i == self.sorted_axis {
            return;
        }
        let centers = self.centers;
        self.indices.sort_unstable_by(|i1, i2| {
            let c1 = centers[*i1][axis_i];
            let c2 = centers[*i2][axis_i];
            c1.partial_cmp(&c2).unwrap()
        });
        self.sorted_axis = axis_i;
    }

    fn split(self, i: usize) -> (Triangles<'a>, Triangles<'a>) {
        let (i1, i2) = self.indices.split_at_mut(i);
        let mut node1 = Triangles::new(self.triangles, self.centers, i1, self.start_i);
        let mut node2 = Triangles::new(self.triangles, self.centers, i2, self.start_i + i);
        node1.sorted_axis = self.sorted_axis;
        node2.sorted_axis = self.sorted_axis;
        (node1, node2)
    }

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

    fn last(&self) -> &RTTriangle {
        let i = self.indices.last().unwrap();
        &self.triangles[*i]
    }
}

impl Index<usize> for Triangles<'_> {
    type Output = RTTriangle;

    fn index(&self, i: usize) -> &RTTriangle {
        let i = self.indices[i];
        &self.triangles[i]
    }
}

pub struct BVH {
    nodes: Vec<BVHNode>,
}

impl BVH {
    pub fn empty() -> BVH {
        BVH { nodes: Vec::new() }
    }

    pub fn build(triangles: &[RTTriangle], split_mode: SplitMode) -> (BVH, Vec<usize>) {
        stats::start_bvh();
        let centers: Vec<Point3<f32>> = triangles.iter().map(|ref tri| tri.center()).collect();
        let mut permutation: Vec<usize> = (0..triangles.len()).collect();
        let tris = Triangles::new(triangles, &centers, &mut permutation, 0);
        let mut nodes = Vec::with_capacity(f32::log2(triangles.len() as f32) as usize);
        nodes.push(BVHNode::new(&tris));
        let mut split_stack = vec![(0usize, tris)];

        while let Some((node_i, mut tris)) = split_stack.pop() {
            let mid_offset = match split_mode {
                SplitMode::Object => object_split(&mut tris),
                SplitMode::Spatial => spatial_split(&mut tris),
                SplitMode::SAH => sah_split(&mut tris),
            };
            let (t1, t2) = if let Some(offset) = mid_offset {
                tris.split(offset)
            } else {
                continue;
            };

            let left_child = BVHNode::new(&t1);
            nodes[node_i].left_child_i = Some(nodes.len());
            if left_child.n_tris() > MAX_LEAF_SIZE {
                split_stack.push((nodes.len(), t1));
            }
            nodes.push(left_child);

            let right_child = BVHNode::new(&t2);
            nodes[node_i].right_child_i = Some(nodes.len());
            if right_child.n_tris() > MAX_LEAF_SIZE {
                split_stack.push((nodes.len(), t2));
            }
            nodes.push(right_child);
        }
        nodes.shrink_to_fit();
        let bvh = BVH { nodes };
        stats::stop_bvh(&bvh);
        (bvh, permutation)
    }

    pub fn get_children(&self, node: &BVHNode) -> Option<(&BVHNode, &BVHNode)> {
        if let Some(left_i) = node.left_child_i {
            Some((
                &self.nodes[left_i],
                &self.nodes[node.right_child_i.unwrap()],
            ))
        } else {
            None
        }
    }

    pub fn root(&self) -> &BVHNode {
        &self.nodes[0]
    }

    pub fn size(&self) -> usize {
        self.nodes.len()
    }

    pub fn n_tris(&self) -> usize {
        self.root().n_tris()
    }
}

fn object_split(triangles: &mut Triangles) -> Option<usize> {
    triangles.sort_longest_axis();
    Some(triangles.len() / 2)
}

fn spatial_split(triangles: &mut Triangles) -> Option<usize> {
    let aabb = &triangles.aabb;
    let axis_i = aabb.longest_edge_i();
    let mid_val = aabb.center()[axis_i];
    triangles.sort(axis_i);
    let centers = triangles.centers;
    let i = triangles
        .indices
        .binary_search_by(|i| {
            let c = centers[*i][axis_i];
            c.partial_cmp(&mid_val).unwrap()
        })
        .unwrap_or_else(|e| e);
    // Use object median if all centers are on one side of the median
    if i == 0 || i == triangles.len() {
        object_split(triangles)
    } else {
        Some(i)
    }
}

fn sah_split(triangles: &mut Triangles) -> Option<usize> {
    let mut min_score = std::f32::MAX;
    let mut min_axis = 0;
    let mut min_i = 0;
    let sorted_axis = triangles.sorted_axis;
    for offset in 0..3 {
        // Check the sorted axis first
        let axis = (sorted_axis + offset) % 3;
        triangles.sort(axis);
        // Precompute all right side bbs
        let mut right_bbs = Vec::with_capacity(triangles.len());
        right_bbs.push(triangles.last().aabb());
        for i in 1..triangles.len() {
            let mut new_bb = right_bbs[i - 1].clone();
            new_bb.add_aabb(&triangles[triangles.len() - 1 - i].aabb());
            right_bbs.push(new_bb);
        }
        let mut left_bb = AABB::empty();
        // Go through the possible splits
        for i in 0..triangles.len() {
            left_bb.add_aabb(&triangles[i].aabb());
            let right_bb = &right_bbs[right_bbs.len() - 1 - i];
            let score = i as f32 * left_bb.area() + (triangles.len() - i) as f32 * right_bb.area();
            if score < min_score {
                min_score = score;
                min_axis = axis;
                min_i = i;
            }
        }
    }
    if min_i == 0 {
        None
    } else {
        triangles.sort(min_axis);
        Some(min_i)
    }
}
<commit_msg>Use pattern matching to dereference indices<commit_after>use std::ops::Index;

use cgmath::Point3;

use crate::aabb::AABB;
use crate::pt_renderer::{Intersect, Ray};
use crate::stats;
use crate::triangle::RTTriangle;

const MAX_LEAF_SIZE: usize = 8;

#[allow(dead_code)]
#[derive(Clone, Copy)]
pub enum SplitMode {
    Object,
    Spatial,
    SAH,
}

pub struct BVHNode {
    aabb: AABB,
    pub start_i: usize,
    pub end_i: usize,
    left_child_i: Option<usize>,
    right_child_i: Option<usize>,
}

impl BVHNode {
    fn new(triangles: &Triangles) -> BVHNode {
        let start_i = triangles.start_i;
        let end_i = start_i + triangles.len();
        BVHNode {
            aabb: triangles.aabb.clone(),
            start_i,
            end_i,
            left_child_i: None,
            right_child_i: None,
        }
    }

    fn n_tris(&self) -> usize {
        self.end_i - self.start_i
    }

    pub fn is_leaf(&self) -> bool {
        self.left_child_i.is_none()
    }
}

impl Intersect<'_, f32> for BVHNode {
    fn intersect(&self, ray: &Ray) -> Option<f32> {
        self.aabb.intersect(ray)
    }
}

struct Triangles<'a> {
    triangles: &'a [RTTriangle],
    centers: &'a [Point3<f32>],
    indices: &'a mut [usize],
    aabb: AABB,
    /// Node contains indices [start_i, start_i + len) from the main indices array
    start_i: usize,
    /// Axis along which the indices have been sorted
    sorted_axis: usize,
}

impl<'a> Triangles<'a> {
    fn new(
        triangles: &'a [RTTriangle],
        centers: &'a [Point3<f32>],
        indices: &'a mut [usize],
        start_i: usize,
    ) -> Triangles<'a> {
        let mut aabb = AABB::empty();
        for &i in indices.iter() {
            let tri = &triangles[i];
            aabb.add_aabb(&tri.aabb());
        }
        Triangles {
            triangles,
            centers,
            indices,
            aabb,
            start_i,
            // Use bogus value since nothing has been sorted
            sorted_axis: 42,
        }
    }

    fn sort_longest_axis(&mut self) {
        let axis_i = self.aabb.longest_edge_i();
        self.sort(axis_i);
    }

    fn sort(&mut self, axis_i: usize) {
        // The indices are already sorted along the requested axis
        if axis_i == self.sorted_axis {
            return;
        }
        let centers = self.centers;
        self.indices.sort_unstable_by(|&i1, &i2| {
            let c1 = centers[i1][axis_i];
            let c2 = centers[i2][axis_i];
            c1.partial_cmp(&c2).unwrap()
        });
        self.sorted_axis = axis_i;
    }

    fn split(self, i: usize) -> (Triangles<'a>, Triangles<'a>) {
        let (i1, i2) = self.indices.split_at_mut(i);
        let mut node1 = Triangles::new(self.triangles, self.centers, i1, self.start_i);
        let mut node2 = Triangles::new(self.triangles, self.centers, i2, self.start_i + i);
        node1.sorted_axis = self.sorted_axis;
        node2.sorted_axis = self.sorted_axis;
        (node1, node2)
    }

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

    fn last(&self) -> &RTTriangle {
        let &i = self.indices.last().unwrap();
        &self.triangles[i]
    }
}

impl Index<usize> for Triangles<'_> {
    type Output = RTTriangle;

    fn index(&self, i: usize) -> &RTTriangle {
        let i = self.indices[i];
        &self.triangles[i]
    }
}

pub struct BVH {
    nodes: Vec<BVHNode>,
}

impl BVH {
    pub fn empty() -> BVH {
        BVH { nodes: Vec::new() }
    }

    pub fn build(triangles: &[RTTriangle], split_mode: SplitMode) -> (BVH, Vec<usize>) {
        stats::start_bvh();
        let centers: Vec<Point3<f32>> = triangles.iter().map(|ref tri| tri.center()).collect();
        let mut permutation: Vec<usize> = (0..triangles.len()).collect();
        let tris = Triangles::new(triangles, &centers, &mut permutation, 0);
        let mut nodes = Vec::with_capacity(f32::log2(triangles.len() as f32) as usize);
        nodes.push(BVHNode::new(&tris));
        let mut split_stack = vec![(0usize, tris)];

        while let Some((node_i, mut tris)) = split_stack.pop() {
            let mid_offset = match split_mode {
                SplitMode::Object => object_split(&mut tris),
                SplitMode::Spatial => spatial_split(&mut tris),
                SplitMode::SAH => sah_split(&mut tris),
            };
            let (t1, t2) = if let Some(offset) = mid_offset {
                tris.split(offset)
            } else {
                continue;
            };

            let left_child = BVHNode::new(&t1);
            nodes[node_i].left_child_i = Some(nodes.len());
            if left_child.n_tris() > MAX_LEAF_SIZE {
                split_stack.push((nodes.len(), t1));
            }
            nodes.push(left_child);

            let right_child = BVHNode::new(&t2);
            nodes[node_i].right_child_i = Some(nodes.len());
            if right_child.n_tris() > MAX_LEAF_SIZE {
                split_stack.push((nodes.len(), t2));
            }
            nodes.push(right_child);
        }
        nodes.shrink_to_fit();
        let bvh = BVH { nodes };
        stats::stop_bvh(&bvh);
        (bvh, permutation)
    }

    pub fn get_children(&self, node: &BVHNode) -> Option<(&BVHNode, &BVHNode)> {
        if let Some(left_i) = node.left_child_i {
            Some((
                &self.nodes[left_i],
                &self.nodes[node.right_child_i.unwrap()],
            ))
        } else {
            None
        }
    }

    pub fn root(&self) -> &BVHNode {
        &self.nodes[0]
    }

    pub fn size(&self) -> usize {
        self.nodes.len()
    }

    pub fn n_tris(&self) -> usize {
        self.root().n_tris()
    }
}

fn object_split(triangles: &mut Triangles) -> Option<usize> {
    triangles.sort_longest_axis();
    Some(triangles.len() / 2)
}

fn spatial_split(triangles: &mut Triangles) -> Option<usize> {
    let aabb = &triangles.aabb;
    let axis_i = aabb.longest_edge_i();
    let mid_val = aabb.center()[axis_i];
    triangles.sort(axis_i);
    let centers = triangles.centers;
    let i = triangles
        .indices
        .binary_search_by(|&i| {
            let c = centers[i][axis_i];
            c.partial_cmp(&mid_val).unwrap()
        })
        .unwrap_or_else(|e| e);
    // Use object median if all centers are on one side of the median
    if i == 0 || i == triangles.len() {
        object_split(triangles)
    } else {
        Some(i)
    }
}

fn sah_split(triangles: &mut Triangles) -> Option<usize> {
    let mut min_score = std::f32::MAX;
    let mut min_axis = 0;
    let mut min_i = 0;
    let sorted_axis = triangles.sorted_axis;
    for offset in 0..3 {
        // Check the sorted axis first
        let axis = (sorted_axis + offset) % 3;
        triangles.sort(axis);
        // Precompute all right side bbs
        let mut right_bbs = Vec::with_capacity(triangles.len());
        right_bbs.push(triangles.last().aabb());
        for i in 1..triangles.len() {
            let mut new_bb = right_bbs[i - 1].clone();
            new_bb.add_aabb(&triangles[triangles.len() - 1 - i].aabb());
            right_bbs.push(new_bb);
        }
        let mut left_bb = AABB::empty();
        // Go through the possible splits
        for i in 0..triangles.len() {
            left_bb.add_aabb(&triangles[i].aabb());
            let right_bb = &right_bbs[right_bbs.len() - 1 - i];
            let score = i as f32 * left_bb.area() + (triangles.len() - i) as f32 * right_bb.area();
            if score < min_score {
                min_score = score;
                min_axis = axis;
                min_i = i;
            }
        }
    }
    if min_i == 0 {
        None
    } else {
        triangles.sort(min_axis);
        Some(min_i)
    }
}
<|endoftext|>


<commit_before>use config::Config;
use error::Result;
use std::net::IpAddr;
use gandi::GandiRPC;
use gandi::GandiRpcEndpoint;
use gandi::ZoneVersion;
use std::str::FromStr;

pub struct DNSProviderFactory;

impl<'a> DNSProviderFactory {
    pub fn build(config: &'a Config) -> Box<DNSProvider + 'a>  {
        Box::new(GandiDNSProvider::new(&config.apikey))
    }
}

#[derive(Debug)]
pub struct Record<'a> {
    pub name: &'a str,
    pub type_: RecordType,
}

impl<'a> Record<'a> {
    pub fn new(record_name: &'a str, ip_addr: &IpAddr) -> Record<'a> {
        let record_type = RecordType::from_ipaddr(&ip_addr);

        Record {
            name: record_name,
            type_: record_type,
        }
    }
}

#[derive(Debug, Clone)]
pub enum RecordType {
    A,
    AAAA,
}

impl RecordType {
    pub fn to_string(&self) -> String {
        match self {
            &RecordType::A => "A".to_string(),
            &RecordType::AAAA => "AAAA".to_string(),
        }
    }

    pub fn from_ipaddr(ip_addr: &IpAddr) -> RecordType {
        match ip_addr {
            &IpAddr::V4(_) => RecordType::A,
            &IpAddr::V6(_) => RecordType::AAAA,
        }
    }
}

pub trait DNSProvider {
    fn init(&mut self, domain: &str) -> Result<()>;
    fn handle_ipv6_addr(&self) -> bool;
    fn is_record_already_declared(&self, record: &Record) -> Result<Option<IpAddr>>;
    fn update_record(&self, record: &Record, ip_addr: &IpAddr) -> Result<()>;
    fn create_record(&self, record: &Record, ip_addr: &IpAddr) -> Result<()>;
}

pub struct GandiDNSProvider<'a> {
    zone_id: u32,
    gandi_rpc: GandiRPC<'a>,
}

impl<'a> GandiDNSProvider<'a> {
    pub fn new(gandi_apikey: &'a str) -> GandiDNSProvider<'a> {

        let gandi_rpc = GandiRPC::new(GandiRpcEndpoint::PROD, gandi_apikey);

        GandiDNSProvider {
            zone_id: Default::default(),
            gandi_rpc: gandi_rpc,
        }
    }
}

impl<'a> DNSProvider for GandiDNSProvider<'a> {
    fn init(&mut self, domain: &str) -> Result<()> {

        let response = &self.gandi_rpc.domain_info(domain);

        // TODO: fix this ugly code
        // Handle errors
        let zone_id_pos = response.body.find("zone_id").unwrap();
        let (_, body_end) = response.body.split_at(zone_id_pos);
        let first_int_markup = body_end.find("<int>").unwrap();
        let (_, body_end) = body_end.split_at(first_int_markup + "<int>".len());
        let first_end_int_markup = body_end.find("</int>").unwrap();
        let (zone_id, _) = body_end.split_at(first_end_int_markup);

        self.zone_id = try!(zone_id.parse::<u32>());

        debug!("Zone id: {}", self.zone_id);
        Ok(())
    }

    fn handle_ipv6_addr(&self) -> bool {
        // IPv6 addresses are not handled yet
        true
    }

    fn is_record_already_declared(&self, record: &Record) -> Result<Option<IpAddr>> {
        let zone = &self.gandi_rpc.domain_zone_record_list(&record.name, &record.type_.to_string(), &self.zone_id, ZoneVersion::LATEST);

        match zone.clone() {
            None => Ok(None),
            Some(zone) => Ok(Some(try!(IpAddr::from_str(&zone.ip_addr))))
        }
    }

    fn update_record(&self, record: &Record, ip_addr: &IpAddr) -> Result<()> {

        // Create a new zone and get returned version

        let new_zone_version = &self.gandi_rpc.domain_zone_version_new(&self.zone_id);

        debug!("New zone version: {}", new_zone_version);

        let zone = &self.gandi_rpc.domain_zone_record_list(&record.name, &record.type_.to_string(), &self.zone_id, ZoneVersion::ANOTHER(*new_zone_version)).unwrap();

        debug!("New zone: {:?}", zone);

        // Update zone with the new record
        &self.gandi_rpc.domain_zone_record_update(&record.name,
                                                ip_addr,
                                                &self.zone_id,
                                                new_zone_version,
                                                &zone.record_id);

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'",
               new_zone_version,
               &self.zone_id);

        self.gandi_rpc.domain_zone_version_set(&self.zone_id, &new_zone_version);
        // TODO: check previous result
        Ok(())
    }

    fn create_record(&self, record: &Record, ip_addr: &IpAddr) -> Result<()> {
        // Create a new zone and get returned version

        let new_zone_version = &self.gandi_rpc.domain_zone_version_new(&self.zone_id);

        debug!("New zone version: {}", new_zone_version);

        // Create the new record for the new zone version
        &self.gandi_rpc.domain_zone_record_add(&record.name,
                                                ip_addr,
                                                &self.zone_id,
                                                new_zone_version);

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'",
               new_zone_version,
               &self.zone_id);

        self.gandi_rpc.domain_zone_version_set(&self.zone_id, &new_zone_version);
        // TODO: check previous result
        Ok(())
    }
}
<commit_msg>(chore) Remove useless comment<commit_after>use config::Config;
use error::Result;
use std::net::IpAddr;
use gandi::GandiRPC;
use gandi::GandiRpcEndpoint;
use gandi::ZoneVersion;
use std::str::FromStr;

pub struct DNSProviderFactory;

impl<'a> DNSProviderFactory {
    pub fn build(config: &'a Config) -> Box<DNSProvider + 'a>  {
        Box::new(GandiDNSProvider::new(&config.apikey))
    }
}

#[derive(Debug)]
pub struct Record<'a> {
    pub name: &'a str,
    pub type_: RecordType,
}

impl<'a> Record<'a> {
    pub fn new(record_name: &'a str, ip_addr: &IpAddr) -> Record<'a> {
        let record_type = RecordType::from_ipaddr(&ip_addr);

        Record {
            name: record_name,
            type_: record_type,
        }
    }
}

#[derive(Debug, Clone)]
pub enum RecordType {
    A,
    AAAA,
}

impl RecordType {
    pub fn to_string(&self) -> String {
        match self {
            &RecordType::A => "A".to_string(),
            &RecordType::AAAA => "AAAA".to_string(),
        }
    }

    pub fn from_ipaddr(ip_addr: &IpAddr) -> RecordType {
        match ip_addr {
            &IpAddr::V4(_) => RecordType::A,
            &IpAddr::V6(_) => RecordType::AAAA,
        }
    }
}

pub trait DNSProvider {
    fn init(&mut self, domain: &str) -> Result<()>;
    fn handle_ipv6_addr(&self) -> bool;
    fn is_record_already_declared(&self, record: &Record) -> Result<Option<IpAddr>>;
    fn update_record(&self, record: &Record, ip_addr: &IpAddr) -> Result<()>;
    fn create_record(&self, record: &Record, ip_addr: &IpAddr) -> Result<()>;
}

pub struct GandiDNSProvider<'a> {
    zone_id: u32,
    gandi_rpc: GandiRPC<'a>,
}

impl<'a> GandiDNSProvider<'a> {
    pub fn new(gandi_apikey: &'a str) -> GandiDNSProvider<'a> {

        let gandi_rpc = GandiRPC::new(GandiRpcEndpoint::PROD, gandi_apikey);

        GandiDNSProvider {
            zone_id: Default::default(),
            gandi_rpc: gandi_rpc,
        }
    }
}

impl<'a> DNSProvider for GandiDNSProvider<'a> {
    fn init(&mut self, domain: &str) -> Result<()> {

        let response = &self.gandi_rpc.domain_info(domain);

        // TODO: fix this ugly code
        // Handle errors
        let zone_id_pos = response.body.find("zone_id").unwrap();
        let (_, body_end) = response.body.split_at(zone_id_pos);
        let first_int_markup = body_end.find("<int>").unwrap();
        let (_, body_end) = body_end.split_at(first_int_markup + "<int>".len());
        let first_end_int_markup = body_end.find("</int>").unwrap();
        let (zone_id, _) = body_end.split_at(first_end_int_markup);

        self.zone_id = try!(zone_id.parse::<u32>());

        debug!("Zone id: {}", self.zone_id);
        Ok(())
    }

    fn handle_ipv6_addr(&self) -> bool {
        true
    }

    fn is_record_already_declared(&self, record: &Record) -> Result<Option<IpAddr>> {
        let zone = &self.gandi_rpc.domain_zone_record_list(&record.name, &record.type_.to_string(), &self.zone_id, ZoneVersion::LATEST);

        match zone.clone() {
            None => Ok(None),
            Some(zone) => Ok(Some(try!(IpAddr::from_str(&zone.ip_addr))))
        }
    }

    fn update_record(&self, record: &Record, ip_addr: &IpAddr) -> Result<()> {

        // Create a new zone and get returned version

        let new_zone_version = &self.gandi_rpc.domain_zone_version_new(&self.zone_id);

        debug!("New zone version: {}", new_zone_version);

        let zone = &self.gandi_rpc.domain_zone_record_list(&record.name, &record.type_.to_string(), &self.zone_id, ZoneVersion::ANOTHER(*new_zone_version)).unwrap();

        debug!("New zone: {:?}", zone);

        // Update zone with the new record
        &self.gandi_rpc.domain_zone_record_update(&record.name,
                                                ip_addr,
                                                &self.zone_id,
                                                new_zone_version,
                                                &zone.record_id);

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'",
               new_zone_version,
               &self.zone_id);

        self.gandi_rpc.domain_zone_version_set(&self.zone_id, &new_zone_version);
        // TODO: check previous result
        Ok(())
    }

    fn create_record(&self, record: &Record, ip_addr: &IpAddr) -> Result<()> {
        // Create a new zone and get returned version

        let new_zone_version = &self.gandi_rpc.domain_zone_version_new(&self.zone_id);

        debug!("New zone version: {}", new_zone_version);

        // Create the new record for the new zone version
        &self.gandi_rpc.domain_zone_record_add(&record.name,
                                                ip_addr,
                                                &self.zone_id,
                                                new_zone_version);

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'",
               new_zone_version,
               &self.zone_id);

        self.gandi_rpc.domain_zone_version_set(&self.zone_id, &new_zone_version);
        // TODO: check previous result
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::transmute;
use std::ops::Range;

use static_assertions::assert_eq_size;

// Minimal ELF support, sufficient for a very simple 64-bit static Linux
// executable.

// Sources:
// * /usr/include/elf.h
// * https://wiki.osdev.org/ELF_Tutorial
// * https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
// * https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
// * https://unix.stackexchange.com/questions/132036/why-does-readelf-show-system-v-as-my-os-instead-of-linux
// * http://www.sco.com/developers/gabi/latest/ch4.eheader.html

type Elf64_Half = u16;
type Elf64_Word = u32;
type Elf64_Xword = u64;
type Elf64_Addr = u64;
type Elf64_Off = u64;

const EI_MAG: Range<usize> = 0..4;
const EI_CLASS: usize = 4;
const EI_DATA: usize = 5;
const EI_VERSION: usize = 6;
const EI_OSABI: usize = 7;

const ELFCLASS64: u8 = 2;
const ELFDATA2LSB: u8 = 1;
const ELFOSABI_SYSV: u8 = 0;
const ET_EXEC: u16 = 2;
const EM_X86_64: u16 = 62;
const PT_LOAD: u32 = 1;

const PF_X: u32 = 1 << 0;
const PF_W: u32 = 1 << 1;
const PF_R: u32 = 1 << 2;

const EHDR_SIZE: usize = 64;
const PHDR_SIZE: usize = 56;
const SHDR_SIZE: usize = 64;

assert_eq_size!(ehdr_size_assert; Elf64_Ehdr, [u8; EHDR_SIZE]);
assert_eq_size!(phdr_size_assert; Elf64_Phdr, [u8; PHDR_SIZE]);
assert_eq_size!(shdr_size_assert; Elf64_Shdr, [u8; SHDR_SIZE]);

// ELF header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Ehdr {
    pub e_ident: [u8; 16],
    pub e_type: Elf64_Half,
    pub e_machine: Elf64_Half,
    pub e_version: Elf64_Word,
    pub e_entry: Elf64_Addr,
    pub e_phoff: Elf64_Off,
    pub e_shoff: Elf64_Off,
    pub e_flags: Elf64_Word,
    pub e_ehsize: Elf64_Half,
    pub e_phentsize: Elf64_Half,
    pub e_phnum: Elf64_Half,
    pub e_shentsize: Elf64_Half,
    pub e_shnum: Elf64_Half,
    pub e_shstrndx: Elf64_Half,
}

// Program header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Phdr {
    pub p_type: Elf64_Word,
    pub p_flags: Elf64_Word,
    pub p_offset: Elf64_Off,
    pub p_vaddr: Elf64_Addr,
    pub p_paddr: Elf64_Addr,
    pub p_filesz: Elf64_Xword,
    pub p_memsz: Elf64_Xword,
    pub p_align: Elf64_Xword,
}

// Symbol header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Elf64_Shdr {
    pub sh_name: Elf64_Word,
    pub sh_type: Elf64_Word,
    pub sh_flags: Elf64_Xword,
    pub sh_addr: Elf64_Addr,
    pub sh_offset: Elf64_Off,
    pub sh_size: Elf64_Xword,
    pub sh_link: Elf64_Word,
    pub sh_info: Elf64_Word,
    pub sh_addralign: Elf64_Xword,
    pub sh_entsize: Elf64_Xword,
}

pub fn elf64_write(f: &mut impl Write, text: &[u8], bss_size: u64) -> io::Result<()> {
    let size = text.len() as u64;
    let hdr_size = (EHDR_SIZE + 2 * PHDR_SIZE) as u64;
    let hdr_size_padded = (hdr_size + 0x1000 - 1) & !(0x1000 - 1);

    let mut e_ident = [0u8; 16];
    e_ident[EI_MAG].copy_from_slice(b"\x7fELF");
    e_ident[EI_CLASS] = ELFCLASS64;
    e_ident[EI_DATA] = ELFDATA2LSB;
    e_ident[EI_VERSION] = 1;
    e_ident[EI_OSABI] = ELFOSABI_SYSV;

    let ehdr = Elf64_Ehdr {
        e_ident,
        e_type: ET_EXEC,
        e_machine: EM_X86_64,
        e_version: 1,
        e_entry: 0x401000,
        // Put program header immediately after ELF header
        e_phoff: EHDR_SIZE as u64,
        // Don't include a section header table
        e_shoff: 0,
        e_flags: 0,
        e_ehsize: EHDR_SIZE as u16,
        e_phentsize: PHDR_SIZE as u16,
        e_phnum: 2,
        e_shentsize: SHDR_SIZE as u16,
        e_shnum: 0,
        e_shstrndx: 0,
    };

    let phdr_text = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_X,
        p_offset: hdr_size_padded,
        p_vaddr: 0x401000,
        p_paddr: 0x401000,
        p_filesz: size,
        p_memsz: size,
        p_align: 0x1000,
    };

    let bss_offset = (size + 0x1000 - 1) & !(0x1000 - 1);

    let phdr_bss = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_W,
        p_offset: hdr_size_padded + bss_offset,
        p_vaddr: 0x401000 + bss_offset,
        p_paddr: 0x401000 + bss_offset,
        p_filesz: 0,
        p_memsz: bss_size,
        p_align: 0x1000,
    };

    unsafe {
        f.write(&transmute::<_, [u8; EHDR_SIZE]>(ehdr))?;
        f.write(&transmute::<_, [u8; PHDR_SIZE]>(phdr_text))?;
        f.write(&transmute::<_, [u8; PHDR_SIZE]>(phdr_bss))?;
    }
    for _ in 0..(hdr_size_padded - hdr_size) {
        f.write(b"0")?;
    }
    f.write(text)?;
    Ok(())
}

fn elf64_read_strtab(f: &mut (impl Read + Seek), ehdr: &Elf64_Ehdr) -> io::Result<Vec<u8>> {
    // Read section header for the string table
    let mut shdr_buf = [0; SHDR_SIZE];
    f.seek(SeekFrom::Start(
        ehdr.e_shoff + ehdr.e_shstrndx as u64 * SHDR_SIZE as u64,
    ))?;
    f.read(&mut shdr_buf)?;
    let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

    // Read string table section
    let mut strtab = Vec::with_capacity(shdr.sh_size as usize);
    strtab.resize(shdr.sh_size as usize, 0);
    f.seek(SeekFrom::Start(shdr.sh_offset))?;
    f.read(&mut strtab)?;

    Ok(strtab)
}

pub fn elf64_get_section(
    f: &mut (impl Read + Seek),
    name: &[u8],
) -> io::Result<Option<Elf64_Shdr>> {
    let mut ehdr_buf = [0; EHDR_SIZE];
    f.seek(SeekFrom::Start(0))?;
    f.read(&mut ehdr_buf)?;
    let ehdr: Elf64_Ehdr = unsafe { transmute(ehdr_buf) };

    let strtab = elf64_read_strtab(f, &ehdr)?;

    f.seek(SeekFrom::Start(ehdr.e_shoff))?;
    for _ in 0..ehdr.e_shnum {
        let mut shdr_buf = [0; SHDR_SIZE];
        f.read(&mut shdr_buf)?;
        let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

        let mut cur_name = &strtab[shdr.sh_name as usize..];
        if let Some(idx) = cur_name.iter().position(|c| *c == b'\0') {
            cur_name = &cur_name[..idx];
        }
        if cur_name == name {
            return Ok(Some(shdr));
        }
    }

    Ok(None)
}
<commit_msg>Put ELF magic in a constant too<commit_after>#![allow(non_camel_case_types)]

use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::transmute;
use std::ops::Range;

use static_assertions::assert_eq_size;

// Minimal ELF support, sufficient for a very simple 64-bit static Linux
// executable.

// Sources:
// * /usr/include/elf.h
// * https://wiki.osdev.org/ELF_Tutorial
// * https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
// * https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
// * https://unix.stackexchange.com/questions/132036/why-does-readelf-show-system-v-as-my-os-instead-of-linux
// * http://www.sco.com/developers/gabi/latest/ch4.eheader.html

type Elf64_Half = u16;
type Elf64_Word = u32;
type Elf64_Xword = u64;
type Elf64_Addr = u64;
type Elf64_Off = u64;

const EI_MAG: Range<usize> = 0..4;
const EI_CLASS: usize = 4;
const EI_DATA: usize = 5;
const EI_VERSION: usize = 6;
const EI_OSABI: usize = 7;

const ELFMAG: &[u8] = b"\x7fELF";
const ELFCLASS64: u8 = 2;
const ELFDATA2LSB: u8 = 1;
const ELFOSABI_SYSV: u8 = 0;

const ET_EXEC: u16 = 2;
const EM_X86_64: u16 = 62;
const PT_LOAD: u32 = 1;

const PF_X: u32 = 1 << 0;
const PF_W: u32 = 1 << 1;
const PF_R: u32 = 1 << 2;

const EHDR_SIZE: usize = 64;
const PHDR_SIZE: usize = 56;
const SHDR_SIZE: usize = 64;

assert_eq_size!(ehdr_size_assert; Elf64_Ehdr, [u8; EHDR_SIZE]);
assert_eq_size!(phdr_size_assert; Elf64_Phdr, [u8; PHDR_SIZE]);
assert_eq_size!(shdr_size_assert; Elf64_Shdr, [u8; SHDR_SIZE]);

// ELF header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Ehdr {
    pub e_ident: [u8; 16],
    pub e_type: Elf64_Half,
    pub e_machine: Elf64_Half,
    pub e_version: Elf64_Word,
    pub e_entry: Elf64_Addr,
    pub e_phoff: Elf64_Off,
    pub e_shoff: Elf64_Off,
    pub e_flags: Elf64_Word,
    pub e_ehsize: Elf64_Half,
    pub e_phentsize: Elf64_Half,
    pub e_phnum: Elf64_Half,
    pub e_shentsize: Elf64_Half,
    pub e_shnum: Elf64_Half,
    pub e_shstrndx: Elf64_Half,
}

// Program header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Phdr {
    pub p_type: Elf64_Word,
    pub p_flags: Elf64_Word,
    pub p_offset: Elf64_Off,
    pub p_vaddr: Elf64_Addr,
    pub p_paddr: Elf64_Addr,
    pub p_filesz: Elf64_Xword,
    pub p_memsz: Elf64_Xword,
    pub p_align: Elf64_Xword,
}

// Symbol header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Elf64_Shdr {
    pub sh_name: Elf64_Word,
    pub sh_type: Elf64_Word,
    pub sh_flags: Elf64_Xword,
    pub sh_addr: Elf64_Addr,
    pub sh_offset: Elf64_Off,
    pub sh_size: Elf64_Xword,
    pub sh_link: Elf64_Word,
    pub sh_info: Elf64_Word,
    pub sh_addralign: Elf64_Xword,
    pub sh_entsize: Elf64_Xword,
}

pub fn elf64_write(f: &mut impl Write, text: &[u8], bss_size: u64) -> io::Result<()> {
    let size = text.len() as u64;
    let hdr_size = (EHDR_SIZE + 2 * PHDR_SIZE) as u64;
    let hdr_size_padded = (hdr_size + 0x1000 - 1) & !(0x1000 - 1);

    let mut e_ident = [0u8; 16];
    e_ident[EI_MAG].copy_from_slice(ELFMAG);
    e_ident[EI_CLASS] = ELFCLASS64;
    e_ident[EI_DATA] = ELFDATA2LSB;
    e_ident[EI_VERSION] = 1;
    e_ident[EI_OSABI] = ELFOSABI_SYSV;

    let ehdr = Elf64_Ehdr {
        e_ident,
        e_type: ET_EXEC,
        e_machine: EM_X86_64,
        e_version: 1,
        e_entry: 0x401000,
        // Put program header immediately after ELF header
        e_phoff: EHDR_SIZE as u64,
        // Don't include a section header table
        e_shoff: 0,
        e_flags: 0,
        e_ehsize: EHDR_SIZE as u16,
        e_phentsize: PHDR_SIZE as u16,
        e_phnum: 2,
        e_shentsize: SHDR_SIZE as u16,
        e_shnum: 0,
        e_shstrndx: 0,
    };

    let phdr_text = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_X,
        p_offset: hdr_size_padded,
        p_vaddr: 0x401000,
        p_paddr: 0x401000,
        p_filesz: size,
        p_memsz: size,
        p_align: 0x1000,
    };

    let bss_offset = (size + 0x1000 - 1) & !(0x1000 - 1);

    let phdr_bss = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_W,
        p_offset: hdr_size_padded + bss_offset,
        p_vaddr: 0x401000 + bss_offset,
        p_paddr: 0x401000 + bss_offset,
        p_filesz: 0,
        p_memsz: bss_size,
        p_align: 0x1000,
    };

    unsafe {
        f.write(&transmute::<_, [u8; EHDR_SIZE]>(ehdr))?;
        f.write(&transmute::<_, [u8; PHDR_SIZE]>(phdr_text))?;
        f.write(&transmute::<_, [u8; PHDR_SIZE]>(phdr_bss))?;
    }
    for _ in 0..(hdr_size_padded - hdr_size) {
        f.write(b"0")?;
    }
    f.write(text)?;
    Ok(())
}

fn elf64_read_strtab(f: &mut (impl Read + Seek), ehdr: &Elf64_Ehdr) -> io::Result<Vec<u8>> {
    // Read section header for the string table
    let mut shdr_buf = [0; SHDR_SIZE];
    f.seek(SeekFrom::Start(
        ehdr.e_shoff + ehdr.e_shstrndx as u64 * SHDR_SIZE as u64,
    ))?;
    f.read(&mut shdr_buf)?;
    let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

    // Read string table section
    let mut strtab = Vec::with_capacity(shdr.sh_size as usize);
    strtab.resize(shdr.sh_size as usize, 0);
    f.seek(SeekFrom::Start(shdr.sh_offset))?;
    f.read(&mut strtab)?;

    Ok(strtab)
}

pub fn elf64_get_section(
    f: &mut (impl Read + Seek),
    name: &[u8],
) -> io::Result<Option<Elf64_Shdr>> {
    let mut ehdr_buf = [0; EHDR_SIZE];
    f.seek(SeekFrom::Start(0))?;
    f.read(&mut ehdr_buf)?;
    let ehdr: Elf64_Ehdr = unsafe { transmute(ehdr_buf) };

    let strtab = elf64_read_strtab(f, &ehdr)?;

    f.seek(SeekFrom::Start(ehdr.e_shoff))?;
    for _ in 0..ehdr.e_shnum {
        let mut shdr_buf = [0; SHDR_SIZE];
        f.read(&mut shdr_buf)?;
        let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

        let mut cur_name = &strtab[shdr.sh_name as usize..];
        if let Some(idx) = cur_name.iter().position(|c| *c == b'\0') {
            cur_name = &cur_name[..idx];
        }
        if cur_name == name {
            return Ok(Some(shdr));
        }
    }

    Ok(None)
}
<|endoftext|>


<commit_before>use vmx;
use cli;

#[repr(packed)]
struct GDTEntry {
    limit_low: u16,
    base_low: u16,
    base_middle: u8,
    flags: u8,
    more_flags: u8,
    base_high: u8,
}

const GDT: [GDTEntry; 3] = [
    GDTEntry{
        limit_low: 0,
        base_low: 0,
        base_middle: 0,
        flags: 0,
        more_flags: 0,
        base_high: 0,
    },
    GDTEntry{
        limit_low: 0xffff,
        base_low: 0,
        base_middle: 0,
        flags: 0b10101001,
        more_flags: 0b11110111,
        base_high: 0,
    },
    GDTEntry{
        limit_low: 0xffff,
        base_low: 0,
        base_middle: 0,
        flags: 0b00101001,
        more_flags: 0b11110111,
        base_high: 0,
    },
];

pub fn new_host_descriptor() -> vmx::CPUTableDescriptor {
    vmx::CPUTableDescriptor{ limit: 0xffff, base: GDT.as_ptr() as u64 }
}

pub fn test_load() {
    cli::ClearLocalInterruptsGuard::new();
    let gdt_desc = new_host_descriptor();
    let mut orig_gdt_desc: vmx::CPUTableDescriptor = Default::default();
    vmx::sgdt(&mut orig_gdt_desc);
    vmx::lgdt(&gdt_desc);
    vmx::lgdt(&orig_gdt_desc);
}
<commit_msg>Fix GDT size<commit_after>use vmx;
use cli;

#[repr(packed)]
struct GDTEntry {
    limit_low: u16,
    base_low: u16,
    base_middle: u8,
    access: u8,
    granularity: u8,
    base_high: u8,
    base_highest: u32,
    reserved0: u32,
}

const GDT: [GDTEntry; 3] = [
    GDTEntry{
        limit_low: 0,
        base_low: 0,
        base_middle: 0,
        access: 0,
        granularity: 0,
        base_high: 0,
        base_highest: 0,
        reserved0: 0,
    },
    GDTEntry{
        limit_low: 0xffff,
        base_low: 0,
        base_middle: 0,
        access: 0b10101001,
        granularity: 0b11110111,
        base_high: 0,
        base_highest: 0,
        reserved0: 0,
    },
    GDTEntry{
        limit_low: 0xffff,
        base_low: 0,
        base_middle: 0,
        access: 0b00101001,
        granularity: 0b11110111,
        base_high: 0,
        base_highest: 0,
        reserved0: 0,
    },
];

pub fn new_host_descriptor() -> vmx::CPUTableDescriptor {
    vmx::CPUTableDescriptor{ limit: 0xffff, base: GDT.as_ptr() as u64 }
}

pub fn test_load() {
    cli::ClearLocalInterruptsGuard::new();
    let gdt_desc = new_host_descriptor();
    let mut orig_gdt_desc: vmx::CPUTableDescriptor = Default::default();
    vmx::sgdt(&mut orig_gdt_desc);
    vmx::lgdt(&gdt_desc);
    vmx::lgdt(&orig_gdt_desc);
}
<|endoftext|>


<commit_before>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status") => status(&request, response),
            path.starts_with("/test") => test(&request, response),
        ];
    }
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(request: &Request, mut response: Response) {
    *response.status_mut() = StatusCode::ImATeapot;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<commit_msg>Implement status<commit_after>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status/") => status(path, response),
            path.starts_with("/test") => test(&request, response),
        ];
    }
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(path: &str, mut response: Response) {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    println!("Status {:?}", param);
    let code = match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    };
    *response.status_mut() = code;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::str;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::process::Command;
use util;

pub struct Git<'a> {
    command: String,
    git_dir: &'a str,
}

impl<'a> Git<'a> {
    pub fn command<S: AsRef<OsStr>>(&self, args: &[S]) -> util::Result<String> {
        let out = Command::new(&self.command)
                    .arg("--git-dir")
                    .arg(self.git_dir)
                    .args(args)
                    .output()
                    .map_err(|e| format!("Error on executing git command: {}", e))?;
        if !out.status.success() {
            return Err(format!("Git command exited with non-zero status: {}", str::from_utf8(&out.stderr).expect("Failed to convert git command output from UTF8")));
        }
        let s = str::from_utf8(&out.stdout).map_err(|e| format!("Invalid UTF-8 sequence in output of git command: {}", e))?;
        Ok(s.trim().to_string())
    }

    pub fn hash<S: AsRef<str>>(&self, commit: &S) -> util::Result<String> {
        self.command(&["rev-parse", commit.as_ref()])
    }

    pub fn remote_url<S: AsRef<str>>(&self, name: &S) -> util::Result<String> {
        let mut url = self.command(&["remote", "get-url", name.as_ref()])?;
        if url.starts_with("git@") {
            // Note: Convert SSH protocol URL
            //  git@service.com:user/repo.git -> ssh://git@service.com:22/user/repo.git
            if let Some(i) = url.find(':') {
                util::insert(&mut url, i + 1, "22/");
            }
            util::insert(&mut url, 0, "ssh://");
        }
        Ok(url)
    }

    pub fn tracking_remote(&self) -> util::Result<(String, String)> {
        let out = self.command(&["rev-parse", "--abbrev-ref", "--symbolic", "@{u}"])?;
        let mut split = out.splitn(2, "/");
        let url = match split.next() {
            None => return Err(format!("Invalid tracking remote name: {}", out)),
            Some(ref u) => self.remote_url(&u)?,
        };
        let branch = match split.next() {
            None => return Err(format!("Invalid tracking remote name: {}", out)),
            Some(ref u) => u.to_string(),
        };
        Ok((url, branch))
    }

    pub fn root_dir(&self) -> util::Result<PathBuf> {
        // XXX:
        // `git rev-parse` can't be used with --git-dir arguments.
        // `git --git-dir ../.git rev-parse --show-toplevel` always returns
        // current working directory.
        // So here root directory is calculated from git-dir.
        let p = Path::new(self.git_dir)
                    .parent()
                    .ok_or(format!("Cannot locate root directory from git-dir '{}'", self.git_dir))?;
        Ok(p.to_owned())
    }
}

pub fn get_git_command() -> String {
    env::var("GIT_BRWS_GIT_COMMAND").unwrap_or("git".to_string())
}

pub fn new(dir: &PathBuf) -> util::Result<Git> {
    let command = get_git_command();
    let path = dir.to_str().ok_or(format!("Failed to retrieve directory path as UTF8 string: {:?}", dir))?;
    Ok(Git { command: command, git_dir: path })
}

fn set_current_dir(p: &PathBuf) -> util::Result<()> {
    env::set_current_dir(p).map_err(|e| format!("Error on setting current direcotry to {:?}: {}", p, e))
}

fn git_revparse_git_dir(current: &PathBuf) -> util::Result<PathBuf> {
    let out = Command::new(get_git_command())
                .arg("rev-parse")
                .arg("--git-dir")
                .output()
                .map_err(|e| format!("{}", e))?;
    if !out.status.success() {
        return Err(format!("Git command exited with non-zero status: {}", str::from_utf8(&out.stderr).expect("Failed to convert git command output from UTF8")));
    }

    let s = str::from_utf8(&out.stdout).map_err(|e| format!("Invalid UTF-8 sequence in output of git command: {}", e))?.trim();

    let p = Path::new(s);
    if p.is_relative() {
        Ok(current.join(&p))
    } else {
        Ok(p.to_owned())
    }
}

pub fn git_dir(dir: Option<String>) -> util::Result<PathBuf> {
    let current_dir = env::current_dir().map_err(|e| format!("{}", e))?;
    match dir {
        Some(d) => {
            let d = fs::canonicalize(&d).map_err(|e| format!("Cannot locate canonical path for '{}': {}", d, e))?;
            set_current_dir(&d)?;
            let p = git_revparse_git_dir(&d).map_err(|e| format!("{}", e));
            set_current_dir(&current_dir)?;
            p
        },
        None => git_revparse_git_dir(&current_dir),
    }
}
<commit_msg>do not use `git remote get-url` because it's unavailable on Git 1.9.1 (Ubuntu 14.04)<commit_after>use std::env;
use std::fs;
use std::str;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::process::Command;
use util;

pub struct Git<'a> {
    command: String,
    git_dir: &'a str,
}

impl<'a> Git<'a> {
    pub fn command<S: AsRef<OsStr>>(&self, args: &[S]) -> util::Result<String> {
        let out = Command::new(&self.command)
                    .arg("--git-dir")
                    .arg(self.git_dir)
                    .args(args)
                    .output()
                    .map_err(|e| format!("Error on executing git command: {}", e))?;
        if !out.status.success() {
            return Err(format!("Git command exited with non-zero status: {}", str::from_utf8(&out.stderr).expect("Failed to convert git command output from UTF8")));
        }
        let s = str::from_utf8(&out.stdout).map_err(|e| format!("Invalid UTF-8 sequence in output of git command: {}", e))?;
        Ok(s.trim().to_string())
    }

    pub fn hash<S: AsRef<str>>(&self, commit: &S) -> util::Result<String> {
        self.command(&["rev-parse", commit.as_ref()])
    }

    pub fn remote_url<S: AsRef<str>>(&self, name: &S) -> util::Result<String> {
        // XXX:
        // `git remote get-url {name}` is not available because it's added recently (at 2.6.1).
        // Note that git installed in Ubuntu 14.04 is 1.9.1.
        let mut url = self.command(&["config", "--get", &format!("remote.{}.url", name.as_ref())])?;
        if url.starts_with("git@") {
            // Note: Convert SSH protocol URL
            //  git@service.com:user/repo.git -> ssh://git@service.com:22/user/repo.git
            if let Some(i) = url.find(':') {
                util::insert(&mut url, i + 1, "22/");
            }
            util::insert(&mut url, 0, "ssh://");
        }
        Ok(url)
    }

    pub fn tracking_remote(&self) -> util::Result<(String, String)> {
        let out = self.command(&["rev-parse", "--abbrev-ref", "--symbolic", "@{u}"])?;
        let mut split = out.splitn(2, "/");
        let url = match split.next() {
            None => return Err(format!("Invalid tracking remote name: {}", out)),
            Some(ref u) => self.remote_url(&u)?,
        };
        let branch = match split.next() {
            None => return Err(format!("Invalid tracking remote name: {}", out)),
            Some(ref u) => u.to_string(),
        };
        Ok((url, branch))
    }

    pub fn root_dir(&self) -> util::Result<PathBuf> {
        // XXX:
        // `git rev-parse` can't be used with --git-dir arguments.
        // `git --git-dir ../.git rev-parse --show-toplevel` always returns
        // current working directory.
        // So here root directory is calculated from git-dir.
        let p = Path::new(self.git_dir)
                    .parent()
                    .ok_or(format!("Cannot locate root directory from git-dir '{}'", self.git_dir))?;
        Ok(p.to_owned())
    }
}

pub fn get_git_command() -> String {
    env::var("GIT_BRWS_GIT_COMMAND").unwrap_or("git".to_string())
}

pub fn new(dir: &PathBuf) -> util::Result<Git> {
    let command = get_git_command();
    let path = dir.to_str().ok_or(format!("Failed to retrieve directory path as UTF8 string: {:?}", dir))?;
    Ok(Git { command: command, git_dir: path })
}

fn set_current_dir(p: &PathBuf) -> util::Result<()> {
    env::set_current_dir(p).map_err(|e| format!("Error on setting current direcotry to {:?}: {}", p, e))
}

fn git_revparse_git_dir(current: &PathBuf) -> util::Result<PathBuf> {
    let out = Command::new(get_git_command())
                .arg("rev-parse")
                .arg("--git-dir")
                .output()
                .map_err(|e| format!("{}", e))?;
    if !out.status.success() {
        return Err(format!("Git command exited with non-zero status: {}", str::from_utf8(&out.stderr).expect("Failed to convert git command output from UTF8")));
    }

    let s = str::from_utf8(&out.stdout).map_err(|e| format!("Invalid UTF-8 sequence in output of git command: {}", e))?.trim();

    let p = Path::new(s);
    if p.is_relative() {
        Ok(current.join(&p))
    } else {
        Ok(p.to_owned())
    }
}

pub fn git_dir(dir: Option<String>) -> util::Result<PathBuf> {
    let current_dir = env::current_dir().map_err(|e| format!("{}", e))?;
    match dir {
        Some(d) => {
            let d = fs::canonicalize(&d).map_err(|e| format!("Cannot locate canonical path for '{}': {}", d, e))?;
            set_current_dir(&d)?;
            let p = git_revparse_git_dir(&d).map_err(|e| format!("{}", e));
            set_current_dir(&current_dir)?;
            p
        },
        None => git_revparse_git_dir(&current_dir),
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use image::{Pixel, Rgb};

#[derive(Debug, PartialEq, PartialOrd, Default)]
pub struct HSL {
    pub h: f64, // 0-360 Degree
    pub s: f64, // 0-1 (Percent)
    pub l: f64, // 0-1 (Percent)
}

impl HSL {
    /// Convert pixel value to HSL
    ///
    /// Algorithm from [go-color] by Brandon Thomson <bt@brandonthomson.com>. (Iternally converts
    /// the pixel to RGB before converting it to HSL.)
    ///
    /// [go-color]: https://github.com/bthomson/go-color
    pub fn from_pixel<P>(pixel: &P) -> HSL
        where P: Pixel<Subpixel = u8>
    {
        HSL::from_rgb(pixel.to_rgb().channels())
    }

    /// Convert RGB pixel (as array of three bytes) to HSL.
    fn from_rgb(rgb: &[u8]) -> HSL {
        let mut h: f64;
        let s: f64;
        let l: f64;

        let (r, g, b) = (rgb[0], rgb[1], rgb[2]);

        let max = cmp::max(cmp::max(r, g), b);
        let min = cmp::min(cmp::min(r, g), b);

        // Normalized RGB: Divide everything by 255 to get percentages of colors.
        let (r, g, b) = (r as f64 / 255_f64, g as f64 / 255_f64, b as f64 / 255_f64);
        let (min, max) = (min as f64 / 255_f64, max as f64 / 255_f64);

        // Luminosity is the average of the max and min rgb color intensities.
        l = (max + min) / 2_f64;

        // Saturation
        let delta: f64 = max - min;
        if delta == 0_f64 {
    		// it's gray
            return HSL { h: 0_f64, s: 0_f64, l: l};
        }

        // it's not gray
        if l < 0.5_f64 {
            s = delta / (max + min);
        } else {
            s = delta / (2_f64 - max - min);
        }

        // Hue
        let r2 = (((max - r) / 6_f64) + (delta / 2_f64)) / delta;
        let g2 = (((max - g) / 6_f64) + (delta / 2_f64)) / delta;
        let b2 = (((max - b) / 6_f64) + (delta / 2_f64)) / delta;

        h = match max {
            x if x == r => b2 - g2,
            x if x == g => (1_f64 / 3_f64) + r2 - b2,
            _ => (2_f64 / 3_f64) + g2 - r2,
        };

        // Fix wraparounds
        if h < 0 as f64 {
            h += 1_f64;
        } else if h > 1 as f64 {
            h -= 1_f64;
        }

        HSL { h: h * 360_f64, s: s, l: l }
    }

    pub fn to_rgb(&self) -> Rgb<u8> {
        if self.s == 0.0 {
            // Achromatic, i.e., grey.
            let l = percent_to_byte(self.l);
            return Rgb::from_channels(l, l, l, 255);
        }

        let h = self.h / 360.0; // treat this as 0..1 instead of degrees
        let s = self.s;
        let l = self.l;

        let q = if l < 0.5 {
            l * (1.0 + s)
        } else {
            l + s - (l * s)
        };
        let p = 2.0 * l - q;

        Rgb::from_channels(percent_to_byte(hue_to_rgb(p, q, h + 1.0 / 3.0)),
                           percent_to_byte(hue_to_rgb(p, q, h)),
                           percent_to_byte(hue_to_rgb(p, q, h - 1.0 / 3.0)),
                           255)
    }
}

fn percent_to_byte(percent: f64) -> u8 {
    (percent * 255.0).round() as u8
}

fn hue_to_rgb(p: f64, q: f64, t: f64) -> f64 {
    let t = if t < 0.0 {
        t + 1.0
    } else if t > 1.0 {
        t - 1.0
    } else {
        t
    };

    let res = if t < 1.0 / 6.0 {
        p + (q - p) * 6.0 * t
    } else if t < 1.0 / 2.0 {
        q
    } else if t < 2.0 / 3.0 {
        p + (q - p) * (2.0 / 3.0 - t) * 6.0
    } else {
        p
    };

    res
}

#[cfg(test)]
mod test {
    macro_rules! test_rgb_to_hsl {
        (($r:expr, $g:expr, $b:expr) <=> ($h:expr, $s:expr, $l:expr)) => {
            {
                // Round gracefully to half a percent
                const EPSILON: f64 = 0.05;
                // Round gracefully to half a degree
                const EPSILON_DEGREE: f64 = 0.5;

                let rgb = Rgb::from_channels($r as u8, $g as u8, $b as u8, 0_u8);
                let hsl = HSL::from_pixel(&rgb);

                assert!(
                    $h - hsl.h <= EPSILON_DEGREE,
                    "Converting {:?} to HSL: H differs too much. Expected {}, got {}.",
                        rgb, $h, hsl.h
                );
                assert!(
                    $s - hsl.s <= EPSILON,
                    "Converting {:?} to HSL: S differs too much. Expected {}, got {}.",
                        rgb, $s, hsl.s
                );
                assert!(
                    $l - hsl.l <= EPSILON,
                    "Converting {:?} to HSL: L differs too much. Expected {}, got {}.",
                        rgb, $l, hsl.l
                );
            }
        };
    }

    use image::{Rgb, Pixel};
    use super::HSL;

    #[test]
    fn rgb_to_hsl() {
        // black
        test_rgb_to_hsl!( (0, 0, 0) <=> (0_f64, 0_f64, 0_f64) );

        // white
        test_rgb_to_hsl!( (255, 255, 255) <=> (0_f64, 0_f64, 1_f64) );

        // http://rgb.to/rgb/18,35,67
        test_rgb_to_hsl!( (18, 35, 67) <=> (219_f64, 0.58_f64, 0.17_f64) );

        // http://rgb.to/hex/93c6cd
        test_rgb_to_hsl!( (147, 198, 205) <=> (187_f64, 0.37_f64, 0.69_f64) );

        // http://rgb.to/hex/bada55
        test_rgb_to_hsl!( (186, 218, 85) <=> (74_f64, 0.64_f64, 0.59_f64) );

        // http://rgb.to/hex/ff0
        test_rgb_to_hsl!( (255, 255, 0) <=> (60_f64, 1_f64, 0.5_f64) );

        // http://rgb.to/rgb/198,250,172
        test_rgb_to_hsl!( (198, 250, 172) <=> (100_f64, 0.89_f64, 0.83_f64) );

        // http://rgb.to/hex/faadc7
        test_rgb_to_hsl!( (250, 173, 199) <=> (340_f64, 0.89_f64, 0.83_f64) );
    }
}
<commit_msg>Refactor HSL Test Macro, Add HSL to RGB Tests<commit_after>use std::cmp;
use image::{Pixel, Rgb};

#[derive(Debug, PartialEq, PartialOrd, Default)]
pub struct HSL {
    pub h: f64, // 0-360 Degree
    pub s: f64, // 0-1 (Percent)
    pub l: f64, // 0-1 (Percent)
}

impl HSL {
    /// Convert pixel value to HSL
    ///
    /// Algorithm from [go-color] by Brandon Thomson <bt@brandonthomson.com>. (Iternally converts
    /// the pixel to RGB before converting it to HSL.)
    ///
    /// [go-color]: https://github.com/bthomson/go-color
    pub fn from_pixel<P>(pixel: &P) -> HSL
        where P: Pixel<Subpixel = u8>
    {
        HSL::from_rgb(pixel.to_rgb().channels())
    }

    /// Convert RGB pixel (as array of three bytes) to HSL.
    fn from_rgb(rgb: &[u8]) -> HSL {
        let mut h: f64;
        let s: f64;
        let l: f64;

        let (r, g, b) = (rgb[0], rgb[1], rgb[2]);

        let max = cmp::max(cmp::max(r, g), b);
        let min = cmp::min(cmp::min(r, g), b);

        // Normalized RGB: Divide everything by 255 to get percentages of colors.
        let (r, g, b) = (r as f64 / 255_f64, g as f64 / 255_f64, b as f64 / 255_f64);
        let (min, max) = (min as f64 / 255_f64, max as f64 / 255_f64);

        // Luminosity is the average of the max and min rgb color intensities.
        l = (max + min) / 2_f64;

        // Saturation
        let delta: f64 = max - min;
        if delta == 0_f64 {
    		// it's gray
            return HSL { h: 0_f64, s: 0_f64, l: l};
        }

        // it's not gray
        if l < 0.5_f64 {
            s = delta / (max + min);
        } else {
            s = delta / (2_f64 - max - min);
        }

        // Hue
        let r2 = (((max - r) / 6_f64) + (delta / 2_f64)) / delta;
        let g2 = (((max - g) / 6_f64) + (delta / 2_f64)) / delta;
        let b2 = (((max - b) / 6_f64) + (delta / 2_f64)) / delta;

        h = match max {
            x if x == r => b2 - g2,
            x if x == g => (1_f64 / 3_f64) + r2 - b2,
            _ => (2_f64 / 3_f64) + g2 - r2,
        };

        // Fix wraparounds
        if h < 0 as f64 {
            h += 1_f64;
        } else if h > 1 as f64 {
            h -= 1_f64;
        }

        HSL { h: h * 360_f64, s: s, l: l }
    }

    pub fn to_rgb(&self) -> Rgb<u8> {
        if self.s == 0.0 {
            // Achromatic, i.e., grey.
            let l = percent_to_byte(self.l);
            return Rgb::from_channels(l, l, l, 255);
        }

        let h = self.h / 360.0; // treat this as 0..1 instead of degrees
        let s = self.s;
        let l = self.l;

        let q = if l < 0.5 {
            l * (1.0 + s)
        } else {
            l + s - (l * s)
        };
        let p = 2.0 * l - q;

        Rgb::from_channels(percent_to_byte(hue_to_rgb(p, q, h + 1.0 / 3.0)),
                           percent_to_byte(hue_to_rgb(p, q, h)),
                           percent_to_byte(hue_to_rgb(p, q, h - 1.0 / 3.0)),
                           255)
    }
}

fn percent_to_byte(percent: f64) -> u8 {
    (percent * 255.0).round() as u8
}

fn hue_to_rgb(p: f64, q: f64, t: f64) -> f64 {
    let t = if t < 0.0 {
        t + 1.0
    } else if t > 1.0 {
        t - 1.0
    } else {
        t
    };

    let res = if t < 1.0 / 6.0 {
        p + (q - p) * 6.0 * t
    } else if t < 1.0 / 2.0 {
        q
    } else if t < 2.0 / 3.0 {
        p + (q - p) * (2.0 / 3.0 - t) * 6.0
    } else {
        p
    };

    res
}

#[cfg(test)]
mod test {
    macro_rules! test_rgb_to_hsl {
        ($name:ident, ($r:expr, $g:expr, $b:expr) <=> ($h:expr, $s:expr, $l:expr)) => {
            #[test]
            fn $name() {
                // Round gracefully to half a percent
                const EPSILON: f64 = 0.05;
                // Round gracefully to half a degree
                const EPSILON_DEGREE: f64 = 0.5;
                // Round gracefully for RGB bytes
                const EPSILON_RGB: i32 = 2;

                let rgb = Rgb::from_channels($r as u8, $g as u8, $b as u8, 0_u8);
                let hsl = HSL::from_pixel(&rgb);

                assert!(
                    ($h - hsl.h).abs() <= EPSILON_DEGREE,
                    "Converting {:?} to HSL: H differs too much. Expected {:?}, got {}. ({:?})",
                        rgb, $h, hsl.h, hsl
                );
                assert!(
                    ($s - hsl.s).abs() <= EPSILON,
                    "Converting {:?} to HSL: S differs too much. Expected {}, got {}. ({:?})",
                        rgb, $s, hsl.s, hsl
                );
                assert!(
                    ($l - hsl.l).abs() <= EPSILON,
                    "Converting {:?} to HSL: L differs too much. Expected {}, got {}. ({:?})",
                        rgb, $l, hsl.l, hsl
                );

                // ...and back!
                let hsl = HSL { h: $h, s: $s, l: $l };
                let rgb = hsl.to_rgb().channels4();
                let (r, g, b, _) = rgb;
                let expectation = ($r, $g, $b, 255);

                assert!(
                    ($r as i32 - r as i32).abs() <= EPSILON_RGB,
                    "Converting {:?} to RGB: R differs too much. Expected {:?}, got {:?}.",
                        hsl, expectation, rgb
                );
                assert!(
                    ($g as i32 - g as i32).abs() <= EPSILON_RGB,
                    "Converting {:?} to RGB: G differs too much. Expected {:?}, got {:?}.",
                        hsl, expectation, rgb
                );
                assert!(
                    ($b as i32 - b as i32).abs() <= EPSILON_RGB,
                    "Converting {:?} to RGB: B differs too much. Expected {:?}, got {:?}.",
                        hsl, expectation, rgb
                );
            }
        };
    }

    use image::{Rgb, Pixel};
    use super::HSL;

    // black
    test_rgb_to_hsl!(black, (0, 0, 0) <=> (0_f64, 0_f64, 0_f64) );

    // white
    test_rgb_to_hsl!(white, (255, 255, 255) <=> (0_f64, 0_f64, 1_f64) );

    // http://rgb.to/rgb/18,35,67
    test_rgb_to_hsl!(blue, (18, 35, 67) <=> (219_f64, 0.58_f64, 0.17_f64) );

    // http://rgb.to/hex/93c6cd
    test_rgb_to_hsl!(lightblue, (147, 198, 205) <=> (187_f64, 0.37_f64, 0.69_f64) );

    // http://rgb.to/hex/bada55
    test_rgb_to_hsl!(bada55, (186, 218, 85) <=> (74_f64, 0.64_f64, 0.59_f64) );

    // http://rgb.to/hex/ff0
    test_rgb_to_hsl!(yellow, (255, 255, 0) <=> (60_f64, 1_f64, 0.5_f64) );

    // http://rgb.to/rgb/198,250,172
    test_rgb_to_hsl!(lightgreen, (198, 250, 172) <=> (100_f64, 0.89_f64, 0.83_f64) );

    // http://rgb.to/hex/faadc7
    test_rgb_to_hsl!(lightpink, (250, 173, 199) <=> (340_f64, 0.89_f64, 0.83_f64) );
}
<|endoftext|>