<commit_before>use linalg::matrix::Matrix;
use linalg::vector::Vector;
use learning::UnSupModel;

struct KMeansClassifier {
    iters: usize,
    k: usize,
    centroids: Option<Matrix<f64>>,
}

impl UnSupModel<Matrix<f64>, Vector<usize>> for KMeansClassifier {
    fn predict(&self, data: Matrix<f64>) -> Vector<usize> {
        Vector::new(vec![0])
    }

    fn train(&mut self, data: Matrix<f64>) {
        self.init_centroids(data.cols);

        for i in 0..self.iters {
            let idx = self.find_closest_centroids(&data);
            self.compute_means(&data, idx);
        }
    }
}

impl KMeansClassifier {
    pub fn new(k: usize) -> KMeansClassifier {
        KMeansClassifier {
            iters: 100,
            k: k,
            centroids: None,
        }
    }

    fn init_centroids(&mut self, dim: usize) {
        // These should not all be equal!
        self.centroids = Some(Matrix::zeros(self.k, dim));
    }

    fn find_closest_centroids(&self, data: &Matrix<f64>) -> Vector<usize> {
        let mut idx = Vector::zeros(data.rows);

        match self.centroids {
            Some(ref c) => {
                for i in 0..data.rows {
                    let centroid_dist = c - data.select_rows(&vec![i; c.rows]);
                    let dist = &centroid_dist.elemul(&centroid_dist).sum_cols();
                    // Now take argmin and this is the centroid.

                }
            }
            None => panic!("Centroids not defined."),
        }

        idx
    }

    fn compute_means(&mut self, data: &Matrix<f64>, classes: Vector<usize>) {
        for i in 0..self.k {
            let mut vec_k = Vec::new();

            for j in classes.data.iter() {
                if *j == i {
                    vec_k.push(j);
                }
            }

            // index out these rows from data
            // make a new matrix
            // compute average of it's rows
        }
    }
}
<commit_msg>Completed basic k-means. Need doc and testing.<commit_after>use linalg::matrix::Matrix;
use linalg::vector::Vector;
use learning::UnSupModel;

pub struct KMeansClassifier {
    iters: usize,
    k: usize,
    centroids: Option<Matrix<f64>>,
}

impl UnSupModel<Matrix<f64>, Vector<usize>> for KMeansClassifier {
    fn predict(&self, data: Matrix<f64>) -> Vector<usize> {
        match self.centroids {
            Some(ref _c) => return self.find_closest_centroids(&data),
            None => panic!("Model has not been trained."),
        }

    }

    fn train(&mut self, data: Matrix<f64>) {
        self.init_centroids(data.cols);

        for _i in 0..self.iters {
            let idx = self.find_closest_centroids(&data);
            self.update_centroids(&data, idx);
        }
    }
}

impl KMeansClassifier {
    pub fn new(k: usize) -> KMeansClassifier {
        KMeansClassifier {
            iters: 100,
            k: k,
            centroids: None,
        }
    }

    fn init_centroids(&mut self, dim: usize) {
        // These should not all be equal!
        self.centroids = Some(Matrix::zeros(self.k, dim));
    }

    fn find_closest_centroids(&self, data: &Matrix<f64>) -> Vector<usize> {
        let mut idx = Vector::zeros(data.rows);

        match self.centroids {
            Some(ref c) => {
                for i in 0..data.rows {
                    // This works like repmat pulling out row i repeatedly.
                    let centroid_diff = c - data.select_rows(&vec![i; c.rows]);
                    let dist = &centroid_diff.elemul(&centroid_diff).sum_cols();

                    // Now take argmin and this is the centroid.
                    idx.data[i] = dist.argmin();

                }
            }
            None => panic!("Centroids not defined."),
        }

        idx
    }

    fn update_centroids(&mut self, data: &Matrix<f64>, classes: Vector<usize>) {
        let mut new_centroids = Vec::with_capacity(self.k * classes.size);
        for i in 0..self.k {
            let mut vec_i = Vec::with_capacity(classes.size);

            for j in classes.data.iter() {
                if *j == i {
                    vec_i.push(*j);
                }
            }

            let mat_i = data.select_rows(&vec_i);

            new_centroids.extend(mat_i.mean(0).data);
        }

        self.centroids = Some(Matrix::new(self.k, classes.size, new_centroids));
    }
}
<|endoftext|>


<commit_before>use crate::ast::{
    ArrowFunctionBody, Block, BlockStatement, Expression, Ident, ImportStatement, Module,
    ModuleStatement, Operator,
};

pub fn render_module(module: Module) -> String {
    let mut accum = String::new();
    module.render(&mut accum);
    accum
}

#[cfg(windows)]
static NEWLINE: &str = "\r\n";

#[cfg(not(windows))]
static NEWLINE: &str = "\n";

pub(crate) trait Render {
    // REVIEW I doubt pushing to a String like this is the most efficient solution?
    fn render(&self, accum: &mut String);
}

impl Render for Module {
    fn render(&self, accum: &mut String) {
        self.imports.iter().for_each(|import| {
            import.render(accum);
            accum.push_str(NEWLINE);
        });
        self.statements.iter().for_each(|stmt| {
            stmt.render(accum);
            accum.push_str(NEWLINE);
        });

        accum.push_str("export {");
        accum.push_str(
            &self
                .exports
                .iter()
                .map(|ident| ident.0.as_str())
                .collect::<Vec<_>>()
                .join(","),
        );
        accum.push_str("};");
        accum.push_str(NEWLINE);
    }
}

impl Render for ImportStatement {
    fn render(&self, accum: &mut String) {
        accum.push_str("import {");
        let imports = self
            .idents
            .iter()
            .map(|(aliased, ident)| format!("{} as {}", aliased.0, ident.0))
            .collect::<Vec<_>>();
        accum.push_str(&imports.join(","));
        accum.push_str(&format!("}} from \"{}\";", self.path));
    }
}

impl Render for ModuleStatement {
    fn render(&self, accum: &mut String) {
        match self {
            Self::LetDeclaration { ident } => {
                accum.push_str(&format!("let {ident};", ident = ident.0));
            }
            Self::ConstAssignment { ident, value } => {
                accum.push_str(&format!("const {ident} = ", ident = ident.0));
                value.render(accum);
                accum.push(';');
            }
            Self::Assignment { ident, value } => {
                accum.push_str(&format!("{ident} = ", ident = ident.0));
                value.render(accum);
                accum.push(';');
            }
            Self::Function {
                ident,
                parameters,
                body,
            } => {
                accum.push_str(&format!(
                    "function {ident}({parameters})",
                    ident = ident.0,
                    parameters = parameters
                        .iter()
                        .map(|ident| ident.0.as_str())
                        .collect::<Vec<&str>>()
                        .join(",")
                ));
                body.render(accum);
            }
        }
    }
}

impl Render for Block {
    fn render(&self, accum: &mut String) {
        accum.push('{');
        self.0.iter().for_each(|stmt| {
            stmt.render(accum);
        });
        accum.push('}');
    }
}

impl Render for BlockStatement {
    fn render(&self, accum: &mut String) {
        match self {
            Self::Return(None) => {
                accum.push_str("return;");
            }
            Self::Return(Some(expression)) => {
                accum.push_str("return ");
                expression.render(accum);
                accum.push(';');
            }
            Self::Expression(expression) => {
                expression.render(accum);
                accum.push(';');
            }
            Self::Throw(message) => {
                accum.push_str("throw new Error(\"");
                accum.push_str(message);
                accum.push_str("\");");
            }
            Self::ConstAssignment { ident, value } => {
                accum.push_str(&format!("const {ident} = ", ident = ident.0));
                value.render(accum);
                accum.push(';');
            }
        }
    }
}

impl Render for Expression {
    fn render(&self, accum: &mut String) {
        match self {
            Self::Variable(ident) => {
                accum.push_str(&ident.0);
            }
            Self::ArrowFunction { parameters, body } => {
                accum.push_str(&format!(
                    "({parameters}) => ",
                    parameters = parameters
                        .iter()
                        .map(|ident| ident.0.as_str())
                        .collect::<Vec<&str>>()
                        .join(",")
                ));
                body.render(accum)
            }
            Self::Call {
                box function,
                arguments,
            } => {
                render_in_parens_if(
                    matches!(function, Self::ArrowFunction { .. }),
                    function,
                    accum,
                );
                accum.push('(');
                render_comma_sep(arguments, accum);
                accum.push(')');
            }
            Self::Conditional {
                box condition,
                true_clause,
                false_clause,
            } => {
                render_in_parens_if(
                    matches!(
                        condition,
                        Self::ArrowFunction { .. } | Self::Conditional { .. }
                    ),
                    condition,
                    accum,
                );
                accum.push('?');
                true_clause.render(accum);
                accum.push(':');
                false_clause.render(accum);
            }
            Self::Array(expressions) => {
                accum.push('[');
                render_comma_sep(expressions, accum);
                accum.push(']');
            }
            Self::Number(number_string) => {
                accum.push_str(number_string);
            }
            Self::String(inner_string) => {
                accum.push('"');
                accum.push_str(inner_string);
                accum.push('"');
            }
            Self::True => {
                accum.push_str("true");
            }
            Self::False => {
                accum.push_str("false");
            }
            Self::Undefined => {
                accum.push_str("undefined");
            }
            Self::Operator { op, lhs, rhs } => {
                // Always use parens rather than worry about precedence
                accum.push('(');
                lhs.render(accum);
                accum.push_str(match op {
                    Operator::And => " && ",
                    Operator::Equals => " === ",
                });
                rhs.render(accum);
                accum.push(')');
            }
            Self::IndexAccess { target, index } => {
                target.render(accum);
                accum.push('[');
                index.render(accum);
                accum.push(']');
            }
        }
    }
}

fn render_comma_sep<T: Render>(ts: &Vec<T>, accum: &mut String) {
    let len = ts.len();
    for (i, t) in ts.iter().enumerate() {
        t.render(accum);
        if i != len - 1 {
            accum.push(',');
        }
    }
}

fn render_in_parens_if<T: Render>(condition: bool, t: &T, accum: &mut String) {
    if condition {
        accum.push('(');
        t.render(accum);
        accum.push(')');
    } else {
        t.render(accum);
    }
}

impl Render for ArrowFunctionBody {
    fn render(&self, accum: &mut String) {
        match self {
            Self::Block(block) => block.render(accum),
            Self::Expression(expression) => expression.render(accum),
        }
    }
}

impl Render for Ident {
    fn render(&self, accum: &mut String) {
        accum.push_str(&self.0);
    }
}

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

    #[test]
    fn it_renders_identifiers() {
        assert_render!(ident!("foo"), "foo");
        assert_render!(ident!("Bar"), "Bar");
    }

    #[test]
    fn it_renders_expressions() {
        assert_render!(Expression::True, "true");
        assert_render!(Expression::False, "false");
        assert_render!(Expression::Undefined, "undefined");

        assert_render!(Expression::Number("42".to_string()), "42");
        assert_render!(Expression::String("five".to_string()), "\"five\"");

        assert_render!(Expression::Variable(ident!("foo")), "foo");

        assert_render!(
            Expression::ArrowFunction {
                parameters: vec![],
                body: Box::new(ArrowFunctionBody::Expression(Expression::String(
                    "test".to_string()
                )))
            },
            "() => \"test\""
        );
        assert_render!(
            Expression::ArrowFunction {
                parameters: vec![ident!("a")],
                body: Box::new(ArrowFunctionBody::Block(Block(vec![
                    BlockStatement::Return(Some(Expression::String("hello".to_string())))
                ]))),
            },
            "(a) => {return \"hello\";}"
        );
        assert_render!(
            Expression::ArrowFunction {
                parameters: vec![ident!("a"), ident!("b"), ident!("c")],
                body: Box::new(ArrowFunctionBody::Expression(Expression::ArrowFunction {
                    parameters: vec![],
                    body: Box::new(ArrowFunctionBody::Expression(Expression::Number(
                        "5".to_string()
                    )))
                }))
            },
            "(a,b,c) => () => 5"
        );

        assert_render!(
            Expression::Call {
                function: Box::new(Expression::Variable(ident!("f"))),
                arguments: vec![Expression::True, Expression::False]
            },
            "f(true,false)"
        );
        assert_render!(
            Expression::Call {
                function: Box::new(Expression::ArrowFunction {
                    parameters: vec![],
                    body: Box::new(ArrowFunctionBody::Expression(Expression::True))
                },),
                arguments: vec![]
            },
            "(() => true)()"
        );

        assert_render!(
            Expression::Conditional {
                condition: Box::new(Expression::True),
                true_clause: Box::new(Expression::Number("0".to_string())),
                false_clause: Box::new(Expression::Number("1".to_string())),
            },
            "true?0:1"
        );
        assert_render!(
            Expression::Conditional {
                condition: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::True),
                    true_clause: Box::new(Expression::True),
                    false_clause: Box::new(Expression::False),
                }),
                true_clause: Box::new(Expression::Number("0".to_string())),
                false_clause: Box::new(Expression::Number("1".to_string())),
            },
            "(true?true:false)?0:1"
        );
        assert_render!(
            Expression::Conditional {
                condition: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::True),
                    true_clause: Box::new(Expression::True),
                    false_clause: Box::new(Expression::False),
                }),
                true_clause: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::False),
                    true_clause: Box::new(Expression::Number("0".to_string())),
                    false_clause: Box::new(Expression::Number("1".to_string())),
                }),
                false_clause: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::False),
                    true_clause: Box::new(Expression::Number("2".to_string())),
                    false_clause: Box::new(Expression::Number("3".to_string())),
                }),
            },
            "(true?true:false)?false?0:1:false?2:3"
        );
        assert_render!(
            Expression::Operator {
                op: Operator::Equals,
                lhs: Box::new(Expression::Operator {
                    op: Operator::And,
                    lhs: Box::new(Expression::False),
                    rhs: Box::new(Expression::True),
                }),
                rhs: Box::new(Expression::True),
            },
            "((false && true) === true)"
        );

        assert_render!(
            Expression::IndexAccess {
                target: Box::new(Expression::IndexAccess {
                    target: Box::new(Expression::Variable(ident!("foo"))),
                    index: Box::new(Expression::String(String::from("bar")))
                }),
                index: Box::new(Expression::String(String::from("baz")))
            },
            r#"foo["bar"]["baz"]"#
        );
    }

    #[test]
    fn it_renders_block_statements() {
        assert_render!(
            BlockStatement::Return(Some(Expression::True)),
            "return true;"
        );
        assert_render!(BlockStatement::Return(None), "return;");
        assert_render!(
            BlockStatement::Throw(String::from("aaaahhh")),
            "throw new Error(\"aaaahhh\");"
        )
    }

    #[test]
    fn it_renders_blocks() {
        assert_render!(
            Block(vec![BlockStatement::Return(Some(Expression::True)),]),
            "{return true;}"
        );
    }

    #[test]
    fn it_renders_module_statements() {
        assert_render!(
            ModuleStatement::Function {
                ident: ident!("identity"),
                parameters: vec![ident!("a")],
                body: Block(vec![BlockStatement::Return(Some(Expression::Variable(
                    ident!("a")
                ))),]),
            },
            "function identity(a){return a;}"
        );
        assert_render!(
            ModuleStatement::ConstAssignment {
                ident: ident!("yes"),
                value: Expression::True,
            },
            "const yes = true;"
        );
        assert_render!(
            ModuleStatement::LetDeclaration {
                ident: ident!("huh"),
            },
            "let huh;"
        );
        assert_render!(
            ModuleStatement::Assignment {
                ident: ident!("huh"),
                value: Expression::Number("42".to_string()),
            },
            "huh = 42;"
        );
    }
}

#[cfg(test)]
mod test_macros {
    macro_rules! assert_render {
        ($renderable:expr, $want:expr) => {{
            let mut accum = String::new();
            $crate::render::Render::render(&$renderable, &mut accum);
            assert_eq!(accum.as_str(), $want);
        }};
    }

    pub(super) use assert_render;
}
<commit_msg>JavaScript ternary expressions must be wrapped in parens if called<commit_after>use crate::ast::{
    ArrowFunctionBody, Block, BlockStatement, Expression, Ident, ImportStatement, Module,
    ModuleStatement, Operator,
};

pub fn render_module(module: Module) -> String {
    let mut accum = String::new();
    module.render(&mut accum);
    accum
}

#[cfg(windows)]
static NEWLINE: &str = "\r\n";

#[cfg(not(windows))]
static NEWLINE: &str = "\n";

pub(crate) trait Render {
    // REVIEW I doubt pushing to a String like this is the most efficient solution?
    fn render(&self, accum: &mut String);
}

impl Render for Module {
    fn render(&self, accum: &mut String) {
        self.imports.iter().for_each(|import| {
            import.render(accum);
            accum.push_str(NEWLINE);
        });
        self.statements.iter().for_each(|stmt| {
            stmt.render(accum);
            accum.push_str(NEWLINE);
        });

        accum.push_str("export {");
        accum.push_str(
            &self
                .exports
                .iter()
                .map(|ident| ident.0.as_str())
                .collect::<Vec<_>>()
                .join(","),
        );
        accum.push_str("};");
        accum.push_str(NEWLINE);
    }
}

impl Render for ImportStatement {
    fn render(&self, accum: &mut String) {
        accum.push_str("import {");
        let imports = self
            .idents
            .iter()
            .map(|(aliased, ident)| format!("{} as {}", aliased.0, ident.0))
            .collect::<Vec<_>>();
        accum.push_str(&imports.join(","));
        accum.push_str(&format!("}} from \"{}\";", self.path));
    }
}

impl Render for ModuleStatement {
    fn render(&self, accum: &mut String) {
        match self {
            Self::LetDeclaration { ident } => {
                accum.push_str(&format!("let {ident};", ident = ident.0));
            }
            Self::ConstAssignment { ident, value } => {
                accum.push_str(&format!("const {ident} = ", ident = ident.0));
                value.render(accum);
                accum.push(';');
            }
            Self::Assignment { ident, value } => {
                accum.push_str(&format!("{ident} = ", ident = ident.0));
                value.render(accum);
                accum.push(';');
            }
            Self::Function {
                ident,
                parameters,
                body,
            } => {
                accum.push_str(&format!(
                    "function {ident}({parameters})",
                    ident = ident.0,
                    parameters = parameters
                        .iter()
                        .map(|ident| ident.0.as_str())
                        .collect::<Vec<&str>>()
                        .join(",")
                ));
                body.render(accum);
            }
        }
    }
}

impl Render for Block {
    fn render(&self, accum: &mut String) {
        accum.push('{');
        self.0.iter().for_each(|stmt| {
            stmt.render(accum);
        });
        accum.push('}');
    }
}

impl Render for BlockStatement {
    fn render(&self, accum: &mut String) {
        match self {
            Self::Return(None) => {
                accum.push_str("return;");
            }
            Self::Return(Some(expression)) => {
                accum.push_str("return ");
                expression.render(accum);
                accum.push(';');
            }
            Self::Expression(expression) => {
                expression.render(accum);
                accum.push(';');
            }
            Self::Throw(message) => {
                accum.push_str("throw new Error(\"");
                accum.push_str(message);
                accum.push_str("\");");
            }
            Self::ConstAssignment { ident, value } => {
                accum.push_str(&format!("const {ident} = ", ident = ident.0));
                value.render(accum);
                accum.push(';');
            }
        }
    }
}

impl Render for Expression {
    fn render(&self, accum: &mut String) {
        match self {
            Self::Variable(ident) => {
                accum.push_str(&ident.0);
            }
            Self::ArrowFunction { parameters, body } => {
                accum.push_str(&format!(
                    "({parameters}) => ",
                    parameters = parameters
                        .iter()
                        .map(|ident| ident.0.as_str())
                        .collect::<Vec<&str>>()
                        .join(",")
                ));
                body.render(accum)
            }
            Self::Call {
                box function,
                arguments,
            } => {
                render_in_parens_if(
                    matches!(
                        function,
                        Self::ArrowFunction { .. } | Self::Conditional { .. } // | Self::Operator { .. } <-- we wrap operators in parens
                    ),
                    function,
                    accum,
                );
                accum.push('(');
                render_comma_sep(arguments, accum);
                accum.push(')');
            }
            Self::Conditional {
                box condition,
                true_clause,
                false_clause,
            } => {
                render_in_parens_if(
                    matches!(
                        condition,
                        Self::ArrowFunction { .. } | Self::Conditional { .. } // | Self::Operator { .. } <-- we wrap operators in parens
                    ),
                    condition,
                    accum,
                );
                accum.push('?');
                true_clause.render(accum);
                accum.push(':');
                false_clause.render(accum);
            }
            Self::Array(expressions) => {
                accum.push('[');
                render_comma_sep(expressions, accum);
                accum.push(']');
            }
            Self::Number(number_string) => {
                accum.push_str(number_string);
            }
            Self::String(inner_string) => {
                accum.push('"');
                accum.push_str(inner_string);
                accum.push('"');
            }
            Self::True => {
                accum.push_str("true");
            }
            Self::False => {
                accum.push_str("false");
            }
            Self::Undefined => {
                accum.push_str("undefined");
            }
            Self::Operator { op, lhs, rhs } => {
                // Always use parens rather than worry about precedence/associativity
                accum.push('(');
                lhs.render(accum);
                accum.push_str(match op {
                    Operator::And => " && ",
                    Operator::Equals => " === ",
                });
                rhs.render(accum);
                accum.push(')');
            }
            Self::IndexAccess { target, index } => {
                target.render(accum);
                accum.push('[');
                index.render(accum);
                accum.push(']');
            }
        }
    }
}

fn render_comma_sep<T: Render>(ts: &Vec<T>, accum: &mut String) {
    let len = ts.len();
    for (i, t) in ts.iter().enumerate() {
        t.render(accum);
        if i != len - 1 {
            accum.push(',');
        }
    }
}

fn render_in_parens_if<T: Render>(condition: bool, t: &T, accum: &mut String) {
    if condition {
        accum.push('(');
        t.render(accum);
        accum.push(')');
    } else {
        t.render(accum);
    }
}

impl Render for ArrowFunctionBody {
    fn render(&self, accum: &mut String) {
        match self {
            Self::Block(block) => block.render(accum),
            Self::Expression(expression) => expression.render(accum),
        }
    }
}

impl Render for Ident {
    fn render(&self, accum: &mut String) {
        accum.push_str(&self.0);
    }
}

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

    #[test]
    fn it_renders_identifiers() {
        assert_render!(ident!("foo"), "foo");
        assert_render!(ident!("Bar"), "Bar");
    }

    #[test]
    fn it_renders_expressions() {
        assert_render!(Expression::True, "true");
        assert_render!(Expression::False, "false");
        assert_render!(Expression::Undefined, "undefined");

        assert_render!(Expression::Number("42".to_string()), "42");
        assert_render!(Expression::String("five".to_string()), "\"five\"");

        assert_render!(Expression::Variable(ident!("foo")), "foo");

        assert_render!(
            Expression::ArrowFunction {
                parameters: vec![],
                body: Box::new(ArrowFunctionBody::Expression(Expression::String(
                    "test".to_string()
                )))
            },
            "() => \"test\""
        );
        assert_render!(
            Expression::ArrowFunction {
                parameters: vec![ident!("a")],
                body: Box::new(ArrowFunctionBody::Block(Block(vec![
                    BlockStatement::Return(Some(Expression::String("hello".to_string())))
                ]))),
            },
            "(a) => {return \"hello\";}"
        );
        assert_render!(
            Expression::ArrowFunction {
                parameters: vec![ident!("a"), ident!("b"), ident!("c")],
                body: Box::new(ArrowFunctionBody::Expression(Expression::ArrowFunction {
                    parameters: vec![],
                    body: Box::new(ArrowFunctionBody::Expression(Expression::Number(
                        "5".to_string()
                    )))
                }))
            },
            "(a,b,c) => () => 5"
        );

        assert_render!(
            Expression::Call {
                function: Box::new(Expression::Variable(ident!("f"))),
                arguments: vec![Expression::True, Expression::False]
            },
            "f(true,false)"
        );
        assert_render!(
            Expression::Call {
                function: Box::new(Expression::ArrowFunction {
                    parameters: vec![],
                    body: Box::new(ArrowFunctionBody::Expression(Expression::True))
                },),
                arguments: vec![]
            },
            "(() => true)()"
        );

        assert_render!(
            Expression::Call {
                function: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::True),
                    true_clause: Box::new(Expression::Number("0".to_string())),
                    false_clause: Box::new(Expression::Number("1".to_string())),
                }),
                arguments: vec![]
            },
            "(true?0:1)()"
        );

        assert_render!(
            Expression::Conditional {
                condition: Box::new(Expression::True),
                true_clause: Box::new(Expression::Number("0".to_string())),
                false_clause: Box::new(Expression::Number("1".to_string())),
            },
            "true?0:1"
        );
        assert_render!(
            Expression::Conditional {
                condition: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::True),
                    true_clause: Box::new(Expression::True),
                    false_clause: Box::new(Expression::False),
                }),
                true_clause: Box::new(Expression::Number("0".to_string())),
                false_clause: Box::new(Expression::Number("1".to_string())),
            },
            "(true?true:false)?0:1"
        );
        assert_render!(
            Expression::Conditional {
                condition: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::True),
                    true_clause: Box::new(Expression::True),
                    false_clause: Box::new(Expression::False),
                }),
                true_clause: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::False),
                    true_clause: Box::new(Expression::Number("0".to_string())),
                    false_clause: Box::new(Expression::Number("1".to_string())),
                }),
                false_clause: Box::new(Expression::Conditional {
                    condition: Box::new(Expression::False),
                    true_clause: Box::new(Expression::Number("2".to_string())),
                    false_clause: Box::new(Expression::Number("3".to_string())),
                }),
            },
            "(true?true:false)?false?0:1:false?2:3"
        );
        assert_render!(
            Expression::Operator {
                op: Operator::Equals,
                lhs: Box::new(Expression::Operator {
                    op: Operator::And,
                    lhs: Box::new(Expression::False),
                    rhs: Box::new(Expression::True),
                }),
                rhs: Box::new(Expression::True),
            },
            "((false && true) === true)"
        );

        assert_render!(
            Expression::IndexAccess {
                target: Box::new(Expression::IndexAccess {
                    target: Box::new(Expression::Variable(ident!("foo"))),
                    index: Box::new(Expression::String(String::from("bar")))
                }),
                index: Box::new(Expression::String(String::from("baz")))
            },
            r#"foo["bar"]["baz"]"#
        );
    }

    #[test]
    fn it_renders_block_statements() {
        assert_render!(
            BlockStatement::Return(Some(Expression::True)),
            "return true;"
        );
        assert_render!(BlockStatement::Return(None), "return;");
        assert_render!(
            BlockStatement::Throw(String::from("aaaahhh")),
            "throw new Error(\"aaaahhh\");"
        )
    }

    #[test]
    fn it_renders_blocks() {
        assert_render!(
            Block(vec![BlockStatement::Return(Some(Expression::True)),]),
            "{return true;}"
        );
    }

    #[test]
    fn it_renders_module_statements() {
        assert_render!(
            ModuleStatement::Function {
                ident: ident!("identity"),
                parameters: vec![ident!("a")],
                body: Block(vec![BlockStatement::Return(Some(Expression::Variable(
                    ident!("a")
                ))),]),
            },
            "function identity(a){return a;}"
        );
        assert_render!(
            ModuleStatement::ConstAssignment {
                ident: ident!("yes"),
                value: Expression::True,
            },
            "const yes = true;"
        );
        assert_render!(
            ModuleStatement::LetDeclaration {
                ident: ident!("huh"),
            },
            "let huh;"
        );
        assert_render!(
            ModuleStatement::Assignment {
                ident: ident!("huh"),
                value: Expression::Number("42".to_string()),
            },
            "huh = 42;"
        );
    }
}

#[cfg(test)]
mod test_macros {
    macro_rules! assert_render {
        ($renderable:expr, $want:expr) => {{
            let mut accum = String::new();
            $crate::render::Render::render(&$renderable, &mut accum);
            assert_eq!(accum.as_str(), $want);
        }};
    }

    pub(super) use assert_render;
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::io::prelude::*;
use std::path::Path;

use rustc_serialize::{Decodable, Decoder};

use git2::Config as GitConfig;

use term::color::BLACK;

use util::{GitRepo, HgRepo, CargoResult, human, ChainError, internal};
use util::{Config, paths};

use toml;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VersionControl { Git, Hg, NoVcs }

pub struct NewOptions<'a> {
    pub version_control: Option<VersionControl>,
    pub bin: bool,
    pub path: &'a str,
    pub name: Option<&'a str>,
}

impl Decodable for VersionControl {
    fn decode<D: Decoder>(d: &mut D) -> Result<VersionControl, D::Error> {
        Ok(match &try!(d.read_str())[..] {
            "git" => VersionControl::Git,
            "hg" => VersionControl::Hg,
            "none" => VersionControl::NoVcs,
            n => {
                let err = format!("could not decode '{}' as version control", n);
                return Err(d.error(&err));
            }
        })
    }
}

struct CargoNewConfig {
    name: Option<String>,
    email: Option<String>,
    version_control: Option<VersionControl>,
}

pub fn new(opts: NewOptions, config: &Config) -> CargoResult<()> {
    let path = config.cwd().join(opts.path);
    if fs::metadata(&path).is_ok() {
        bail!("destination `{}` already exists", path.display())
    }
    let name = match opts.name {
        Some(name) => name,
        None => {
            let dir_name = try!(path.file_name().and_then(|s| s.to_str()).chain_error(|| {
                human(&format!("cannot create a project with a non-unicode name: {:?}",
                               path.file_name().unwrap()))
            }));
            if opts.bin {
                dir_name
            } else {
                let new_name = strip_rust_affixes(dir_name);
                if new_name != dir_name {
                    let message = format!(
                        "note: package will be named `{}`; use --name to override",
                        new_name);
                    try!(config.shell().say(&message, BLACK));
                }
                new_name
            }
        }
    };
    for c in name.chars() {
        if c.is_alphanumeric() { continue }
        if c == '_' || c == '-' { continue }
        bail!("Invalid character `{}` in crate name: `{}`", c, name)
    }
    mk(config, &path, name, &opts).chain_error(|| {
        human(format!("Failed to create project `{}` at `{}`",
                      name, path.display()))
    })
}

fn strip_rust_affixes(name: &str) -> &str {
    for &prefix in &["rust-", "rust_", "rs-", "rs_"] {
        if name.starts_with(prefix) {
            return &name[prefix.len()..];
        }
    }
    for &suffix in &["-rust", "_rust", "-rs", "_rs"] {
        if name.ends_with(suffix) {
            return &name[..name.len()-suffix.len()];
        }
    }
    name
}

fn existing_vcs_repo(path: &Path, cwd: &Path) -> bool {
    GitRepo::discover(path, cwd).is_ok() || HgRepo::discover(path, cwd).is_ok()
}

fn mk(config: &Config, path: &Path, name: &str,
      opts: &NewOptions) -> CargoResult<()> {
    let cfg = try!(global_config(config));
    let mut ignore = "target\n".to_string();
    let in_existing_vcs_repo = existing_vcs_repo(path.parent().unwrap(), config.cwd());
    if !opts.bin {
        ignore.push_str("Cargo.lock\n");
    }

    let vcs = match (opts.version_control, cfg.version_control, in_existing_vcs_repo) {
        (None, None, false) => VersionControl::Git,
        (None, Some(option), false) => option,
        (Some(option), _, _) => option,
        (_, _, true) => VersionControl::NoVcs,
    };

    match vcs {
        VersionControl::Git => {
            try!(GitRepo::init(path, config.cwd()));
            try!(paths::write(&path.join(".gitignore"), ignore.as_bytes()));
        },
        VersionControl::Hg => {
            try!(HgRepo::init(path, config.cwd()));
            try!(paths::write(&path.join(".hgignore"), ignore.as_bytes()));
        },
        VersionControl::NoVcs => {
            try!(fs::create_dir(path));
        },
    };

    let (author_name, email) = try!(discover_author());
    // Hoo boy, sure glad we've got exhaustivenes checking behind us.
    let author = match (cfg.name, cfg.email, author_name, email) {
        (Some(name), Some(email), _, _) |
        (Some(name), None, _, Some(email)) |
        (None, Some(email), name, _) |
        (None, None, name, Some(email)) => format!("{} <{}>", name, email),
        (Some(name), None, _, None) |
        (None, None, name, None) => name,
    };

    try!(paths::write(&path.join("Cargo.toml"), format!(
r#"[package]
name = "{}"
version = "0.1.0"
authors = [{}]

[dependencies]
"#, name, toml::Value::String(author)).as_bytes()));

    try!(fs::create_dir(&path.join("src")));

    if opts.bin {
        try!(paths::write(&path.join("src/main.rs"), b"\
fn main() {
    println!(\"Hello, world!\");
}
"));
    } else {
        try!(paths::write(&path.join("src/lib.rs"), b"\
#[test]
fn it_works() {
}
"));
    }

    Ok(())
}

fn discover_author() -> CargoResult<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name = git_config.and_then(|g| g.get_string("user.name").ok())
                         .map(|s| s.to_string())
                         .or_else(|| env::var("USER").ok())      // unix
                         .or_else(|| env::var("USERNAME").ok()); // windows
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) {"USERNAME"} else {"USER"};
            bail!("could not determine the current user, please set ${}",
                  username_var)
        }
    };
    let email = git_config.and_then(|g| g.get_string("user.email").ok())
                          .or_else(|| env::var("EMAIL").ok());

    let name = name.trim().to_string();
    let email = email.map(|s| s.trim().to_string());

    Ok((name, email))
}

fn global_config(config: &Config) -> CargoResult<CargoNewConfig> {
    let name = try!(config.get_string("cargo-new.name")).map(|s| s.0);
    let email = try!(config.get_string("cargo-new.email")).map(|s| s.0);
    let vcs = try!(config.get_string("cargo-new.vcs"));

    let vcs = match vcs.as_ref().map(|p| (&p.0[..], &p.1)) {
        Some(("git", _)) => Some(VersionControl::Git),
        Some(("hg", _)) => Some(VersionControl::Hg),
        Some(("none", _)) => Some(VersionControl::NoVcs),
        Some((s, p)) => {
            return Err(internal(format!("invalid configuration for key \
                                         `cargo-new.vcs`, unknown vcs `{}` \
                                         (found in {:?})", s, p)))
        }
        None => None
    };
    Ok(CargoNewConfig {
        name: name,
        email: email,
        version_control: vcs,
    })
}

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

    #[test]
    fn affixes_stripped() {
        assert_eq!(strip_rust_affixes("rust-foo"), "foo");
        assert_eq!(strip_rust_affixes("foo-rs"), "foo");
        assert_eq!(strip_rust_affixes("rs_foo"), "foo");
        // Only one affix is stripped
        assert_eq!(strip_rust_affixes("rs-foo-rs"), "foo-rs");
        assert_eq!(strip_rust_affixes("foo-rs-rs"), "foo-rs");
        // It shouldn't touch the middle
        assert_eq!(strip_rust_affixes("some-rust-crate"), "some-rust-crate");
    }
}
<commit_msg>Tweak the new project template to be more idiomatic.<commit_after>use std::env;
use std::fs;
use std::io::prelude::*;
use std::path::Path;

use rustc_serialize::{Decodable, Decoder};

use git2::Config as GitConfig;

use term::color::BLACK;

use util::{GitRepo, HgRepo, CargoResult, human, ChainError, internal};
use util::{Config, paths};

use toml;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VersionControl { Git, Hg, NoVcs }

pub struct NewOptions<'a> {
    pub version_control: Option<VersionControl>,
    pub bin: bool,
    pub path: &'a str,
    pub name: Option<&'a str>,
}

impl Decodable for VersionControl {
    fn decode<D: Decoder>(d: &mut D) -> Result<VersionControl, D::Error> {
        Ok(match &try!(d.read_str())[..] {
            "git" => VersionControl::Git,
            "hg" => VersionControl::Hg,
            "none" => VersionControl::NoVcs,
            n => {
                let err = format!("could not decode '{}' as version control", n);
                return Err(d.error(&err));
            }
        })
    }
}

struct CargoNewConfig {
    name: Option<String>,
    email: Option<String>,
    version_control: Option<VersionControl>,
}

pub fn new(opts: NewOptions, config: &Config) -> CargoResult<()> {
    let path = config.cwd().join(opts.path);
    if fs::metadata(&path).is_ok() {
        bail!("destination `{}` already exists", path.display())
    }
    let name = match opts.name {
        Some(name) => name,
        None => {
            let dir_name = try!(path.file_name().and_then(|s| s.to_str()).chain_error(|| {
                human(&format!("cannot create a project with a non-unicode name: {:?}",
                               path.file_name().unwrap()))
            }));
            if opts.bin {
                dir_name
            } else {
                let new_name = strip_rust_affixes(dir_name);
                if new_name != dir_name {
                    let message = format!(
                        "note: package will be named `{}`; use --name to override",
                        new_name);
                    try!(config.shell().say(&message, BLACK));
                }
                new_name
            }
        }
    };
    for c in name.chars() {
        if c.is_alphanumeric() { continue }
        if c == '_' || c == '-' { continue }
        bail!("Invalid character `{}` in crate name: `{}`", c, name)
    }
    mk(config, &path, name, &opts).chain_error(|| {
        human(format!("Failed to create project `{}` at `{}`",
                      name, path.display()))
    })
}

fn strip_rust_affixes(name: &str) -> &str {
    for &prefix in &["rust-", "rust_", "rs-", "rs_"] {
        if name.starts_with(prefix) {
            return &name[prefix.len()..];
        }
    }
    for &suffix in &["-rust", "_rust", "-rs", "_rs"] {
        if name.ends_with(suffix) {
            return &name[..name.len()-suffix.len()];
        }
    }
    name
}

fn existing_vcs_repo(path: &Path, cwd: &Path) -> bool {
    GitRepo::discover(path, cwd).is_ok() || HgRepo::discover(path, cwd).is_ok()
}

fn mk(config: &Config, path: &Path, name: &str,
      opts: &NewOptions) -> CargoResult<()> {
    let cfg = try!(global_config(config));
    let mut ignore = "target\n".to_string();
    let in_existing_vcs_repo = existing_vcs_repo(path.parent().unwrap(), config.cwd());
    if !opts.bin {
        ignore.push_str("Cargo.lock\n");
    }

    let vcs = match (opts.version_control, cfg.version_control, in_existing_vcs_repo) {
        (None, None, false) => VersionControl::Git,
        (None, Some(option), false) => option,
        (Some(option), _, _) => option,
        (_, _, true) => VersionControl::NoVcs,
    };

    match vcs {
        VersionControl::Git => {
            try!(GitRepo::init(path, config.cwd()));
            try!(paths::write(&path.join(".gitignore"), ignore.as_bytes()));
        },
        VersionControl::Hg => {
            try!(HgRepo::init(path, config.cwd()));
            try!(paths::write(&path.join(".hgignore"), ignore.as_bytes()));
        },
        VersionControl::NoVcs => {
            try!(fs::create_dir(path));
        },
    };

    let (author_name, email) = try!(discover_author());
    // Hoo boy, sure glad we've got exhaustivenes checking behind us.
    let author = match (cfg.name, cfg.email, author_name, email) {
        (Some(name), Some(email), _, _) |
        (Some(name), None, _, Some(email)) |
        (None, Some(email), name, _) |
        (None, None, name, Some(email)) => format!("{} <{}>", name, email),
        (Some(name), None, _, None) |
        (None, None, name, None) => name,
    };

    try!(paths::write(&path.join("Cargo.toml"), format!(
r#"[package]
name = "{}"
version = "0.1.0"
authors = [{}]

[dependencies]
"#, name, toml::Value::String(author)).as_bytes()));

    try!(fs::create_dir(&path.join("src")));

    if opts.bin {
        try!(paths::write(&path.join("src/main.rs"), b"\
fn main() {
    println!(\"Hello, world!\");
}
"));
    } else {
        try!(paths::write(&path.join("src/lib.rs"), b"\
#[cfg(test)]
mod test {
    #[test]
    fn it_works() {
    }
}
"));
    }

    Ok(())
}

fn discover_author() -> CargoResult<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name = git_config.and_then(|g| g.get_string("user.name").ok())
                         .map(|s| s.to_string())
                         .or_else(|| env::var("USER").ok())      // unix
                         .or_else(|| env::var("USERNAME").ok()); // windows
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) {"USERNAME"} else {"USER"};
            bail!("could not determine the current user, please set ${}",
                  username_var)
        }
    };
    let email = git_config.and_then(|g| g.get_string("user.email").ok())
                          .or_else(|| env::var("EMAIL").ok());

    let name = name.trim().to_string();
    let email = email.map(|s| s.trim().to_string());

    Ok((name, email))
}

fn global_config(config: &Config) -> CargoResult<CargoNewConfig> {
    let name = try!(config.get_string("cargo-new.name")).map(|s| s.0);
    let email = try!(config.get_string("cargo-new.email")).map(|s| s.0);
    let vcs = try!(config.get_string("cargo-new.vcs"));

    let vcs = match vcs.as_ref().map(|p| (&p.0[..], &p.1)) {
        Some(("git", _)) => Some(VersionControl::Git),
        Some(("hg", _)) => Some(VersionControl::Hg),
        Some(("none", _)) => Some(VersionControl::NoVcs),
        Some((s, p)) => {
            return Err(internal(format!("invalid configuration for key \
                                         `cargo-new.vcs`, unknown vcs `{}` \
                                         (found in {:?})", s, p)))
        }
        None => None
    };
    Ok(CargoNewConfig {
        name: name,
        email: email,
        version_control: vcs,
    })
}

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

    #[test]
    fn affixes_stripped() {
        assert_eq!(strip_rust_affixes("rust-foo"), "foo");
        assert_eq!(strip_rust_affixes("foo-rs"), "foo");
        assert_eq!(strip_rust_affixes("rs_foo"), "foo");
        // Only one affix is stripped
        assert_eq!(strip_rust_affixes("rs-foo-rs"), "foo-rs");
        assert_eq!(strip_rust_affixes("foo-rs-rs"), "foo-rs");
        // It shouldn't touch the middle
        assert_eq!(strip_rust_affixes("some-rust-crate"), "some-rust-crate");
    }
}
<|endoftext|>


<commit_before>/// Converts a `String` to lowercase `String`
///
/// #Examples
/// ```
///     use inflector::cases::lowercase::to_lower_case;
///     let mock_string: String = "FoObAR".to_string();
///     let expected_string: String = "foobar".to_string();
///     let asserted_string: String = to_lower_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
pub fn to_lower_case(non_lower_string: String) -> String {
    // See https://github.com/calebmer/inflections/blob/master/src/case.rs#L37 for where this
    // implementation comes from.
    non_lower_string.chars()
        .flat_map(char::to_lowercase)
        .collect()
}

/// Determines if a `String` is lowercase
///
/// #Examples
/// ```
///     use inflector::cases::lowercase::is_lower_case;
///     let mock_string: String = "foobarisareallyreallylongstring".to_string();
///     let asserted_bool: bool = is_lower_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
/// ```
///     use inflector::cases::lowercase::is_lower_case;
///     let mock_string: String = "Foobarisareallyreallylongstring".to_string();
///     let asserted_bool: bool = is_lower_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::lowercase::is_lower_case;
///     let mock_string: String = "FOOBARSTRINGTHATISREALLYREALLYLONG".to_string();
///     let asserted_bool: bool = is_lower_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
pub fn is_lower_case(test_string: String) -> bool {
    test_string == to_lower_case(test_string.clone())
}
<commit_msg>Lower bench<commit_after>/// Converts a `String` to lowercase `String`
///
/// #Examples
/// ```
///     use inflector::cases::lowercase::to_lower_case;
///     let mock_string: String = "FoObAR".to_string();
///     let expected_string: String = "foobar".to_string();
///     let asserted_string: String = to_lower_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
pub fn to_lower_case(non_lower_string: String) -> String {
    // See https://github.com/calebmer/inflections/blob/master/src/case.rs#L37 for where this
    // implementation comes from.
    non_lower_string.chars()
        .flat_map(char::to_lowercase)
        .collect()
}

/// Determines if a `String` is lowercase
///
/// #Examples
/// ```
///     use inflector::cases::lowercase::is_lower_case;
///     let mock_string: String = "foobarisareallyreallylongstring".to_string();
///     let asserted_bool: bool = is_lower_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
/// ```
///     use inflector::cases::lowercase::is_lower_case;
///     let mock_string: String = "Foobarisareallyreallylongstring".to_string();
///     let asserted_bool: bool = is_lower_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::lowercase::is_lower_case;
///     let mock_string: String = "FOOBARSTRINGTHATISREALLYREALLYLONG".to_string();
///     let asserted_bool: bool = is_lower_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
pub fn is_lower_case(test_string: String) -> bool {
    test_string == to_lower_case(test_string.clone())
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    #[bench]
    fn bench_lower(b: &mut Bencher) {
        b.iter(|| super::to_lower_case("Foo BAR".to_string()));
    }

    #[bench]
    fn bench_is_lower(b: &mut Bencher) {
        b.iter(|| super::is_lower_case("Foo bar".to_string()));
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::sync::Arc;
use std::marker::PhantomData;

use futures::{Async, Future};
use futures::future::FutureResult;
use tokio_core::io::Io;
use tokio_core::reactor::Handle;
use minihttp::Status;
use minihttp::server::{Dispatcher, Error, Head};
use minihttp::server as http;
use minihttp::server::{EncoderDone, RecvMode, WebsocketAccept};

use intern::{Topic, SessionPoolName, Lattice as Namespace};
use chat::Cid;
use config::SessionPool;
use runtime::Runtime;

pub struct Handler {
    runtime: Arc<Runtime>,
    name: SessionPoolName,
    settings: Arc<SessionPool>,
    handle: Handle,
}

pub struct Request {
    settings: Arc<SessionPool>,
    query: Result<Route, Status>,
}

pub enum Route {
    /// `PUT /v1/connection/<conn_id>/subscriptions/<path>`
    Subscribe(Cid, Topic),
    /// `DELETE /v1/connection/<conn_id>/subscriptions/<path>`
    Unsubscribe(Cid, Topic),
    /// `POST /v1/publish/<path>`
    Publish(Topic),
    /// `PUT /v1/connection/<conn_id>/lattices/<namespace>`
    Attach(Cid, Namespace),
    /// `DELETE /v1/connection/<conn_id>/lattices/<namespace>`
    Detach(Cid, Namespace),
    /// `POST /v1/lattice/<namespace>`
    Lattice(Namespace),
}

impl fmt::Display for Route {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Route::*;
        match *self {
            Subscribe(cid, ref tpc) => {
                write!(f, "Subscribe {:#?} {:?}", cid, tpc)
            }
            Unsubscribe(cid, ref tpc) => {
                write!(f, "Unsubscribe {:#?} {:?}", cid, tpc)
            }
            Publish(ref topic) => write!(f, "Publish {:?}", topic),
            Attach(cid, ref ns) => {
                write!(f, "Lattice attach {:#?} {:?}", cid, ns)
            }
            Detach(cid, ref ns) => {
                write!(f, "Lattice detach {:#?} {:?}", cid, ns)
            }
            Lattice(ref ns) => write!(f, "Lattice update {:?}", ns),
        }
    }
}

impl Handler {
    pub fn new(runtime: Arc<Runtime>, name: SessionPoolName,
        settings: Arc<SessionPool>, handle: Handle)
        -> Handler
    {
        Handler {
            runtime: runtime,
            name: name,
            settings: settings,
            handle: handle,
        }
    }
}

impl<S: Io> Dispatcher<S> for Handler {
    type Codec = Request;
    fn headers_received(&mut self, headers: &Head)
        -> Result<Self::Codec, Error>
    {
        let query = match headers.path() {
            Some(path) => {
                if !path.starts_with("/v1/") {
                    Err(Status::NotFound)
                } else {
                    self.dispatch(&path[4..], headers.method())
                }
            }
            None => {
                Err(Status::BadRequest)
            }
        };
        match query {
            Ok(ref route) => {
                info!("{:?} received from backend {}", self.name, route);
            }
            Err(status) => {
                info!("{:?} path {:?} gets {:?}",
                    self.name, headers.path(), status);
            }
        }
        Ok(Request {
            settings: self.settings.clone(),
            query: query,
        })
    }
}

impl Handler {
    fn dispatch(&mut self, path: &str, method: &str) -> Result<Route, Status> {
        let mut iter = path.splitn(2, '/');
        let head = iter.next().unwrap();
        let tail = iter.next();
        match (head, tail) {
            ("connection", Some(tail)) => {
                let mut p = tail.splitn(3, '/');
                let cid = p.next().and_then(|x| x.parse().ok());
                let middle = p.next();
                let tail = p.next();
                match middle {
                    Some("subscriptions") => {
                        let topic = tail.and_then(|x| {
                            x.replace("/", ".").parse().ok()
                        });
                        match (method, cid, topic) {
                            ("PUT", Some(cid), Some(t)) => {
                                Ok(Route::Subscribe(cid, t))
                            }
                            ("DELETE", Some(cid), Some(t)) => {
                                Ok(Route::Unsubscribe(cid, t))
                            }
                            _ => Err(Status::NotFound),
                        }
                    }
                    Some("lattices") => {
                        let ns = tail.and_then(|x| {
                            x.replace("/", ".").parse().ok()
                        });
                        match (method, cid, ns) {
                            ("PUT", Some(cid), Some(ns)) => {
                                Ok(Route::Attach(cid, ns))
                            }
                            ("DELETE", Some(cid), Some(ns)) => {
                                Ok(Route::Detach(cid, ns))
                            }
                            _ => Err(Status::NotFound),
                        }
                    }
                    _ => Err(Status::NotFound),
                }
            }
            ("publish", Some(tail)) => {
                let topic = tail.replace("/", ".").parse().ok();
                if let Some(topic) = topic {
                    Ok(Route::Publish(topic))
                } else {
                    Err(Status::NotFound)
                }
            }
            ("lattice", Some(tail)) => {
                let topic = tail.replace("/", ".").parse().ok();
                if let Some(topic) = topic {
                    Ok(Route::Lattice(topic))
                } else {
                    Err(Status::NotFound)
                }
            }
            _ => {
                Err(Status::NotFound)
            }
        }
    }
}

impl<S: Io> http::Codec<S> for Request {
    type ResponseFuture = FutureResult<EncoderDone<S>, Error>;
    fn recv_mode(&mut self) -> RecvMode {
        RecvMode::BufferedUpfront(self.settings.max_payload_size)
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        assert!(end);
        match self.query {
            Subscribe(cid, ref topic) => {
                unimplemented!();
            }
            Unsubscribe(cid, ref topic) => {
                unimplemented!();
            }
            Public(ref topic) => {
                unimplemented!();
            }
            Attach(cid, ref ns) => {
                unimplemented!();
            }
            Detach(cid, ref ns) => {
                unimplemented!();
            }
            Lattice(ref ns) => {
                unimplemented!();
            }
        }
    }
    fn start_response(&mut self, e: http::Encoder<S>) -> Self::ResponseFuture {
        if let Err(status) = self.query {
            e.status(status)
            // TODO(tailhook) add some body describing the error
            e.add_length(0);
            e.done_headers().unwrap();
            e.done()
        } else {
            e.status(Status::NoContent)
            e.add_length(0);
            e.done_headers().unwrap();
            e.done()
        }
    }
}
<commit_msg>Fixup of the previous commit<commit_after>use std::fmt;
use std::sync::Arc;
use std::marker::PhantomData;

use futures::{Async, Future};
use futures::future::{FutureResult, ok};
use tokio_core::io::Io;
use tokio_core::reactor::Handle;
use minihttp::Status;
use minihttp::server::{Dispatcher, Error, Head};
use minihttp::server as http;
use minihttp::server::{EncoderDone, RecvMode, WebsocketAccept};

use intern::{Topic, SessionPoolName, Lattice as Namespace};
use chat::Cid;
use config::SessionPool;
use runtime::Runtime;

pub struct Handler {
    runtime: Arc<Runtime>,
    name: SessionPoolName,
    settings: Arc<SessionPool>,
    handle: Handle,
}

pub struct Request {
    settings: Arc<SessionPool>,
    query: Result<Route, Status>,
}

pub enum Route {
    /// `PUT /v1/connection/<conn_id>/subscriptions/<path>`
    Subscribe(Cid, Topic),
    /// `DELETE /v1/connection/<conn_id>/subscriptions/<path>`
    Unsubscribe(Cid, Topic),
    /// `POST /v1/publish/<path>`
    Publish(Topic),
    /// `PUT /v1/connection/<conn_id>/lattices/<namespace>`
    Attach(Cid, Namespace),
    /// `DELETE /v1/connection/<conn_id>/lattices/<namespace>`
    Detach(Cid, Namespace),
    /// `POST /v1/lattice/<namespace>`
    Lattice(Namespace),
}

impl fmt::Display for Route {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Route::*;
        match *self {
            Subscribe(cid, ref tpc) => {
                write!(f, "Subscribe {:#?} {:?}", cid, tpc)
            }
            Unsubscribe(cid, ref tpc) => {
                write!(f, "Unsubscribe {:#?} {:?}", cid, tpc)
            }
            Publish(ref topic) => write!(f, "Publish {:?}", topic),
            Attach(cid, ref ns) => {
                write!(f, "Lattice attach {:#?} {:?}", cid, ns)
            }
            Detach(cid, ref ns) => {
                write!(f, "Lattice detach {:#?} {:?}", cid, ns)
            }
            Lattice(ref ns) => write!(f, "Lattice update {:?}", ns),
        }
    }
}

impl Handler {
    pub fn new(runtime: Arc<Runtime>, name: SessionPoolName,
        settings: Arc<SessionPool>, handle: Handle)
        -> Handler
    {
        Handler {
            runtime: runtime,
            name: name,
            settings: settings,
            handle: handle,
        }
    }
}

impl<S: Io> Dispatcher<S> for Handler {
    type Codec = Request;
    fn headers_received(&mut self, headers: &Head)
        -> Result<Self::Codec, Error>
    {
        let query = match headers.path() {
            Some(path) => {
                if !path.starts_with("/v1/") {
                    Err(Status::NotFound)
                } else {
                    self.dispatch(&path[4..], headers.method())
                }
            }
            None => {
                Err(Status::BadRequest)
            }
        };
        match query {
            Ok(ref route) => {
                info!("{:?} received from backend {}", self.name, route);
            }
            Err(status) => {
                info!("{:?} path {:?} gets {:?}",
                    self.name, headers.path(), status);
            }
        }
        Ok(Request {
            settings: self.settings.clone(),
            query: query,
        })
    }
}

impl Handler {
    fn dispatch(&mut self, path: &str, method: &str) -> Result<Route, Status> {
        let mut iter = path.splitn(2, '/');
        let head = iter.next().unwrap();
        let tail = iter.next();
        match (head, tail) {
            ("connection", Some(tail)) => {
                let mut p = tail.splitn(3, '/');
                let cid = p.next().and_then(|x| x.parse().ok());
                let middle = p.next();
                let tail = p.next();
                match middle {
                    Some("subscriptions") => {
                        let topic = tail.and_then(|x| {
                            x.replace("/", ".").parse().ok()
                        });
                        match (method, cid, topic) {
                            ("PUT", Some(cid), Some(t)) => {
                                Ok(Route::Subscribe(cid, t))
                            }
                            ("DELETE", Some(cid), Some(t)) => {
                                Ok(Route::Unsubscribe(cid, t))
                            }
                            _ => Err(Status::NotFound),
                        }
                    }
                    Some("lattices") => {
                        let ns = tail.and_then(|x| {
                            x.replace("/", ".").parse().ok()
                        });
                        match (method, cid, ns) {
                            ("PUT", Some(cid), Some(ns)) => {
                                Ok(Route::Attach(cid, ns))
                            }
                            ("DELETE", Some(cid), Some(ns)) => {
                                Ok(Route::Detach(cid, ns))
                            }
                            _ => Err(Status::NotFound),
                        }
                    }
                    _ => Err(Status::NotFound),
                }
            }
            ("publish", Some(tail)) => {
                let topic = tail.replace("/", ".").parse().ok();
                if let Some(topic) = topic {
                    Ok(Route::Publish(topic))
                } else {
                    Err(Status::NotFound)
                }
            }
            ("lattice", Some(tail)) => {
                let topic = tail.replace("/", ".").parse().ok();
                if let Some(topic) = topic {
                    Ok(Route::Lattice(topic))
                } else {
                    Err(Status::NotFound)
                }
            }
            _ => {
                Err(Status::NotFound)
            }
        }
    }
}

impl<S: Io> http::Codec<S> for Request {
    type ResponseFuture = FutureResult<EncoderDone<S>, Error>;
    fn recv_mode(&mut self) -> RecvMode {
        RecvMode::BufferedUpfront(self.settings.max_payload_size)
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        use self::Route::*;
        assert!(end);
        match self.query {
            Ok(Subscribe(cid, ref topic)) => {
                unimplemented!();
            }
            Ok(Unsubscribe(cid, ref topic)) => {
                unimplemented!();
            }
            Ok(Publish(ref topic)) => {
                unimplemented!();
            }
            Ok(Attach(cid, ref ns)) => {
                unimplemented!();
            }
            Ok(Detach(cid, ref ns)) => {
                unimplemented!();
            }
            Ok(Lattice(ref ns)) => {
                unimplemented!();
            }
            Err(_) => {}
        }
        Ok(Async::Ready(data.len()))
    }
    fn start_response(&mut self, mut e: http::Encoder<S>)
        -> Self::ResponseFuture
    {
        if let Err(status) = self.query {
            e.status(status);
            // TODO(tailhook) add some body describing the error
            e.add_length(0);
            e.done_headers().unwrap();
            ok(e.done())
        } else {
            e.status(Status::NoContent);
            e.add_length(0);
            e.done_headers().unwrap();
            ok(e.done())
        }
    }
}
<|endoftext|>


<commit_before>use crate::Msg;
use seed::prelude::*;

pub fn render() -> Node<Msg> {
    div![
        h1!["Primality Test, Calculate Primes"],
        br![],
        br![],
        br![],
        //TODO: Convert the j.js file into rust!
        Script!(attrs! {At::Src => "https://static.bigprimes.net/j.js"}),
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Name => "primetest", At::OnSubmit => "return false"},
                    "Tool is limited to checking numbers upto 16 digits.",
                    br![],
                    br![],
                    "Is ",
                    input![
                        attrs! {At::Type => "text", At::Size => "16", At::Name => "input", At::Value => "", At::MaxLength => "16"}
                    ],
                    " prime? ",
                    button![attrs! {At::OnClick => "check(false,0)"}, "Check!"],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Name => "javascriptoutput", At::Cols => 60, At::Rows => 2, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Name => "primelist", At::OnSubmit => "return false"},
                    "This tool is limited to checking numbers upto 15 digits.",
                    br![],
                    br![],
                    "This will show ",
                    input![
                        attrs! {At::Type => "text", At::Size => "4", At::Name => "primes", At::Value => "1", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "text", At::Size => "16", At::Name => "start", At::Value => "0", At::MaxLength => "15"}
                    ],
                    " ",
                    button![
                        attrs! {At::OnClick => "primelist.javascriptlistoutput.value='';listy();"},
                        "Go!"
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Name => "javascriptlistoutput", At::Cols => 60, At::Rows => 10, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ]
    ]
}
<commit_msg>Added trial_divide() and corresponding unit tests<commit_after>use crate::Msg;
use seed::prelude::*;

fn trial_divide(n: usize, max: usize) -> usize {
    // Trial divides the positive integer n by the primes from 2 to max
    // Returns the first prime divisor found, or 0 if none found
    // Note: if n < max^2 is a prime, then n will be returned.
    if n % 2 == 0 {
        2
    } else if n % 3 == 0 {
        3
    } else {
        // No need to go past the square root of our number
        let sqrt: usize = (n as f64).sqrt().floor() as usize;
        let stop = if sqrt > max { max } else { sqrt };
        // Okay, lets "wheel factor" alternately adding 2 and 4
        let mut di = 2;
        let mut i = 5;
        while i <= stop {
            if n % i == 0 {
                return i;
            }
            i += di;
            di = 6 - di;
        }
        if n >= max * max {
            0
        } else {
            n
        }
    }
}

pub fn render() -> Node<Msg> {
    div![
        h1!["Primality Test, Calculate Primes"],
        br![],
        br![],
        br![],
        //TODO: Convert the j.js file into rust!
        Script!(attrs! {At::Src => "https://static.bigprimes.net/j.js"}),
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Name => "primetest", At::OnSubmit => "return false"},
                    "Tool is limited to checking numbers upto 16 digits.",
                    br![],
                    br![],
                    "Is ",
                    input![
                        attrs! {At::Type => "text", At::Size => "16", At::Name => "input", At::Value => "", At::MaxLength => "16"}
                    ],
                    " prime? ",
                    button![attrs! {At::OnClick => "check(false,0)"}, "Check!"],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Name => "javascriptoutput", At::Cols => 60, At::Rows => 2, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Name => "primelist", At::OnSubmit => "return false"},
                    "This tool is limited to checking numbers upto 15 digits.",
                    br![],
                    br![],
                    "This will show ",
                    input![
                        attrs! {At::Type => "text", At::Size => "4", At::Name => "primes", At::Value => "1", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "text", At::Size => "16", At::Name => "start", At::Value => "0", At::MaxLength => "15"}
                    ],
                    " ",
                    button![
                        attrs! {At::OnClick => "primelist.javascriptlistoutput.value='';listy();"},
                        "Go!"
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Name => "javascriptlistoutput", At::Cols => 60, At::Rows => 10, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ]
    ]
}

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

    #[test]
    fn trial_divide_test() {
        assert_eq!(trial_divide(2, 2), 2);
        assert_eq!(trial_divide(3, 4), 3);
        assert_eq!(trial_divide(30, 10000), 2);
        assert_eq!(trial_divide(7777771, 10000), 29);
        assert_eq!(trial_divide(7777771111111111, 10000), 11);
        //in the case of a prime
        assert_eq!(trial_divide(777777111111113, 10000), 0);
    }
}
<|endoftext|>


<commit_before>use LalafellBot;
use commands::*;

use discord::model::{PublicChannel, ChannelType};
use discord::builders::EmbedBuilder;

use std::sync::Arc;

const USAGE: &'static str = "!join <voice channel name>";

pub struct JoinCommand {
  bot: Arc<LalafellBot>
}

impl JoinCommand {
  pub fn new(bot: Arc<LalafellBot>) -> JoinCommand {
    JoinCommand {
      bot: bot
    }
  }
}

impl HasBot for JoinCommand {
  fn bot(&self) -> Arc<LalafellBot> {
    self.bot.clone()
  }
}

impl<'a> PublicChannelCommand<'a> for JoinCommand {
  fn run(&self, _: &Message, channel: &PublicChannel, params: &[&str]) -> CommandResult<'a> {
    if params.is_empty() {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough parameters.")
          .description(USAGE))
        .wrap());
    }

    let chan_name = params.join(" ");

    let server_id = channel.server_id;
    let state_option = self.bot.state.read().unwrap();
    let state = state_option.as_ref().unwrap();
    let server = match state.servers().iter().find(|x| x.id == server_id) {
      Some(s) => s,
      None => {
        let err: error::Error = "could not find server for channel".into();
        return Err(err.into());
      }
    };

    let opt_channel = server.channels.iter()
      .find(|x| x.kind == ChannelType::Voice && x.name.to_lowercase() == chan_name.to_lowercase());
    let channel = match opt_channel {
      Some(s) => s,
      None => return Err(ExternalCommandFailure::default()
                .message(move |e: EmbedBuilder| e.
                  description(&format!("Could not find channel {}", chan_name)))
                .wrap())
    };

    {
      let mut connection = self.bot.connection.lock().unwrap();
      let mut voice = connection.voice(Some(server_id));
      voice.connect(channel.id);
    }

    Ok(CommandSuccess::default())
  }
}
<commit_msg>feat: add debug lines to join<commit_after>use LalafellBot;
use commands::*;

use discord::model::{PublicChannel, ChannelType};
use discord::builders::EmbedBuilder;

use std::sync::Arc;

const USAGE: &'static str = "!join <voice channel name>";

pub struct JoinCommand {
  bot: Arc<LalafellBot>
}

impl JoinCommand {
  pub fn new(bot: Arc<LalafellBot>) -> JoinCommand {
    JoinCommand {
      bot: bot
    }
  }
}

impl HasBot for JoinCommand {
  fn bot(&self) -> Arc<LalafellBot> {
    self.bot.clone()
  }
}

impl<'a> PublicChannelCommand<'a> for JoinCommand {
  fn run(&self, _: &Message, channel: &PublicChannel, params: &[&str]) -> CommandResult<'a> {
    debug!("!join");
    if params.is_empty() {
      debug!("empty params");
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough parameters.")
          .description(USAGE))
        .wrap());
    }

    let chan_name = params.join(" ");
    debug!("asked to join {}", chan_name);

    let server_id = channel.server_id;
    debug!("server_id: {}", server_id);
    debug!("locking state");
    let state_option = self.bot.state.read().unwrap();
    let state = state_option.as_ref().unwrap();
    let server = match state.servers().iter().find(|x| x.id == server_id) {
      Some(s) => s,
      None => {
        let err: error::Error = "could not find server for channel".into();
        return Err(err.into());
      }
    };
    debug!("found server for text channel");

    let opt_channel = server.channels.iter()
      .find(|x| x.kind == ChannelType::Voice && x.name.to_lowercase() == chan_name.to_lowercase());
    let channel = match opt_channel {
      Some(s) => s,
      None => return Err(ExternalCommandFailure::default()
                .message(move |e: EmbedBuilder| e.
                  description(&format!("Could not find channel {}", chan_name)))
                .wrap())
    };
    debug!("found voice channel");

    {
      debug!("locking connection");
      let mut connection = self.bot.connection.lock().unwrap();
      debug!("connection.voice");
      let mut voice = connection.voice(Some(server_id));
      // FIXME: deadlock if the bot doesn't have voice perms
      debug!("voice.connect");
      voice.connect(channel.id);
    }

    debug!("done");

    Ok(CommandSuccess::default())
  }
}
<|endoftext|>


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

// Test that a type which is covariant with respect to its region
// parameter yields an error when used in a contravariant way.
//
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.

// This is contravariant with respect to 'a, meaning that
// Contravariant<'foo> <: Contravariant<'static> because
// 'foo <= 'static
struct Contravariant<'a> {
    f: &'a int
}

fn use_<'short,'long>(c: Contravariant<'short>,
                      s: &'short int,
                      l: &'long int,
                      _where:Option<&'short &'long ()>) {

    // Test whether Contravariant<'short> <: Contravariant<'long>.  Since
    // 'short <= 'long, this would be true if the Contravariant type were
    // covariant with respect to its parameter 'a.

    let _: Contravariant<'long> = c; //~ ERROR mismatched types
    //~^ ERROR  cannot infer an appropriate lifetime
}

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

// Test that a type which is covariant with respect to its region
// parameter yields an error when used in a contravariant way.
//
// Note: see variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.

// This is contravariant with respect to 'a, meaning that
// Contravariant<'long> <: Contravariant<'short> iff
// 'short <= 'long
struct Contravariant<'a> {
    f: &'a int
}

fn use_<'short,'long>(c: Contravariant<'short>,
                      s: &'short int,
                      l: &'long int,
                      _where:Option<&'short &'long ()>) {

    // Test whether Contravariant<'short> <: Contravariant<'long>.  Since
    // 'short <= 'long, this would be true if the Contravariant type were
    // covariant with respect to its parameter 'a.

    let _: Contravariant<'long> = c; //~ ERROR mismatched types
    //~^ ERROR  cannot infer an appropriate lifetime
}

fn main() {}
<|endoftext|>


<commit_before>#![feature(const_generics, const_evaluatable_checked)]
#![allow(incomplete_features)]

// library portion of testing that `impl Trait<{ expr }>` doesnt ice because of a `DefKind::TyParam` parent
pub fn foo<const N: usize>(foo: impl Into<[(); N + 1]>) {
    foo.into();
}
<commit_msg>*sprinkles some dust everywhere*<commit_after>#![feature(const_generics, const_evaluatable_checked)]
#![allow(incomplete_features)]

// library portion of testing that `impl Trait<{ expr }>` doesnt
// ice because of a `DefKind::TyParam` parent
pub fn foo<const N: usize>(foo: impl Into<[(); N + 1]>) {
    foo.into();
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::path::{Component, Path};

use crate::prelude::*;

use rustc_span::FileName;

use cranelift_codegen::binemit::CodeOffset;

use gimli::write::{
    Address, AttributeValue, FileId, LineProgram, LineString, LineStringTable, UnitEntryId,
};

// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
    let mut iter = path.components();
    let file_name = match iter.next_back() {
        Some(Component::Normal(p)) => p,
        component => {
            panic!("Path component {:?} of path {} is an invalid filename", component, path.display());
        }
    };
    let parent = iter.as_path();
    (parent, file_name)
}

// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
    #[cfg(unix)] {
        use std::os::unix::ffi::OsStrExt;
        return path.as_bytes();
    }
    #[cfg(not(unix))] {
        return path.to_str().unwrap().as_bytes();
    }
}

fn line_program_add_file(
    line_program: &mut LineProgram,
    line_strings: &mut LineStringTable,
    file: &FileName,
) -> FileId {
    match file {
        FileName::Real(path) => {
            let (dir_path, file_name) = split_path_dir_and_file(path);
            let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
            let file_name = osstr_as_utf8_bytes(file_name);

            let dir_id = if !dir_name.is_empty() {
                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
                line_program.add_directory(dir_name)
            } else {
                line_program.default_directory()
            };
            let file_name = LineString::new(
                file_name,
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(file_name, dir_id, None)
        }
        // FIXME give more appropriate file names
        _ => {
            let dir_id = line_program.default_directory();
            let dummy_file_name = LineString::new(
                file.to_string().into_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(dummy_file_name, dir_id, None)
        }
    }
}

impl<'tcx> DebugContext<'tcx> {
    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());

        let file_id = line_program_add_file(
            &mut self.dwarf.unit.line_program,
            &mut self.dwarf.line_strings,
            &loc.file.name,
        );

        let entry = self.dwarf.unit.get_mut(entry_id);

        entry.set(
            gimli::DW_AT_decl_file,
            AttributeValue::FileIndex(Some(file_id)),
        );
        entry.set(
            gimli::DW_AT_decl_line,
            AttributeValue::Udata(loc.line as u64),
        );
        // FIXME: probably omit this
        entry.set(
            gimli::DW_AT_decl_column,
            AttributeValue::Udata(loc.col.to_usize() as u64),
        );
    }
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(super) fn create_debug_lines(
        &mut self,
        context: &Context,
        isa: &dyn cranelift_codegen::isa::TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
    ) -> CodeOffset {
        let tcx = self.debug_context.tcx;

        let line_program = &mut self.debug_context.dwarf.unit.line_program;

        line_program.begin_sequence(Some(Address::Symbol {
            symbol: self.symbol,
            addend: 0,
        }));

        let encinfo = isa.encoding_info();
        let func = &context.func;
        let mut blocks = func.layout.blocks().collect::<Vec<_>>();
        blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase

        let line_strings = &mut self.debug_context.dwarf.line_strings;
        let mut last_file = None;
        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
            let loc = tcx.sess.source_map().lookup_char_pos(span.lo());

            // line_program_add_file is very slow.
            // Optimize for the common case of the current file not being changed.
            let current_file_changed = if let Some(last_file) = &mut last_file {
                // If the allocations are not equal, then the files may still be equal, but that
                // is not a problem, as this is just an optimization.
                !Lrc::ptr_eq(last_file, &loc.file)
            } else {
                true
            };
            if current_file_changed {
                let file_id = line_program_add_file(line_program, line_strings, &loc.file.name);
                line_program.row().file = file_id;
                last_file = Some(loc.file.clone());
            }

            line_program.row().line = loc.line as u64;
            line_program.row().column = loc.col.to_u32() as u64 + 1;
            line_program.generate_row();
        };

        let mut end = 0;
        for block in blocks {
            for (offset, inst, size) in func.inst_offsets(block, &encinfo) {
                let srcloc = func.srclocs[inst];
                line_program.row().address_offset = offset as u64;
                if !srcloc.is_default() {
                    let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
                    create_row_for_span(line_program, source_info.span);
                } else {
                    create_row_for_span(line_program, self.mir.span);
                }
                end = offset + size;
            }
        }

        line_program.end_sequence(end as u64);

        let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
        entry.set(
            gimli::DW_AT_low_pc,
            AttributeValue::Address(Address::Symbol {
                symbol: self.symbol,
                addend: 0,
            }),
        );
        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));

        self.debug_context
            .emit_location(self.entry_id, self.mir.span);

        end
    }
}
<commit_msg>Dont single step into macros<commit_after>use std::ffi::OsStr;
use std::path::{Component, Path};

use crate::prelude::*;

use rustc_span::FileName;

use cranelift_codegen::binemit::CodeOffset;

use gimli::write::{
    Address, AttributeValue, FileId, LineProgram, LineString, LineStringTable, UnitEntryId,
};

// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
    let mut iter = path.components();
    let file_name = match iter.next_back() {
        Some(Component::Normal(p)) => p,
        component => {
            panic!("Path component {:?} of path {} is an invalid filename", component, path.display());
        }
    };
    let parent = iter.as_path();
    (parent, file_name)
}

// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
    #[cfg(unix)] {
        use std::os::unix::ffi::OsStrExt;
        return path.as_bytes();
    }
    #[cfg(not(unix))] {
        return path.to_str().unwrap().as_bytes();
    }
}

fn line_program_add_file(
    line_program: &mut LineProgram,
    line_strings: &mut LineStringTable,
    file: &FileName,
) -> FileId {
    match file {
        FileName::Real(path) => {
            let (dir_path, file_name) = split_path_dir_and_file(path);
            let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
            let file_name = osstr_as_utf8_bytes(file_name);

            let dir_id = if !dir_name.is_empty() {
                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
                line_program.add_directory(dir_name)
            } else {
                line_program.default_directory()
            };
            let file_name = LineString::new(
                file_name,
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(file_name, dir_id, None)
        }
        // FIXME give more appropriate file names
        _ => {
            let dir_id = line_program.default_directory();
            let dummy_file_name = LineString::new(
                file.to_string().into_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(dummy_file_name, dir_id, None)
        }
    }
}

impl<'tcx> DebugContext<'tcx> {
    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());

        let file_id = line_program_add_file(
            &mut self.dwarf.unit.line_program,
            &mut self.dwarf.line_strings,
            &loc.file.name,
        );

        let entry = self.dwarf.unit.get_mut(entry_id);

        entry.set(
            gimli::DW_AT_decl_file,
            AttributeValue::FileIndex(Some(file_id)),
        );
        entry.set(
            gimli::DW_AT_decl_line,
            AttributeValue::Udata(loc.line as u64),
        );
        // FIXME: probably omit this
        entry.set(
            gimli::DW_AT_decl_column,
            AttributeValue::Udata(loc.col.to_usize() as u64),
        );
    }
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(super) fn create_debug_lines(
        &mut self,
        context: &Context,
        isa: &dyn cranelift_codegen::isa::TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
    ) -> CodeOffset {
        let tcx = self.debug_context.tcx;

        let line_program = &mut self.debug_context.dwarf.unit.line_program;

        line_program.begin_sequence(Some(Address::Symbol {
            symbol: self.symbol,
            addend: 0,
        }));

        let encinfo = isa.encoding_info();
        let func = &context.func;
        let mut blocks = func.layout.blocks().collect::<Vec<_>>();
        blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase

        let line_strings = &mut self.debug_context.dwarf.line_strings;
        let function_span = self.mir.span;
        let mut last_file = None;
        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
            // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
            // In order to have a good line stepping behavior in debugger, we overwrite debug
            // locations of macro expansions with that of the outermost expansion site
            // (unless the crate is being compiled with `-Z debug-macros`).
            let span = if !span.from_expansion() ||
                tcx.sess.opts.debugging_opts.debug_macros {
                span
            } else {
                // Walk up the macro expansion chain until we reach a non-expanded span.
                // We also stop at the function body level because no line stepping can occur
                // at the level above that.
                rustc_span::hygiene::walk_chain(span, function_span.ctxt())
            };

            let loc = tcx.sess.source_map().lookup_char_pos(span.lo());

            // line_program_add_file is very slow.
            // Optimize for the common case of the current file not being changed.
            let current_file_changed = if let Some(last_file) = &mut last_file {
                // If the allocations are not equal, then the files may still be equal, but that
                // is not a problem, as this is just an optimization.
                !Lrc::ptr_eq(last_file, &loc.file)
            } else {
                true
            };
            if current_file_changed {
                let file_id = line_program_add_file(line_program, line_strings, &loc.file.name);
                line_program.row().file = file_id;
                last_file = Some(loc.file.clone());
            }

            line_program.row().line = loc.line as u64;
            line_program.row().column = loc.col.to_u32() as u64 + 1;
            line_program.generate_row();
        };

        let mut end = 0;
        for block in blocks {
            for (offset, inst, size) in func.inst_offsets(block, &encinfo) {
                let srcloc = func.srclocs[inst];
                line_program.row().address_offset = offset as u64;
                if !srcloc.is_default() {
                    let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
                    create_row_for_span(line_program, source_info.span);
                } else {
                    create_row_for_span(line_program, self.mir.span);
                }
                end = offset + size;
            }
        }

        line_program.end_sequence(end as u64);

        let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
        entry.set(
            gimli::DW_AT_low_pc,
            AttributeValue::Address(Address::Symbol {
                symbol: self.symbol,
                addend: 0,
            }),
        );
        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));

        self.debug_context
            .emit_location(self.entry_id, self.mir.span);

        end
    }
}
<|endoftext|>