<commit_before>use analysis::Analysis;
use clang;
use entity::{Argument, Entity, EntityType, Enum, Function};
use error::*;
use python_parser::ast::{CompoundStatement, Expression, Statement};
use python_parser::{file_input, make_strspan};
use std::fs::File;
use std::io::Read;

pub trait LanguageType: Default {
    fn file_types() -> &'static [&'static str];
    fn extract_functions<T: LanguageType>(analysis: &Analysis<T>) -> Result<()>;
}

/// The file extensions which should be checked for C project analysis.
static C_FILE_EXTENSIONS: &[&str] = &["c", "h"];

#[derive(Default, Clone, Debug)]
struct CFamily;

impl CFamily {
    fn format_arguments(arguments: &[clang::Entity]) -> Result<Vec<Argument>> {
        let mut args = Vec::new();

        for argument in arguments {
            args.push(Argument::new(
                argument.get_display_name().unwrap_or(String::new()),
                Some(
                    argument
                        .get_type()
                        .ok_or_else(|| "Argument type can not be parsed from signature.")?
                        .get_display_name(),
                ),
            ));
        }

        Ok(args)
    }

    fn analyse_clang_function_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        if let Some(entity_name) = entity.get_name() {
            let mut function = Function::new(entity_name);

            // Set return type.
            if let Some(return_type) = entity.get_type() {
                function.set_return_type(
                    return_type.get_display_name().as_str(),
                )?;
            }

            // Set arguments vector.
            if let Some(arguments) = entity.get_arguments() {
                function.set_arguments(&Self::format_arguments(&arguments)?);
            }

            // Set description.
            if let Some(description) = entity.get_comment() {
                function.set_description(description.as_str());
            }

            return Ok(Some(EntityType::Function(function)));
        }

        Ok(None)
    }

    fn analyse_clang_enum_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        if let Some(entity_name) = entity.get_name() {
            let enumeration = Enum::new(entity_name);

            return Ok(Some(EntityType::Enum(enumeration)));
        }

        Ok(None)
    }

    fn analyse_clang_generic_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        if let Some(entity_name) = entity.get_name() {
            let entity = Entity::new(entity_name);

            return Ok(Some(EntityType::Entity(entity)));
        }

        Ok(None)
    }
}

#[derive(Default, Clone, Debug)]
pub struct C;

impl C {
    fn analyse_clang_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        let entity_kind = entity.get_kind();

        // Search for functions outside the system headers
        if !entity.is_in_system_header() {
            match &entity_kind {
                clang::EntityKind::FunctionDecl => {
                    return CFamily::analyse_clang_function_entity(entity);
                }
                clang::EntityKind::EnumDecl => {
                    return CFamily::analyse_clang_enum_entity(entity);
                }
                _ => {}
            }

            return Ok(None);
        }

        Ok(None)
    }
}

impl LanguageType for C {
    fn file_types() -> &'static [&'static str] {
        C_FILE_EXTENSIONS
    }

    fn extract_functions<C: LanguageType>(analysis: &Analysis<C>) -> Result<()> {
        match clang::Clang::new() {
            Ok(clang) => {
                let clang_index = clang::Index::new(&clang, false, false);
                for project_file in analysis.project_files().iter() {
                    if let EntityType::Entity(mut index) = EntityType::Entity(Entity::new("")) {
                        let parsed_path = &clang_index.parser(&project_file.path).parse()?;
                        let clang_entity = parsed_path.get_entity();

                        // Iterate through the child entities of the current entity
                        for child in clang_entity.get_children() {
                            if let Ok(Some(entity)) = Self::analyse_clang_entity(&child) {
                                index.add_entity::<Entity>(entity);
                            }
                        }

                        println!("{:#?}", index);
                        project_file.add_entity(index);
                    }
                }
            }
            Err(e) => bail!(e),
        }

        Ok(())
    }
}

/// The file extensions which should be checked for C++ project analysis.
static CPP_FILE_EXTENSIONS: &[&str] = &["cpp", "hpp"];

#[derive(Default, Clone, Debug)]
pub struct Cpp;

impl Cpp {
    fn analyse_clang_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        let entity_kind = entity.get_kind();

        // Search for functions outside the system headers
        if !entity.is_in_system_header() {
            match &entity_kind {
                clang::EntityKind::Constructor |
                clang::EntityKind::Destructor |
                clang::EntityKind::Method |
                clang::EntityKind::FunctionDecl => {
                    return CFamily::analyse_clang_function_entity(entity);
                }
                clang::EntityKind::EnumDecl => {
                    return CFamily::analyse_clang_enum_entity(entity);
                }
                clang::EntityKind::ClassDecl |
                clang::EntityKind::Namespace => {
                    return CFamily::analyse_clang_generic_entity(entity);
                }
                _ => {}
            }

            return Ok(None);
        }

        Ok(None)
    }

    fn analyse_clang_entity_tree(parent: &mut Entity, clang_entity: &clang::Entity) -> Result<()> {
        // Iterate through the child entities of the current entity
        for child in clang_entity.get_children() {
            if let Ok(Some(entity)) = Self::analyse_clang_entity(&child) {
                if let Some(added_entity) = parent.add_entity(entity) {
                    Self::analyse_clang_entity_tree(added_entity, &child)?;
                }
            }
        }

        Ok(())
    }
}

impl LanguageType for Cpp {
    fn file_types() -> &'static [&'static str] {
        CPP_FILE_EXTENSIONS
    }

    fn extract_functions<Cpp: LanguageType>(analysis: &Analysis<Cpp>) -> Result<()> {
        match clang::Clang::new() {
            Ok(clang) => {
                let clang_index = clang::Index::new(&clang, false, false);
                for project_file in analysis.project_files().iter() {
                    if let EntityType::Entity(mut index) = EntityType::Entity(Entity::new("")) {
                        let parsed_path = &clang_index.parser(&project_file.path).parse()?;
                        let clang_entity = parsed_path.get_entity();

                        Self::analyse_clang_entity_tree(&mut index, &clang_entity)?;

                        println!("{:#?}", index);
                        project_file.add_entity(index);
                    }
                }
            }
            Err(e) => bail!(e),
        }

        Ok(())
    }
}

/// The file extensions which should be checked for Python project analysis.
static PYTHON_FILE_EXTENSIONS: &[&str] = &["py"];

#[derive(Default, Clone, Debug)]
pub struct Python;

impl Python {
    fn extract_function_doc(function: &mut Function, statement: &Statement) {
        if let Statement::Assignment(ent_v, _) = statement {
            for ent in ent_v.iter() {
                if let Expression::String(expr_v) = ent {
                    for expr in expr_v.iter() {
                        function.set_description(&expr.content.to_string_lossy());
                    }
                }
            }
        }
    }

    fn analyse_statement(entity: &mut Entity, statement: &Statement) -> Result<()> {
        if let Statement::Compound(ent_box) = statement {
            match Box::leak((*ent_box).clone()) {
                // Statement is a statement definition
                CompoundStatement::Funcdef(expr) => {
                    let mut function: Function = Function::new(expr.name.as_str());

                    // Split arguments and add them to the function
                    let mut arguments: Vec<Argument> = Vec::new();
                    for arg in &expr.parameters.positional_args {
                        arguments.push(Argument::new(arg.0.as_str(), None));
                    }
                    function.set_arguments(&arguments);

                    if let Some(mut function_inst) =
                        entity.add_entity(EntityType::Function(function))
                    {
                        Self::extract_function_doc(&mut function_inst, &expr.code[0]);
                    }
                }

                // Statement is a class definition
                CompoundStatement::Classdef(expr) => {
                    if let Some(ref mut class_entity) =
                        entity.add_entity(EntityType::Entity(Entity::new(expr.name.as_str())))
                    {
                        for code in &expr.code {
                            Self::analyse_statement(class_entity, &code)?;
                        }
                    }
                }
                _ => {}
            }
        }

        Ok(())
    }
}

impl LanguageType for Python {
    fn file_types() -> &'static [&'static str] {
        PYTHON_FILE_EXTENSIONS
    }

    fn extract_functions<Python: LanguageType>(analysis: &Analysis<Python>) -> Result<()> {
        for project_file in analysis.project_files().iter() {
            // Parse file to string
            let mut file = File::open(&project_file.path)?;
            let mut content = String::new();
            file.read_to_string(&mut content)?;

            if let EntityType::Entity(mut index) = EntityType::Entity(Entity::new("")) {
                match file_input(make_strspan(content.as_str())) {
                    Ok(ast) => {
                        for entity in ast.1.iter() {
                            Self::analyse_statement(&mut index, entity)?;
                        }
                    }
                    Err(_) => bail!("Unable to create python AST."),
                }
                println!("{:#?}", index);
                project_file.add_entity(index);
            }
        }

        Ok(())
    }
}

#[test]
fn new_c() {
    // Given
    let analysis: Analysis<C> = Analysis::new();

    // Then
    assert_eq!(analysis.file_types, C_FILE_EXTENSIONS);
    assert_eq!(analysis.project_files().len(), 0);
}

#[test]
fn new_python() {
    // Given
    let analysis: Analysis<Python> = Analysis::new();

    // Then
    assert_eq!(analysis.file_types, PYTHON_FILE_EXTENSIONS);
    assert_eq!(analysis.project_files().len(), 0);
}
<commit_msg>Add file_types tests<commit_after>use analysis::Analysis;
use clang;
use entity::{Argument, Entity, EntityType, Enum, Function};
use error::*;
use python_parser::ast::{CompoundStatement, Expression, Statement};
use python_parser::{file_input, make_strspan};
use std::fs::File;
use std::io::Read;

pub trait LanguageType: Default {
    fn file_types() -> &'static [&'static str];
    fn extract_functions<T: LanguageType>(analysis: &Analysis<T>) -> Result<()>;
}

/// The file extensions which should be checked for C project analysis.
static C_FILE_EXTENSIONS: &[&str] = &["c", "h"];

#[derive(Default, Clone, Debug)]
struct CFamily;

impl CFamily {
    fn format_arguments(arguments: &[clang::Entity]) -> Result<Vec<Argument>> {
        let mut args = Vec::new();

        for argument in arguments {
            args.push(Argument::new(
                argument.get_display_name().unwrap_or(String::new()),
                Some(
                    argument
                        .get_type()
                        .ok_or_else(|| "Argument type can not be parsed from signature.")?
                        .get_display_name(),
                ),
            ));
        }

        Ok(args)
    }

    fn analyse_clang_function_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        if let Some(entity_name) = entity.get_name() {
            let mut function = Function::new(entity_name);

            // Set return type.
            if let Some(return_type) = entity.get_type() {
                function.set_return_type(
                    return_type.get_display_name().as_str(),
                )?;
            }

            // Set arguments vector.
            if let Some(arguments) = entity.get_arguments() {
                function.set_arguments(&Self::format_arguments(&arguments)?);
            }

            // Set description.
            if let Some(description) = entity.get_comment() {
                function.set_description(description.as_str());
            }

            return Ok(Some(EntityType::Function(function)));
        }

        Ok(None)
    }

    fn analyse_clang_enum_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        if let Some(entity_name) = entity.get_name() {
            let enumeration = Enum::new(entity_name);

            return Ok(Some(EntityType::Enum(enumeration)));
        }

        Ok(None)
    }

    fn analyse_clang_generic_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        if let Some(entity_name) = entity.get_name() {
            let entity = Entity::new(entity_name);

            return Ok(Some(EntityType::Entity(entity)));
        }

        Ok(None)
    }
}

#[derive(Default, Clone, Debug)]
pub struct C;

impl C {
    fn analyse_clang_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        let entity_kind = entity.get_kind();

        // Search for functions outside the system headers
        if !entity.is_in_system_header() {
            match &entity_kind {
                clang::EntityKind::FunctionDecl => {
                    return CFamily::analyse_clang_function_entity(entity);
                }
                clang::EntityKind::EnumDecl => {
                    return CFamily::analyse_clang_enum_entity(entity);
                }
                _ => {}
            }

            return Ok(None);
        }

        Ok(None)
    }
}

impl LanguageType for C {
    fn file_types() -> &'static [&'static str] {
        C_FILE_EXTENSIONS
    }

    fn extract_functions<C: LanguageType>(analysis: &Analysis<C>) -> Result<()> {
        match clang::Clang::new() {
            Ok(clang) => {
                let clang_index = clang::Index::new(&clang, false, false);
                for project_file in analysis.project_files().iter() {
                    if let EntityType::Entity(mut index) = EntityType::Entity(Entity::new("")) {
                        let parsed_path = &clang_index.parser(&project_file.path).parse()?;
                        let clang_entity = parsed_path.get_entity();

                        // Iterate through the child entities of the current entity
                        for child in clang_entity.get_children() {
                            if let Ok(Some(entity)) = Self::analyse_clang_entity(&child) {
                                index.add_entity::<Entity>(entity);
                            }
                        }

                        println!("{:#?}", index);
                        project_file.add_entity(index);
                    }
                }
            }
            Err(e) => bail!(e),
        }

        Ok(())
    }
}

/// The file extensions which should be checked for C++ project analysis.
static CPP_FILE_EXTENSIONS: &[&str] = &["cpp", "hpp"];

#[derive(Default, Clone, Debug)]
pub struct Cpp;

impl Cpp {
    fn analyse_clang_entity(entity: &clang::Entity) -> Result<Option<EntityType>> {
        let entity_kind = entity.get_kind();

        // Search for functions outside the system headers
        if !entity.is_in_system_header() {
            match &entity_kind {
                clang::EntityKind::Constructor |
                clang::EntityKind::Destructor |
                clang::EntityKind::Method |
                clang::EntityKind::FunctionDecl => {
                    return CFamily::analyse_clang_function_entity(entity);
                }
                clang::EntityKind::EnumDecl => {
                    return CFamily::analyse_clang_enum_entity(entity);
                }
                clang::EntityKind::ClassDecl |
                clang::EntityKind::Namespace => {
                    return CFamily::analyse_clang_generic_entity(entity);
                }
                _ => {}
            }

            return Ok(None);
        }

        Ok(None)
    }

    fn analyse_clang_entity_tree(parent: &mut Entity, clang_entity: &clang::Entity) -> Result<()> {
        // Iterate through the child entities of the current entity
        for child in clang_entity.get_children() {
            if let Ok(Some(entity)) = Self::analyse_clang_entity(&child) {
                if let Some(added_entity) = parent.add_entity(entity) {
                    Self::analyse_clang_entity_tree(added_entity, &child)?;
                }
            }
        }

        Ok(())
    }
}

impl LanguageType for Cpp {
    fn file_types() -> &'static [&'static str] {
        CPP_FILE_EXTENSIONS
    }

    fn extract_functions<Cpp: LanguageType>(analysis: &Analysis<Cpp>) -> Result<()> {
        match clang::Clang::new() {
            Ok(clang) => {
                let clang_index = clang::Index::new(&clang, false, false);
                for project_file in analysis.project_files().iter() {
                    if let EntityType::Entity(mut index) = EntityType::Entity(Entity::new("")) {
                        let parsed_path = &clang_index.parser(&project_file.path).parse()?;
                        let clang_entity = parsed_path.get_entity();

                        Self::analyse_clang_entity_tree(&mut index, &clang_entity)?;

                        println!("{:#?}", index);
                        project_file.add_entity(index);
                    }
                }
            }
            Err(e) => bail!(e),
        }

        Ok(())
    }
}

/// The file extensions which should be checked for Python project analysis.
static PYTHON_FILE_EXTENSIONS: &[&str] = &["py"];

#[derive(Default, Clone, Debug)]
pub struct Python;

impl Python {
    fn extract_function_doc(function: &mut Function, statement: &Statement) {
        if let Statement::Assignment(ent_v, _) = statement {
            for ent in ent_v.iter() {
                if let Expression::String(expr_v) = ent {
                    for expr in expr_v.iter() {
                        function.set_description(&expr.content.to_string_lossy());
                    }
                }
            }
        }
    }

    fn analyse_statement(entity: &mut Entity, statement: &Statement) -> Result<()> {
        if let Statement::Compound(ent_box) = statement {
            match Box::leak((*ent_box).clone()) {
                // Statement is a statement definition
                CompoundStatement::Funcdef(expr) => {
                    let mut function: Function = Function::new(expr.name.as_str());

                    // Split arguments and add them to the function
                    let mut arguments: Vec<Argument> = Vec::new();
                    for arg in &expr.parameters.positional_args {
                        arguments.push(Argument::new(arg.0.as_str(), None));
                    }
                    function.set_arguments(&arguments);

                    if let Some(mut function_inst) =
                        entity.add_entity(EntityType::Function(function))
                    {
                        Self::extract_function_doc(&mut function_inst, &expr.code[0]);
                    }
                }

                // Statement is a class definition
                CompoundStatement::Classdef(expr) => {
                    if let Some(ref mut class_entity) =
                        entity.add_entity(EntityType::Entity(Entity::new(expr.name.as_str())))
                    {
                        for code in &expr.code {
                            Self::analyse_statement(class_entity, &code)?;
                        }
                    }
                }
                _ => {}
            }
        }

        Ok(())
    }
}

impl LanguageType for Python {
    fn file_types() -> &'static [&'static str] {
        PYTHON_FILE_EXTENSIONS
    }

    fn extract_functions<Python: LanguageType>(analysis: &Analysis<Python>) -> Result<()> {
        for project_file in analysis.project_files().iter() {
            // Parse file to string
            let mut file = File::open(&project_file.path)?;
            let mut content = String::new();
            file.read_to_string(&mut content)?;

            if let EntityType::Entity(mut index) = EntityType::Entity(Entity::new("")) {
                match file_input(make_strspan(content.as_str())) {
                    Ok(ast) => {
                        for entity in ast.1.iter() {
                            Self::analyse_statement(&mut index, entity)?;
                        }
                    }
                    Err(_) => bail!("Unable to create python AST."),
                }
                println!("{:#?}", index);
                project_file.add_entity(index);
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod c {
    use super::{Analysis, C, C_FILE_EXTENSIONS, LanguageType};

    #[test]
    fn new() {
        let analysis: Analysis<C> = Analysis::new();

        assert_eq!(analysis.file_types, C_FILE_EXTENSIONS);
        assert_eq!(analysis.project_files().len(), 0);
    }

    #[test]
    fn file_types() {
        assert_eq!(C::file_types(), C_FILE_EXTENSIONS);
    }
}

#[cfg(test)]
mod cpp {
    use super::{Analysis, Cpp, CPP_FILE_EXTENSIONS, LanguageType};

    #[test]
    fn new() {
        let analysis: Analysis<Cpp> = Analysis::new();

        assert_eq!(analysis.file_types, CPP_FILE_EXTENSIONS);
        assert_eq!(analysis.project_files().len(), 0);
    }

    #[test]
    fn file_types() {
        assert_eq!(Cpp::file_types(), CPP_FILE_EXTENSIONS);
    }
}

#[cfg(test)]
mod python {
    use super::{Analysis, LanguageType, Python, PYTHON_FILE_EXTENSIONS};

    #[test]
    fn new() {
        let analysis: Analysis<Python> = Analysis::new();

        assert_eq!(analysis.file_types, PYTHON_FILE_EXTENSIONS);
        assert_eq!(analysis.project_files().len(), 0);
    }

    #[test]
    fn file_types() {
        assert_eq!(Python::file_types(), PYTHON_FILE_EXTENSIONS);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use std::mem;
use std::default::Default;

use token::Token;
use token::Data;
use logger::Logger;

pub fn traverse_token<F1, F2, R>(token: &Token, f: &F1, add: &F2) -> R
    where F1: Fn(&str) -> R,
          R: Default,
          F2: Fn(R, R) -> R
{
    match token {
        &Token::Str(ref s) => f(s),

        &Token::Rule
            | &Token::SoftBreak
            | &Token::HardBreak
            => f("\n"),

        &Token::Image(..)
            | &Token::StandaloneImage(..)
            | &Token::Footnote(..)
            | &Token::Table(..)
            | &Token::TableHead(..)
            | &Token::TableRow(..)
            | &Token::TableCell(..)
            => f(""),

        _ => traverse_vec(token.inner().unwrap(), f, add),
    }
}

/// Traverse a vector of tokens
#[doc(hidden)]
    pub fn traverse_vec<F1, F2, R>(tokens: &[Token], f:&F1, add: &F2) -> R
    where F1: Fn(&str) -> R,
          F2: Fn(R, R) -> R,
          R: Default
{
        tokens.iter()
            .map(|t| traverse_token(t, f, add))
            .fold(R::default(), |r1, r2| add(r1, r2))
    }

/// Returns the content of an AST as raw text, without any formatting
/// Useful for tools like grammar checks
pub fn view_as_text(tokens: &[Token]) -> String {
        traverse_vec(tokens,
                     &|s| s.to_owned(),
                     &|s1, s2| s1 + &s2)
    }

pub fn count_length(tokens: &[Token]) -> usize {
    traverse_vec(tokens,
                 &|s| s.chars().count(),
                 &|s1, s2| s1 + s2)
}

/// Insert an annotation at begin and end pos begin+len in the text_view
#[doc(hidden)]
pub fn insert_annotation(tokens: &mut Vec<Token>, annotation: &Data, pos: usize, length: usize) -> Option<usize> {
    let mut pos = pos;
    let mut found_left = None;
    let mut found_right = None;
    for i in 0..tokens.len() {
        let recurse  = match tokens[i] {
            Token::Str(ref s) => {
                let len = s.chars().count();
                if pos < len || (pos == len && found_left.is_some()) {
                    // We found the first element already, so now it's the right
                    if found_left.is_some() {
                        found_right = Some((i, pos));
                        break;
                    }
                    found_left = Some((i, pos));
                    pos += length;
                    if pos <= len {
                        found_right = Some((i, pos));
                        break;
                    }
                }
                pos = pos - len;
                false
            },

            Token::Rule
                | Token::SoftBreak
                | Token::HardBreak
                => {
                    if pos < 1 {
                        if found_left.is_some() {
                            found_right = Some((i, pos));
                            break;
                        }
                        found_left = Some((i, pos));
                        pos += length;
                        if pos <= 1 {
                            found_right = Some((i, pos));
                            break;
                        }
                    }
                    pos -= 1;
                    false
                },

            _ => {
                if let Some(ref inner) = tokens[i].inner() {
                    let len = count_length(inner);
                    // Only recurse if the two is in this subtree
                    if pos < len {
                        if found_left.is_none() {
                            true
                        } else {
                            Logger::display_warning("ignored annotation as it wasn't compatible with the Markdown structure");
                            return None;
                        }
                    } else {
                        pos -= len;
                        false
                    }
                } else {
                    false
                }

            },
        };

        // Moved out of the match 'thanks' to borrowcheck
        if recurse {
            if let Some(ref mut inner) = tokens[i].inner_mut() {
                if let Some(new_pos) = insert_annotation(inner, annotation, pos, length) {
                    pos = new_pos;
                } else {
                    return None;
                }
            }
        }
    }

    if let (Some((i, pos_left)), Some((j, pos_right))) = (found_left, found_right) {
        let pos_right = pos_right;
        let mut vec = vec!();

        // Beginning token: keep the left part in the str, put the right one in our vec
        if !tokens[i].is_str() || pos_left == 0 {
            // do nothing
        } else {
            let old_token = mem::replace(&mut tokens[i], Token::Str(String::new()));
            if let Token::Str(old_str) = old_token {
                let mut chars_left:Vec<char> = old_str.chars().collect();
                let mut chars_right = chars_left.split_off(pos_left);

                let str_left:String = chars_left.into_iter().collect();
                tokens[i] = Token::Str(str_left);

                if i == j { // i and j are in same str, so split again
                    if length != chars_right.len() {
                        let inline_token = chars_right.split_off(length);
                        let inline_token = Token::Str(inline_token.into_iter().collect());
                        if pos_left == 0 {
                            tokens.insert(i, inline_token)
                        } else if i == tokens.len() {
                            tokens.push(inline_token);
                        } else {
                            tokens.insert(i+1, inline_token);
                        }
                    }
                    let annot = Token::Annotation(annotation.clone(), vec!(Token::Str(chars_right.into_iter().collect())));
                    if pos_left == 0 {
                        tokens.insert(i, annot)
                    } else if i == tokens.len() {
                        tokens.push(annot);
                    } else {
                        tokens.insert(i+1, annot);
                    }
                    return None;
                }

                let str_right:String = chars_right.into_iter().collect();
                vec.push(Token::Str(str_right));
            } else {
                unreachable!();
            }
        }

        // Middle tokens: remove them entirely and put them in our vec
        for _ in i+1..j {
            vec.push(tokens.remove(i+1));
        }

        // End token: keep the right part in the str, put the left one in our vec
        // j is now i + 1 because all tokens in between have been removed
        // unless j was equal to i to begin with
        let j = if i == j || i >= tokens.len() - 1 {
            i
        } else {
            i + 1
        };

        if !tokens[j].is_str() {
            // do nothing
        } else {
            let count = if let Token::Str(ref s) = tokens[j] {
                s.chars().count()
            } else {
                unreachable!()
            };
            if count != pos_right {
                let old_token = mem::replace(&mut tokens[j], Token::Rule);
                if let Token::Str(old_str) = old_token {
                    let mut chars_left:Vec<char> = old_str.chars().collect();
                    let chars_right = chars_left.split_off(pos_right);
                    let str_left:String = chars_left.into_iter().collect();
                    let str_right:String = chars_right.into_iter().collect();
                    tokens[j] = Token::Str(str_right);
                    // todo: if only one token, maybe concat the strings
                    vec.push(Token::Str(str_left));
                } else {
                    unreachable!();
                }
            }
        }
        let new_token = Token::Annotation(annotation.clone(), vec);
        if pos_left == 0 {
            tokens.insert(i, new_token);
        }  else if i >= tokens.len() - 1 {
            tokens.push(new_token);
        } else {
            tokens.insert(i+1, new_token);
        }
        return None;
    } else {
        if found_left.is_none() && found_right.is_none() {
            return Some(pos);
        } else {
            Logger::display_warning("ignored annotation as it wasn't compatible with the Markdown structure");
            return None;
        }
    }
}

#[test]
fn test_text_view() {
    let ast = vec!(Token::Str("123".to_owned()),
                   Token::Emphasis(vec!(Token::Str("456".to_owned()))),
                   Token::Str("789".to_owned()));
    assert_eq!(view_as_text(&ast), "123456789");
}

// #[test]
// fn test_text_insert() {
//     let mut ast = vec!(Token::Str("123".to_owned()),
//                        Token::Emphasis(vec!(Token::Str("456".to_owned()))),
//                        Token::Str("789".to_owned()));
//     insert_at(&mut ast, "!!!", 5);
//     let expected = vec!(Token::Str("123".to_owned()),
//                         Token::Emphasis(vec!(Token::Str("45".to_owned()),
//                                              Token::Comment("!!!".to_owned()),
//                                              Token::Str("6".to_owned()))),
//                         Token::Str("789".to_owned()));
//     assert_eq!(expected, ast);
// }
<commit_msg>Fix indent<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use std::mem;
use std::default::Default;

use token::Token;
use token::Data;
use logger::Logger;

pub fn traverse_token<F1, F2, R>(token: &Token, f: &F1, add: &F2) -> R
    where F1: Fn(&str) -> R,
          R: Default,
          F2: Fn(R, R) -> R
{
    match token {
        &Token::Str(ref s) => f(s),

        &Token::Rule
            | &Token::SoftBreak
            | &Token::HardBreak
            => f("\n"),

        &Token::Image(..)
            | &Token::StandaloneImage(..)
            | &Token::Footnote(..)
            | &Token::Table(..)
            | &Token::TableHead(..)
            | &Token::TableRow(..)
            | &Token::TableCell(..)
            => f(""),

        _ => traverse_vec(token.inner().unwrap(), f, add),
    }
}

/// Traverse a vector of tokens
#[doc(hidden)]
pub fn traverse_vec<F1, F2, R>(tokens: &[Token], f:&F1, add: &F2) -> R
    where F1: Fn(&str) -> R,
          F2: Fn(R, R) -> R,
          R: Default
{
    tokens.iter()
        .map(|t| traverse_token(t, f, add))
        .fold(R::default(), |r1, r2| add(r1, r2))
}

/// Returns the content of an AST as raw text, without any formatting
/// Useful for tools like grammar checks
pub fn view_as_text(tokens: &[Token]) -> String {
        traverse_vec(tokens,
                     &|s| s.to_owned(),
                     &|s1, s2| s1 + &s2)
    }

pub fn count_length(tokens: &[Token]) -> usize {
    traverse_vec(tokens,
                 &|s| s.chars().count(),
                 &|s1, s2| s1 + s2)
}

/// Insert an annotation at begin and end pos begin+len in the text_view
#[doc(hidden)]
pub fn insert_annotation(tokens: &mut Vec<Token>, annotation: &Data, pos: usize, length: usize) -> Option<usize> {
    let mut pos = pos;
    let mut found_left = None;
    let mut found_right = None;
    for i in 0..tokens.len() {
        let recurse  = match tokens[i] {
            Token::Str(ref s) => {
                let len = s.chars().count();
                if pos < len || (pos == len && found_left.is_some()) {
                    // We found the first element already, so now it's the right
                    if found_left.is_some() {
                        found_right = Some((i, pos));
                        break;
                    }
                    found_left = Some((i, pos));
                    pos += length;
                    if pos <= len {
                        found_right = Some((i, pos));
                        break;
                    }
                }
                pos = pos - len;
                false
            },

            Token::Rule
                | Token::SoftBreak
                | Token::HardBreak
                => {
                    if pos < 1 {
                        if found_left.is_some() {
                            found_right = Some((i, pos));
                            break;
                        }
                        found_left = Some((i, pos));
                        pos += length;
                        if pos <= 1 {
                            found_right = Some((i, pos));
                            break;
                        }
                    }
                    pos -= 1;
                    false
                },

            _ => {
                if let Some(ref inner) = tokens[i].inner() {
                    let len = count_length(inner);
                    // Only recurse if the two is in this subtree
                    if pos < len {
                        if found_left.is_none() {
                            true
                        } else {
                            Logger::display_warning("ignored annotation as it wasn't compatible with the Markdown structure");
                            return None;
                        }
                    } else {
                        pos -= len;
                        false
                    }
                } else {
                    false
                }

            },
        };

        // Moved out of the match 'thanks' to borrowcheck
        if recurse {
            if let Some(ref mut inner) = tokens[i].inner_mut() {
                if let Some(new_pos) = insert_annotation(inner, annotation, pos, length) {
                    pos = new_pos;
                } else {
                    return None;
                }
            }
        }
    }

    if let (Some((i, pos_left)), Some((j, pos_right))) = (found_left, found_right) {
        let pos_right = pos_right;
        let mut vec = vec!();

        // Beginning token: keep the left part in the str, put the right one in our vec
        if !tokens[i].is_str() || pos_left == 0 {
            // do nothing
        } else {
            let old_token = mem::replace(&mut tokens[i], Token::Str(String::new()));
            if let Token::Str(old_str) = old_token {
                let mut chars_left:Vec<char> = old_str.chars().collect();
                let mut chars_right = chars_left.split_off(pos_left);

                let str_left:String = chars_left.into_iter().collect();
                tokens[i] = Token::Str(str_left);

                if i == j { // i and j are in same str, so split again
                    if length != chars_right.len() {
                        let inline_token = chars_right.split_off(length);
                        let inline_token = Token::Str(inline_token.into_iter().collect());
                        if pos_left == 0 {
                            tokens.insert(i, inline_token)
                        } else if i == tokens.len() {
                            tokens.push(inline_token);
                        } else {
                            tokens.insert(i+1, inline_token);
                        }
                    }
                    let annot = Token::Annotation(annotation.clone(), vec!(Token::Str(chars_right.into_iter().collect())));
                    if pos_left == 0 {
                        tokens.insert(i, annot)
                    } else if i == tokens.len() {
                        tokens.push(annot);
                    } else {
                        tokens.insert(i+1, annot);
                    }
                    return None;
                }

                let str_right:String = chars_right.into_iter().collect();
                vec.push(Token::Str(str_right));
            } else {
                unreachable!();
            }
        }

        // Middle tokens: remove them entirely and put them in our vec
        for _ in i+1..j {
            vec.push(tokens.remove(i+1));
        }

        // End token: keep the right part in the str, put the left one in our vec
        // j is now i + 1 because all tokens in between have been removed
        // unless j was equal to i to begin with
        let j = if i == j || i >= tokens.len() - 1 {
            i
        } else {
            i + 1
        };

        if !tokens[j].is_str() {
            // do nothing
        } else {
            let count = if let Token::Str(ref s) = tokens[j] {
                s.chars().count()
            } else {
                unreachable!()
            };
            if count != pos_right {
                let old_token = mem::replace(&mut tokens[j], Token::Rule);
                if let Token::Str(old_str) = old_token {
                    let mut chars_left:Vec<char> = old_str.chars().collect();
                    let chars_right = chars_left.split_off(pos_right);
                    let str_left:String = chars_left.into_iter().collect();
                    let str_right:String = chars_right.into_iter().collect();
                    tokens[j] = Token::Str(str_right);
                    // todo: if only one token, maybe concat the strings
                    vec.push(Token::Str(str_left));
                } else {
                    unreachable!();
                }
            }
        }
        let new_token = Token::Annotation(annotation.clone(), vec);
        if pos_left == 0 {
            tokens.insert(i, new_token);
        }  else if i >= tokens.len() - 1 {
            tokens.push(new_token);
        } else {
            tokens.insert(i+1, new_token);
        }
        return None;
    } else {
        if found_left.is_none() && found_right.is_none() {
            return Some(pos);
        } else {
            Logger::display_warning("ignored annotation as it wasn't compatible with the Markdown structure");
            return None;
        }
    }
}

#[test]
fn test_text_view() {
    let ast = vec!(Token::Str("123".to_owned()),
                   Token::Emphasis(vec!(Token::Str("456".to_owned()))),
                   Token::Str("789".to_owned()));
    assert_eq!(view_as_text(&ast), "123456789");
}

// #[test]
// fn test_text_insert() {
//     let mut ast = vec!(Token::Str("123".to_owned()),
//                        Token::Emphasis(vec!(Token::Str("456".to_owned()))),
//                        Token::Str("789".to_owned()));
//     insert_at(&mut ast, "!!!", 5);
//     let expected = vec!(Token::Str("123".to_owned()),
//                         Token::Emphasis(vec!(Token::Str("45".to_owned()),
//                                              Token::Comment("!!!".to_owned()),
//                                              Token::Str("6".to_owned()))),
//                         Token::Str("789".to_owned()));
//     assert_eq!(expected, ast);
// }
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros to make our custom address types require a lot less repetitive code.

macro_rules! Addr {
    (($size:ty) $(pub)* enum $name:ident $($tail:tt)*) => {
        Addr! { @impl $name, $size }
    };
    (($size:ty) $(pub)* struct $name:ident $($tail:tt)*) => {
        Addr! { @impl $name, $size }
    };
    (@impl $ty:ident, $size:ty) => {

        impl $crate::core::fmt::Debug for $ty {
            fn fmt(&self, f: &mut $crate::core::fmt::Formatter)
                  -> $crate::core::fmt::Result {
                write!(f, "{}({:#x})", stringify!($ty), self.0)
            }
        }

        impl $crate::core::convert::Into<$size> for $ty {
            #[inline] fn into(self) -> $size { self.0 }
        }

        impl $crate::core::convert::From<$size> for $ty {
            #[inline] fn from(n: $size) -> Self { $ty(n) }
        }

        impl<T> $crate::core::convert::From<*mut T> for $ty {
            #[inline] fn from(ptr: *mut T) -> Self { $ty(ptr as $size) }
        }

        impl<T> $crate::core::convert::From<*const T> for $ty {
            #[inline] fn from(ptr: *const T) -> Self { $ty(ptr as $size) }
        }

        impl $crate::core::ops::Deref for $ty {
            type Target = $size;
            #[inline] fn deref(&self) -> &Self::Target { &self.0 }
        }

        impl $ty {
            #[inline(always)]
            pub const fn as_mut_ptr<T>(&self) -> *mut T { self.0 as *mut _ }

            #[inline(always)]
            pub const fn as_ptr<T>(&self) -> *const T { self.0 as *const _ }

            /// Returns true if this address is aligned on a page boundary.
            #[inline]
            pub fn is_page_aligned(&self) -> bool {
                **self % PAGE_SIZE as <Self as Addr>::Repr == 0 as <Self as Addr>::Repr
            }
        }

        impl_ops! {
            Add, add, + for $ty, $size
            Sub, sub, - for $ty, $size
            Div, div, / for $ty, $size
            Mul, mul, * for $ty, $size
            Shl, shl, >> for $ty, $size
            Shr, shr, << for $ty, $size
            Rem, rem, % for $ty, $size
            BitAnd, bitand, & for $ty, $size
            BitOr, bitor, | for $ty, $size
            BitXor, bitxor, ^ for $ty, $size

        }

        impl_assign_ops! {
            AddAssign, add_assign, += for $ty, $size
            SubAssign, sub_assign, -= for $ty, $size
            DivAssign, div_assign, /= for $ty, $size
            MulAssign, mul_assign, *= for $ty, $size
            ShlAssign, shl_assign, >>= for $ty, $size
            ShrAssign, shr_assign, <<= for $ty, $size
            RemAssign, rem_assign, %= for $ty, $size
            BitAndAssign, bitand_assign, &= for $ty, $size
            BitOrAssign, bitor_assign, |= for $ty, $size
            BitXorAssign, bitxor_assign, ^= for $ty, $size
        }

        impl_fmt! {
            Binary for $ty
            Display for $ty
            Octal for $ty
            LowerHex for $ty
            UpperHex for $ty
        }

        impl Addr for $ty {
            type Repr = $size;
        }

    }
}

macro_rules! impl_page_ops {
    ($($name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl $crate::core::ops::$name<$ty> for $ty {
            type Output = Self;

            #[inline] fn $fun(self, rhs: $ty) -> Self {
                expr!( $ty { number: expr!(self.number $op rhs.number) })
            }
        }
        impl $crate::core::ops::$name<$size> for $ty {
            type Output = $ty;

            #[inline] fn $fun(self, rhs: $size) -> Self {
                expr!($ty{ number: expr!(self.number $op rhs) })
            }
        }

        forward_ref_binop! {
            $name, $fun for $ty, $ty
        }
        forward_ref_binop! {
            $name, $fun for $ty, $size
        }
    )*}
}

macro_rules! impl_page_assign_ops {
    ($($name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl $crate::core::ops::$name<$ty> for $ty {

            #[inline] fn $fun(&mut self, rhs: $ty) {
                expr!(self.number $op rhs.number);
            }
        }
        impl $crate::core::ops::$name<$size> for $ty {

            #[inline] fn $fun(&mut self, rhs: $size) {
                expr!(self.number $op rhs);
            }
        }
    )*}
}

macro_rules! Page {
    (($addr:ty) $(pub)* struct $name:ident $($tail:tt)*) => {
        Page! { @impl $name, $addr }
    };
    (@impl $ty:ident, $addr:ty) => {

        impl Page for $ty {
            type Address = $addr;

            /// Create a new `Page` containing the given address.
            //  TODO: rewrite this as `up`/`down` using the page shift, instead.
            fn containing(addr: $addr) -> Self {
                use $crate::memory::PAGE_SHIFT;
                assert!( *addr < 0x0000_8000_0000_0000 ||
                         *addr >= 0xffff_8000_0000_0000
                       , "invalid address: 0x{:x}", addr );
                $ty { number: *addr >> PAGE_SHIFT as <Self::Address as Addr>::Repr }
            }

            /// Return the start virtual address of this page
            #[inline]
            fn base(&self) -> $addr {
                Self::Address::from(
                    self.number << PAGE_SHIFT as <Self::Address as Addr>::Repr )
            }

            #[inline] fn number(&self) -> usize {
                self.number as usize
            }
        }

        impl $crate::core::num::One for $ty {
            #[inline] fn one() -> Self {
                $ty { number:
                    <<$addr as Addr>::Repr as $crate::core::num::One>::one()
                }
            }
        }

        impl $crate::core::iter::Step for $ty {
            #[inline]
            fn step(&self, by: &Self) -> Option<Self> {
                self.number
                    .step(&by.number)
                    .map(|s| $ty { number: s})
            }

            #[inline]
            #[allow(trivial_numeric_casts)]
            fn steps_between(start: &$ty, end: &$ty, by: &$ty)
                            -> Option<usize> {
                use $crate::core::iter::Step;
                <<$addr as Addr>::Repr as Step>::steps_between( &start.number
                                                              , &end.number
                                                              , &by.number
                                                              )
            }
        }

        impl_page_ops! {
            Add, add, + for $ty, <<$ty as Page>::Address as Addr>::Repr
            Sub, sub, - for $ty, <<$ty as Page>::Address as Addr>::Repr
            Div, div, / for $ty, <<$ty as Page>::Address as Addr>::Repr
            Mul, mul, * for $ty, <<$ty as Page>::Address as Addr>::Repr
            Shl, shl, >> for $ty,<<$ty as Page>::Address as Addr>::Repr
            Shr, shr, << for $ty, <<$ty as Page>::Address as Addr>::Repr
            Rem, rem, % for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitAnd, bitand, & for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitOr, bitor, | for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitXor, bitxor, ^ for $ty, <<$ty as Page>::Address as Addr>::Repr

        }

        impl_page_assign_ops! {
            AddAssign, add_assign, += for $ty, <<$ty as Page>::Address as Addr>::Repr
            SubAssign, sub_assign, -= for $ty, <<$ty as Page>::Address as Addr>::Repr
            DivAssign, div_assign, /= for $ty, <<$ty as Page>::Address as Addr>::Repr
            MulAssign, mul_assign, *= for $ty, <<$ty as Page>::Address as Addr>::Repr
            ShlAssign, shl_assign, >>= for $ty, <<$ty as Page>::Address as Addr>::Repr
            ShrAssign, shr_assign, <<= for $ty, <<$ty as Page>::Address as Addr>::Repr
            RemAssign, rem_assign, %= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitAndAssign, bitand_assign, &= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitOrAssign, bitor_assign, |= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitXorAssign, bitxor_assign, ^= for $ty, <<$ty as Page>::Address as Addr>::Repr
        }
    }
}
<commit_msg>[kernel] start updating paging to build against latest nightly<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros to make our custom address types require a lot less repetitive code.

macro_rules! Addr {
    (($size:ty) $(pub)* enum $name:ident $($tail:tt)*) => {
        Addr! { @impl $name, $size }
    };
    (($size:ty) $(pub)* struct $name:ident $($tail:tt)*) => {
        Addr! { @impl $name, $size }
    };
    (@impl $ty:ident, $size:ty) => {

        impl $crate::core::fmt::Debug for $ty {
            fn fmt(&self, f: &mut $crate::core::fmt::Formatter)
                  -> $crate::core::fmt::Result {
                write!(f, "{}({:#x})", stringify!($ty), self.0)
            }
        }

        impl $crate::core::convert::Into<$size> for $ty {
            #[inline] fn into(self) -> $size { self.0 }
        }

        impl $crate::core::convert::From<$size> for $ty {
            #[inline] fn from(n: $size) -> Self { $ty(n) }
        }

        impl<T> $crate::core::convert::From<*mut T> for $ty {
            #[inline] fn from(ptr: *mut T) -> Self { $ty(ptr as $size) }
        }

        impl<T> $crate::core::convert::From<*const T> for $ty {
            #[inline] fn from(ptr: *const T) -> Self { $ty(ptr as $size) }
        }

        impl $crate::core::ops::Deref for $ty {
            type Target = $size;
            #[inline] fn deref(&self) -> &Self::Target { &self.0 }
        }

        impl $ty {
            #[inline(always)]
            pub const fn as_mut_ptr<T>(&self) -> *mut T { self.0 as *mut _ }

            #[inline(always)]
            pub const fn as_ptr<T>(&self) -> *const T { self.0 as *const _ }

            /// Returns true if this address is aligned on a page boundary.
            #[inline]
            pub fn is_page_aligned(&self) -> bool {
                **self % PAGE_SIZE as <Self as Addr>::Repr == 0 as <Self as Addr>::Repr
            }
        }

        impl_ops! {
            Add, add, + for $ty, $size
            Sub, sub, - for $ty, $size
            Div, div, / for $ty, $size
            Mul, mul, * for $ty, $size
            Shl, shl, >> for $ty, $size
            Shr, shr, << for $ty, $size
            Rem, rem, % for $ty, $size
            BitAnd, bitand, & for $ty, $size
            BitOr, bitor, | for $ty, $size
            BitXor, bitxor, ^ for $ty, $size

        }

        impl_assign_ops! {
            AddAssign, add_assign, += for $ty, $size
            SubAssign, sub_assign, -= for $ty, $size
            DivAssign, div_assign, /= for $ty, $size
            MulAssign, mul_assign, *= for $ty, $size
            ShlAssign, shl_assign, >>= for $ty, $size
            ShrAssign, shr_assign, <<= for $ty, $size
            RemAssign, rem_assign, %= for $ty, $size
            BitAndAssign, bitand_assign, &= for $ty, $size
            BitOrAssign, bitor_assign, |= for $ty, $size
            BitXorAssign, bitxor_assign, ^= for $ty, $size
        }

        impl_fmt! {
            Binary for $ty
            Display for $ty
            Octal for $ty
            LowerHex for $ty
            UpperHex for $ty
        }

        impl Addr for $ty {
            type Repr = $size;
        }

    }
}

macro_rules! impl_page_ops {
    ($($name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl $crate::core::ops::$name<$ty> for $ty {
            type Output = Self;

            #[inline] fn $fun(self, rhs: $ty) -> Self {
                expr!( $ty { number: expr!(self.number $op rhs.number) })
            }
        }
        impl $crate::core::ops::$name<$size> for $ty {
            type Output = $ty;

            #[inline] fn $fun(self, rhs: $size) -> Self {
                expr!($ty{ number: expr!(self.number $op rhs) })
            }
        }

        forward_ref_binop! {
            $name, $fun for $ty, $ty
        }
        forward_ref_binop! {
            $name, $fun for $ty, $size
        }
    )*}
}

macro_rules! impl_page_assign_ops {
    ($($name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl $crate::core::ops::$name<$ty> for $ty {

            #[inline] fn $fun(&mut self, rhs: $ty) {
                expr!(self.number $op rhs.number);
            }
        }
        impl $crate::core::ops::$name<$size> for $ty {

            #[inline] fn $fun(&mut self, rhs: $size) {
                expr!(self.number $op rhs);
            }
        }
    )*}
}

macro_rules! Page {
    (($addr:ty) $(pub)* struct $name:ident $($tail:tt)*) => {
        Page! { @impl $name, $addr }
    };
    (@impl $ty:ident, $addr:ty) => {

        impl Page for $ty {
            type Address = $addr;

            /// Create a new `Page` containing the given address.
            //  TODO: rewrite this as `up`/`down` using the page shift, instead.
            fn containing(addr: $addr) -> Self {
                use $crate::memory::PAGE_SHIFT;
                assert!( *addr < 0x0000_8000_0000_0000 ||
                         *addr >= 0xffff_8000_0000_0000
                       , "invalid address: 0x{:x}", addr );
                $ty { number: *addr >> PAGE_SHIFT as <Self::Address as Addr>::Repr }
            }

            /// Return the start virtual address of this page
            #[inline]
            fn base(&self) -> $addr {
                Self::Address::from(
                    self.number << PAGE_SHIFT as <Self::Address as Addr>::Repr )
            }

            #[inline] fn number(&self) -> usize {
                self.number as usize
            }
        }

        impl $crate::core::num::One for $ty {
            #[inline] fn one() -> Self {
                $ty { number:
                    <<$addr as Addr>::Repr as $crate::core::num::One>::one()
                }
            }
        }

        impl $crate::core::iter::Step for $ty {
            #[inline]
            fn step(&self, by: &Self) -> Option<Self> {
                self.number
                    .step(&by.number)
                    .map(|s| $ty { number: s})
            }

            #[inline]
            #[allow(trivial_numeric_casts)]
            fn steps_between(start: &$ty, end: &$ty, by: &$ty)
                            -> Option<usize> {
                use $crate::core::iter::Step;
                <<$addr as Addr>::Repr as Step>::steps_between( &start.number
                                                              , &end.number
                                                              , &by.number
                                                              )
            }

            #[inline]
            fn steps_between_by_one(start: &$ty, end: &$ty) -> Option<usize> {
                use $crate::core::iter::Step;
                <<$addr as Addr>::Repr as Step>::steps_between( &start.number
                                                              , &end.number
                                                              , &1
                                                              )
            }

            #[inline] fn sub_one(&self) -> Self { self - 1 }

            #[inline] fn add_one(&self) -> Self { self + 1 }

            #[inline] fn replace_one(&mut self) -> Self { unimplemented!() }

            #[inline] fn replace_zero(&mut self) -> Self { unimplemented!() }

            #[inline] fn is_negative(&self) -> bool { unimplemented!(); }

        }

        impl_page_ops! {
            Add, add, + for $ty, <<$ty as Page>::Address as Addr>::Repr
            Sub, sub, - for $ty, <<$ty as Page>::Address as Addr>::Repr
            Div, div, / for $ty, <<$ty as Page>::Address as Addr>::Repr
            Mul, mul, * for $ty, <<$ty as Page>::Address as Addr>::Repr
            Shl, shl, >> for $ty,<<$ty as Page>::Address as Addr>::Repr
            Shr, shr, << for $ty, <<$ty as Page>::Address as Addr>::Repr
            Rem, rem, % for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitAnd, bitand, & for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitOr, bitor, | for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitXor, bitxor, ^ for $ty, <<$ty as Page>::Address as Addr>::Repr

        }

        impl_page_assign_ops! {
            AddAssign, add_assign, += for $ty, <<$ty as Page>::Address as Addr>::Repr
            SubAssign, sub_assign, -= for $ty, <<$ty as Page>::Address as Addr>::Repr
            DivAssign, div_assign, /= for $ty, <<$ty as Page>::Address as Addr>::Repr
            MulAssign, mul_assign, *= for $ty, <<$ty as Page>::Address as Addr>::Repr
            ShlAssign, shl_assign, >>= for $ty, <<$ty as Page>::Address as Addr>::Repr
            ShrAssign, shr_assign, <<= for $ty, <<$ty as Page>::Address as Addr>::Repr
            RemAssign, rem_assign, %= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitAndAssign, bitand_assign, &= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitOrAssign, bitor_assign, |= for $ty, <<$ty as Page>::Address as Addr>::Repr
            BitXorAssign, bitxor_assign, ^= for $ty, <<$ty as Page>::Address as Addr>::Repr
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016, Johan Sköld.
// License: http://opensource.org/licenses/ISC

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

fn main() {
    let target = env::var("TARGET").unwrap();
    let profile = env::var("PROFILE").unwrap();

    let first_div = target.find('-').unwrap();
    let last_div = target.rfind('-').unwrap();

    let arch = &target[..first_div];
    let platform = &target[(first_div + 1)..last_div];
    let compiler = &target[(last_div + 1)..];
    let bitness = if arch == "x86_64" { 64 } else { 32 };

    match compiler {
        "msvc" => build_msvc(bitness),
        "gnu" || "darwin" => build_gmake(bitness, &profile, platform),
        _ => panic!("Unsupported compiler"),
    }
}

fn build_msvc(bitness: u32) {
    let vs_version = env::var("VisualStudioVersion").expect("Visual Studio version not detected");
    let platform = if bitness == 32 { "X86" } else { "X64" };

    let vs_release = match vs_version.as_ref() {
        "12.0" => "2013",
        "14.0" => "2015",
        _ => panic!(format!("Unknown Visual Studio version: {:?}", vs_version)),
    };

    Command::new("make.exe")
        .current_dir("bgfx")
        .arg(format!(".build/projects/vs{}", vs_release))
        .output()
        .expect("Failed to generate project files");

    let status = Command::new("MSBuild.exe")
                     .current_dir("bgfx")
                     .arg("/p:Configuration=Release")
                     .arg(format!("/p:Platform={}", platform))
                     .arg(format!(".build/projects/vs{}/bgfx.vcxproj", vs_release))
                     .status()
                     .expect("Failed to build bgfx");

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

    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("win{}_vs{}", bitness, vs_release));
    path.push("bin");

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

fn build_gmake(bitness: u32, profile: &str, platform: &str) {
    let project_name = match platform {
        "pc-windows" => "gmake-mingw-gcc",
        "unknown-linux" => "gmake-linux",
        "apple" => "gmake-osx",
        _ => panic!("Unsupported OS"),
    };

    let output_name = match platform {
        "pc-windows" => format!("win{}_mingw-gcc", bitness),
        "unknown-linux" => format!("linux{}_gcc", bitness),
        "apple" => format!("osx{}_clang", bitness),
        _ => unreachable!(),
    };

    // Generate makefiles
    Command::new("make")
        .current_dir("bgfx")
        .arg(format!(".build/projects/{}", project_name))
        .output()
        .expect("Failed to generate makefiles");

    // Build bgfx
    let status = Command::new("make")
                     .current_dir("bgfx")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(format!(".build/projects/{}", project_name))
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .expect("Failed to build bgfx");

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

    // Output linker config
    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(output_name);
    path.push("bin");

    let config = if profile == "debug" { "Debug" } else { "Release" };
    println!("cargo:rustc-link-lib=bgfx{}", config);
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());

    match platform {
        "pc-windows" => {
            println!("cargo:rustc-link-lib=gdi32");
            println!("cargo:rustc-link-lib=opengl32");
            println!("cargo:rustc-link-lib=psapi");
        }
        "unknown-linux" => {
            println!("cargo:rustc-link-lib=GL");
            println!("cargo:rustc-link-lib=X11");
        }
        "apple" => {
            println!("cargo:rustc-link-lib=framework=Cocoa");
            println!("cargo:rustc-link-lib=framework=QuartzCore");
            println!("cargo:rustc-link-lib=framework=OpenGL");
            println!("cargo:rustc-link-lib=framework=Metal");
        }
        _ => unreachable!(),
    }
}
<commit_msg>Fixing typo in build script.<commit_after>// Copyright (c) 2015-2016, Johan Sköld.
// License: http://opensource.org/licenses/ISC

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

fn main() {
    let target = env::var("TARGET").unwrap();
    let profile = env::var("PROFILE").unwrap();

    let first_div = target.find('-').unwrap();
    let last_div = target.rfind('-').unwrap();

    let arch = &target[..first_div];
    let platform = &target[(first_div + 1)..last_div];
    let compiler = &target[(last_div + 1)..];
    let bitness = if arch == "x86_64" { 64 } else { 32 };

    match compiler {
        "msvc" => build_msvc(bitness),
        "gnu" | "darwin" => build_gmake(bitness, &profile, platform),
        _ => panic!("Unsupported compiler"),
    }
}

fn build_msvc(bitness: u32) {
    let vs_version = env::var("VisualStudioVersion").expect("Visual Studio version not detected");
    let platform = if bitness == 32 { "X86" } else { "X64" };

    let vs_release = match vs_version.as_ref() {
        "12.0" => "2013",
        "14.0" => "2015",
        _ => panic!(format!("Unknown Visual Studio version: {:?}", vs_version)),
    };

    Command::new("make.exe")
        .current_dir("bgfx")
        .arg(format!(".build/projects/vs{}", vs_release))
        .output()
        .expect("Failed to generate project files");

    let status = Command::new("MSBuild.exe")
                     .current_dir("bgfx")
                     .arg("/p:Configuration=Release")
                     .arg(format!("/p:Platform={}", platform))
                     .arg(format!(".build/projects/vs{}/bgfx.vcxproj", vs_release))
                     .status()
                     .expect("Failed to build bgfx");

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

    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("win{}_vs{}", bitness, vs_release));
    path.push("bin");

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

fn build_gmake(bitness: u32, profile: &str, platform: &str) {
    let project_name = match platform {
        "pc-windows" => "gmake-mingw-gcc",
        "unknown-linux" => "gmake-linux",
        "apple" => "gmake-osx",
        _ => panic!("Unsupported OS"),
    };

    let output_name = match platform {
        "pc-windows" => format!("win{}_mingw-gcc", bitness),
        "unknown-linux" => format!("linux{}_gcc", bitness),
        "apple" => format!("osx{}_clang", bitness),
        _ => unreachable!(),
    };

    // Generate makefiles
    Command::new("make")
        .current_dir("bgfx")
        .arg(format!(".build/projects/{}", project_name))
        .output()
        .expect("Failed to generate makefiles");

    // Build bgfx
    let status = Command::new("make")
                     .current_dir("bgfx")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(format!(".build/projects/{}", project_name))
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .expect("Failed to build bgfx");

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

    // Output linker config
    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(output_name);
    path.push("bin");

    let config = if profile == "debug" { "Debug" } else { "Release" };
    println!("cargo:rustc-link-lib=bgfx{}", config);
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());

    match platform {
        "pc-windows" => {
            println!("cargo:rustc-link-lib=gdi32");
            println!("cargo:rustc-link-lib=opengl32");
            println!("cargo:rustc-link-lib=psapi");
        }
        "unknown-linux" => {
            println!("cargo:rustc-link-lib=GL");
            println!("cargo:rustc-link-lib=X11");
        }
        "apple" => {
            println!("cargo:rustc-link-lib=framework=Cocoa");
            println!("cargo:rustc-link-lib=framework=QuartzCore");
            println!("cargo:rustc-link-lib=framework=OpenGL");
            println!("cargo:rustc-link-lib=framework=Metal");
        }
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>//! Executor abstraction for executing callbacks to user code (request filters, provider state change callbacks)

use pact_matching::models::Request;

/// Trait for executors that call request filters
pub trait RequestFilterExecutor {
  fn call(&self, request: &Request) -> Request;
}

/// A "null" request filter executor, which does nothing, but permits
/// bypassing of typechecking issues where no filter should be applied.
pub struct NullRequestFilterExecutor;

impl RequestFilterExecutor for NullRequestFilterExecutor {
  fn call(&self, request: &Request) -> Request {
    unimplemented!("NullRequestFilterExecutor should never be called")
  }
}
<commit_msg>Make `NullRequestFilterExecutor` unconstructable.<commit_after>//! Executor abstraction for executing callbacks to user code (request filters, provider state change callbacks)

use pact_matching::models::Request;

/// Trait for executors that call request filters
pub trait RequestFilterExecutor {
  fn call(&self, request: &Request) -> Request;
}

/// A "null" request filter executor, which does nothing, but permits
/// bypassing of typechecking issues where no filter should be applied.
pub struct NullRequestFilterExecutor {
  // This field is added (and is private) to guarantee that this struct
  // is never instantiated accidentally, and is instead only able to be
  // used for type-level programming.
  _private_field: (),
}

impl RequestFilterExecutor for NullRequestFilterExecutor {
  fn call(&self, request: &Request) -> Request {
    unimplemented!("NullRequestFilterExecutor should never be called")
  }
}
<|endoftext|>


<commit_before>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type suseconds_t = i64;

s! {
    pub struct timeval {
        pub tv_sec: time_t,
        pub tv_usec: suseconds_t,
    }

    pub struct timespec {
        pub tv_sec: time_t,
        pub tv_nsec: c_long,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

pub const F_DUPFD: ::c_int = 0;
pub const F_GETFD: ::c_int = 1;
pub const F_SETFD: ::c_int = 2;
pub const F_GETFL: ::c_int = 3;
pub const F_SETFL: ::c_int = 4;

pub const O_RDONLY: ::c_int =     0x0001_0000;
pub const O_WRONLY: ::c_int =     0x0002_0000;
pub const O_RDWR: ::c_int =       0x0003_0000;
pub const O_NONBLOCK: ::c_int =   0x0004_0000;
pub const O_APPEND: ::c_int =     0x0008_0000;
pub const O_SHLOCK: ::c_int =     0x0010_0000;
pub const O_EXLOCK: ::c_int =     0x0020_0000;
pub const O_ASYNC: ::c_int =      0x0040_0000;
pub const O_FSYNC: ::c_int =      0x0080_0000;
pub const O_CLOEXEC: ::c_int =    0x0100_0000;
pub const O_CREAT: ::c_int =      0x0200_0000;
pub const O_TRUNC: ::c_int =      0x0400_0000;
pub const O_EXCL: ::c_int =       0x0800_0000;
pub const O_DIRECTORY: ::c_int =  0x1000_0000;
pub const O_STAT: ::c_int =       0x2000_0000;
pub const O_SYMLINK: ::c_int =    0x4000_0000;
pub const O_NOFOLLOW: ::c_int =   0x8000_0000;
pub const O_ACCMODE: ::c_int =    O_RDONLY | O_WRONLY | O_RDWR;

pub const SIGHUP:    usize = 1;
pub const SIGINT:    usize = 2;
pub const SIGQUIT:   usize = 3;
pub const SIGILL:    usize = 4;
pub const SIGTRAP:   usize = 5;
pub const SIGABRT:   usize = 6;
pub const SIGBUS:    usize = 7;
pub const SIGFPE:    usize = 8;
pub const SIGKILL:   usize = 9;
pub const SIGUSR1:   usize = 10;
pub const SIGSEGV:   usize = 11;
pub const SIGUSR2:   usize = 12;
pub const SIGPIPE:   usize = 13;
pub const SIGALRM:   usize = 14;
pub const SIGTERM:   usize = 15;
pub const SIGSTKFLT: usize = 16;
pub const SIGCHLD:   usize = 17;
pub const SIGCONT:   usize = 18;
pub const SIGSTOP:   usize = 19;
pub const SIGTSTP:   usize = 20;
pub const SIGTTIN:   usize = 21;
pub const SIGTTOU:   usize = 22;
pub const SIGURG:    usize = 23;
pub const SIGXCPU:   usize = 24;
pub const SIGXFSZ:   usize = 25;
pub const SIGVTALRM: usize = 26;
pub const SIGPROF:   usize = 27;
pub const SIGWINCH:  usize = 28;
pub const SIGIO:     usize = 29;
pub const SIGPWR:    usize = 30;
pub const SIGSYS:    usize = 31;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t)
                -> ::ssize_t;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t)
                 -> ::ssize_t;
    pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int;
    pub fn close(fd: ::c_int) -> ::c_int;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}

pub use self::net::*;

mod net;
<commit_msg>c_int over usize, whoops<commit_after>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type suseconds_t = i64;

s! {
    pub struct timeval {
        pub tv_sec: time_t,
        pub tv_usec: suseconds_t,
    }

    pub struct timespec {
        pub tv_sec: time_t,
        pub tv_nsec: c_long,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

pub const F_DUPFD: ::c_int = 0;
pub const F_GETFD: ::c_int = 1;
pub const F_SETFD: ::c_int = 2;
pub const F_GETFL: ::c_int = 3;
pub const F_SETFL: ::c_int = 4;

pub const O_RDONLY: ::c_int =     0x0001_0000;
pub const O_WRONLY: ::c_int =     0x0002_0000;
pub const O_RDWR: ::c_int =       0x0003_0000;
pub const O_NONBLOCK: ::c_int =   0x0004_0000;
pub const O_APPEND: ::c_int =     0x0008_0000;
pub const O_SHLOCK: ::c_int =     0x0010_0000;
pub const O_EXLOCK: ::c_int =     0x0020_0000;
pub const O_ASYNC: ::c_int =      0x0040_0000;
pub const O_FSYNC: ::c_int =      0x0080_0000;
pub const O_CLOEXEC: ::c_int =    0x0100_0000;
pub const O_CREAT: ::c_int =      0x0200_0000;
pub const O_TRUNC: ::c_int =      0x0400_0000;
pub const O_EXCL: ::c_int =       0x0800_0000;
pub const O_DIRECTORY: ::c_int =  0x1000_0000;
pub const O_STAT: ::c_int =       0x2000_0000;
pub const O_SYMLINK: ::c_int =    0x4000_0000;
pub const O_NOFOLLOW: ::c_int =   0x8000_0000;
pub const O_ACCMODE: ::c_int =    O_RDONLY | O_WRONLY | O_RDWR;

pub const SIGHUP:    ::c_int = 1;
pub const SIGINT:    ::c_int = 2;
pub const SIGQUIT:   ::c_int = 3;
pub const SIGILL:    ::c_int = 4;
pub const SIGTRAP:   ::c_int = 5;
pub const SIGABRT:   ::c_int = 6;
pub const SIGBUS:    ::c_int = 7;
pub const SIGFPE:    ::c_int = 8;
pub const SIGKILL:   ::c_int = 9;
pub const SIGUSR1:   ::c_int = 10;
pub const SIGSEGV:   ::c_int = 11;
pub const SIGUSR2:   ::c_int = 12;
pub const SIGPIPE:   ::c_int = 13;
pub const SIGALRM:   ::c_int = 14;
pub const SIGTERM:   ::c_int = 15;
pub const SIGSTKFLT: ::c_int = 16;
pub const SIGCHLD:   ::c_int = 17;
pub const SIGCONT:   ::c_int = 18;
pub const SIGSTOP:   ::c_int = 19;
pub const SIGTSTP:   ::c_int = 20;
pub const SIGTTIN:   ::c_int = 21;
pub const SIGTTOU:   ::c_int = 22;
pub const SIGURG:    ::c_int = 23;
pub const SIGXCPU:   ::c_int = 24;
pub const SIGXFSZ:   ::c_int = 25;
pub const SIGVTALRM: ::c_int = 26;
pub const SIGPROF:   ::c_int = 27;
pub const SIGWINCH:  ::c_int = 28;
pub const SIGIO:     ::c_int = 29;
pub const SIGPWR:    ::c_int = 30;
pub const SIGSYS:    ::c_int = 31;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t)
                -> ::ssize_t;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t)
                 -> ::ssize_t;
    pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int;
    pub fn close(fd: ::c_int) -> ::c_int;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}

pub use self::net::*;

mod net;
<|endoftext|>


<commit_before>#![crate_name = "uu_mktemp"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Sunrin SHIMURA
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;
extern crate tempfile;
extern crate rand;

#[macro_use]
extern crate uucore;

use std::env;
use std::io::Write;
use std::path::{PathBuf, is_separator};
use std::mem::forget;
use std::iter;

use rand::Rng;
use tempfile::NamedTempFileOptions;

static NAME: &'static str = "mktemp";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static DEFAULT_TEMPLATE: &'static str = "tmp.XXXXXXXXXX";

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("d", "directory", "Make a directory instead of a file");
    opts.optflag("u", "dry-run", "do not create anything; merely print a name (unsafe)");
    opts.optflag("q", "quiet", "Fail silently if an error occurs.");
    opts.optopt("", "suffix", "append SUFF to TEMPLATE; SUFF must not contain a path separator. This option is implied if TEMPLATE does not end with X.", "SUFF");
    opts.optopt("p", "tmpdir", "interpret TEMPLATE relative to DIR; if DIR is not specified, use $TMPDIR if set, else /tmp.  With this option, TEMPLATE  must  not  be  an  absolute name; unlike with -t, TEMPLATE may contain slashes, but mktemp creates only the final component", "DIR");
    // deprecated option of GNU coreutils
    //    opts.optflag("t", "", "Generate a template (using the supplied prefix and TMPDIR if set) to create a filename template");
    opts.optflag("", "help", "Print this help and exit");
    opts.optflag("", "version", "print the version and exit");

    // >> early return options
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };

    if matches.opt_present("quiet") {
        // TODO: close stderror. `crash!` macro always write output to stderror
        crash!(1, "quiet option is not supported yet.");
    };

    if  matches.opt_present("help") {
        print_help(&opts);
        return 0;
    }
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if 1 < matches.free.len() {
        crash!(1, "Too many templates");
    }
    // <<

    let make_dir = matches.opt_present("directory");
    let dry_run = matches.opt_present("dry-run");
    let suffix_opt = matches.opt_str("suffix");

    let template = if matches.free.is_empty() {
        DEFAULT_TEMPLATE
    } else {
        &matches.free[0][..]
    };

    let (prefix, rand, suffix) = match parse_template(template) {
        Some((p, r, s)) => match suffix_opt {
            Some(suf) => if s == "" {
                (p, r, suf)
            } else {
                crash!(1, "Template should end with 'X' when you specify suffix option.")
            },
            None => (p, r, s.to_owned())
        },
        None => ("",0, "".to_owned())
    };

    if rand < 3 {
        crash!(1, "Too few 'X's in template")
    }

    if suffix.chars().any(is_separator) {
        crash!(1, "suffix cannot contain any path separators");
    }

    let tmpdir = match matches.opt_str("tmpdir") {
        Some(s) => {
            if PathBuf::from(prefix).is_absolute() {
                crash!(1, "template must not be an absolute path when tempdir is specified.");
            }
            PathBuf::from(s)

        },
        None => env::temp_dir()
    };

    if dry_run {
        dry_exec(tmpdir, prefix, rand, &suffix)
    } else {
        exec(tmpdir, prefix, rand , &suffix, make_dir)
    }

}

fn print_help(opts: &getopts::Options) {
    let usage = format!(" Create a temporary file or directory, safely, and print its name.
TEMPLATE must contain at least 3 consecutive 'X's in last component.
If TEMPLATE is not specified, use {}, and --tmpdir is implied", DEFAULT_TEMPLATE);

    println!("{} {}", NAME, VERSION);
    println!("SYNOPSIS");
    println!("  {} [OPTION]... [FILE]", NAME);
    println!("Usage:");
    print!("{}", opts.usage(&usage[..]));
}

fn parse_template(temp :&str) -> Option<(&str, usize, &str)> {
    let right = match temp.rfind('X') {
        Some(r) => r+1,
        None => return None
    };
    let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1);
    let prefix = &temp[..left];
    let rand = right - left;
    let suffix = &temp[right..];
    Some((prefix, rand, suffix))
}

pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) -> i32 {
    let len = prefix.len() + suffix.len() + rand;
    let mut buf = String::with_capacity(len);
    buf.push_str(prefix);
    buf.extend(iter::repeat('X').take(rand));
    buf.push_str(suffix);

    // Randomize.
    unsafe {
        // We guarantee utf8.
        let bytes = &mut buf.as_mut_vec()[prefix.len()..prefix.len() + rand];
        rand::thread_rng().fill_bytes(bytes);
        for byte in bytes.iter_mut() {
            *byte = match *byte % 62 {
                v @ 0...9 => (v + '0' as u8),
                v @ 10...35 => (v - 10 + 'a' as u8),
                v @ 36...61 => (v - 36 + 'A' as u8),
                _ => unreachable!(),
            }
        }
    }
    tmpdir.push(String::from(buf));
    println!("{}", tmpdir.display());
    0
}

fn exec(tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> i32 {
    // TODO: respect make_dir option
    if make_dir {
        crash!(1, "Directory option is not supported yet. Sorry.");
    }

    let tmpfile = NamedTempFileOptions::new()
        .prefix(prefix)
        .rand_bytes(rand)
        .suffix(suffix)
        .create_in(tmpdir);

    let tmpfile = match tmpfile {
        Ok(f) => f,
        Err(_) => crash!(1, "failed to create tempfile")
    };

    let tmpname = tmpfile
        .path()
        .to_string_lossy()
        .to_string();

    println!("{}", tmpname);

    // CAUTION: Not to call `drop` of tmpfile, which removes the tempfile,
    // I call a dengeros function `forget`.
    forget(tmpfile);

    0
}
<commit_msg>mktemp: fix whitespace<commit_after>#![crate_name = "uu_mktemp"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Sunrin SHIMURA
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;
extern crate tempfile;
extern crate rand;

#[macro_use]
extern crate uucore;

use std::env;
use std::io::Write;
use std::path::{PathBuf, is_separator};
use std::mem::forget;
use std::iter;

use rand::Rng;
use tempfile::NamedTempFileOptions;

static NAME: &'static str = "mktemp";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static DEFAULT_TEMPLATE: &'static str = "tmp.XXXXXXXXXX";

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("d", "directory", "Make a directory instead of a file");
    opts.optflag("u", "dry-run", "do not create anything; merely print a name (unsafe)");
    opts.optflag("q", "quiet", "Fail silently if an error occurs.");
    opts.optopt("", "suffix", "append SUFF to TEMPLATE; SUFF must not contain a path separator. This option is implied if TEMPLATE does not end with X.", "SUFF");
    opts.optopt("p", "tmpdir", "interpret TEMPLATE relative to DIR; if DIR is not specified, use $TMPDIR if set, else /tmp.  With this option, TEMPLATE  must  not  be  an  absolute name; unlike with -t, TEMPLATE may contain slashes, but mktemp creates only the final component", "DIR");
    // deprecated option of GNU coreutils
    //    opts.optflag("t", "", "Generate a template (using the supplied prefix and TMPDIR if set) to create a filename template");
    opts.optflag("", "help", "Print this help and exit");
    opts.optflag("", "version", "print the version and exit");

    // >> early return options
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };

    if matches.opt_present("quiet") {
        // TODO: close stderror. `crash!` macro always write output to stderror
        crash!(1, "quiet option is not supported yet.");
    };

    if  matches.opt_present("help") {
        print_help(&opts);
        return 0;
    }
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if 1 < matches.free.len() {
        crash!(1, "Too many templates");
    }
    // <<

    let make_dir = matches.opt_present("directory");
    let dry_run = matches.opt_present("dry-run");
    let suffix_opt = matches.opt_str("suffix");

    let template = if matches.free.is_empty() {
        DEFAULT_TEMPLATE
    } else {
        &matches.free[0][..]
    };

    let (prefix, rand, suffix) = match parse_template(template) {
        Some((p, r, s)) => match suffix_opt {
            Some(suf) => if s == "" {
                (p, r, suf)
            } else {
                crash!(1, "Template should end with 'X' when you specify suffix option.")
            },
            None => (p, r, s.to_owned())
        },
        None => ("",0, "".to_owned())
    };

    if rand < 3 {
        crash!(1, "Too few 'X's in template")
    }

    if suffix.chars().any(is_separator) {
        crash!(1, "suffix cannot contain any path separators");
    }

    let tmpdir = match matches.opt_str("tmpdir") {
        Some(s) => {
            if PathBuf::from(prefix).is_absolute() {
                crash!(1, "template must not be an absolute path when tempdir is specified.");
            }
            PathBuf::from(s)

        },
        None => env::temp_dir()
    };

    if dry_run {
        dry_exec(tmpdir, prefix, rand, &suffix)
    } else {
        exec(tmpdir, prefix, rand , &suffix, make_dir)
    }

}

fn print_help(opts: &getopts::Options) {
    let usage = format!(" Create a temporary file or directory, safely, and print its name.
TEMPLATE must contain at least 3 consecutive 'X's in last component.
If TEMPLATE is not specified, use {}, and --tmpdir is implied", DEFAULT_TEMPLATE);

    println!("{} {}", NAME, VERSION);
    println!("SYNOPSIS");
    println!("  {} [OPTION]... [FILE]", NAME);
    println!("Usage:");
    print!("{}", opts.usage(&usage[..]));
}

fn parse_template(temp :&str) -> Option<(&str, usize, &str)> {
    let right = match temp.rfind('X') {
        Some(r) => r+1,
        None => return None
    };
    let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1);
    let prefix = &temp[..left];
    let rand = right - left;
    let suffix = &temp[right..];
    Some((prefix, rand, suffix))
}

pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) -> i32 {
    let len = prefix.len() + suffix.len() + rand;
    let mut buf = String::with_capacity(len);
    buf.push_str(prefix);
    buf.extend(iter::repeat('X').take(rand));
    buf.push_str(suffix);

    // Randomize.
    unsafe {
        // We guarantee utf8.
        let bytes = &mut buf.as_mut_vec()[prefix.len()..prefix.len() + rand];
        rand::thread_rng().fill_bytes(bytes);
        for byte in bytes.iter_mut() {
            *byte = match *byte % 62 {
                v @ 0...9 => (v + '0' as u8),
                v @ 10...35 => (v - 10 + 'a' as u8),
                v @ 36...61 => (v - 36 + 'A' as u8),
                _ => unreachable!(),
            }
        }
    }
    tmpdir.push(String::from(buf));
    println!("{}", tmpdir.display());
    0
}

fn exec(tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> i32 {
    // TODO: respect make_dir option
    if make_dir {
        crash!(1, "Directory option is not supported yet. Sorry.");
    }

    let tmpfile = NamedTempFileOptions::new()
        .prefix(prefix)
        .rand_bytes(rand)
        .suffix(suffix)
        .create_in(tmpdir);

    let tmpfile = match tmpfile {
        Ok(f) => f,
        Err(_) => crash!(1, "failed to create tempfile")
    };

    let tmpname = tmpfile
        .path()
        .to_string_lossy()
        .to_string();

    println!("{}", tmpname);

    // CAUTION: Not to call `drop` of tmpfile, which removes the tempfile,
    // I call a dengeros function `forget`.
    forget(tmpfile);

    0
}
<|endoftext|>