<commit_before>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Finding C declarations.

use std::vec;
use std::collections::{HashSet};
use std::str::{FromStr};

use super::{Entity, EntityKind, Type, TypeKind};

type Seen = HashSet<String>;

//================================================
// Enums
//================================================

// DefinitionValue _______________________________

/// The value of a C preprocessor definition.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum DefinitionValue {
    /// An integer.
    Integer(bool, u64),
    /// A floating point number.
    Real(f64),
}

impl DefinitionValue {
    //- Constructors -----------------------------

    fn from_entity(entity: Entity) -> Option<DefinitionValue> {
        let mut tokens = entity.get_range().unwrap().tokenize();
        if tokens.last().map_or(false, |t| t.get_spelling() == "#") {
            tokens.pop();
        }

        let (negated, number) = if tokens.len() == 2 {
            (false, tokens[1].get_spelling())
        } else if tokens.len() == 3 && tokens[1].get_spelling() == "-" {
            (true, tokens[2].get_spelling())
        } else {
            return None;
        };

        if let Ok(integer) = u64::from_str(&number) {
            Some(DefinitionValue::Integer(negated, integer))
        } else if let Ok(real) = f64::from_str(&number) {
            if negated {
                Some(DefinitionValue::Real(-real))
            } else {
                Some(DefinitionValue::Real(real))
            }
        } else {
            None
        }
    }
}

//================================================
// Structs
//================================================

// Declaration ___________________________________

/// A C declaration.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Declaration<'tu> {
    /// The name of the declaration.
    pub name: String,
    /// The entity that describes the declaration (e.g., contains the fields of a struct).
    pub entity: Entity<'tu>,
    /// The entity the declaration originated from if it differs from `entity`.
    pub source: Option<Entity<'tu>>,
}

impl<'tu> Declaration<'tu> {
    //- Constructors -----------------------------

    fn new(name: String, entity: Entity<'tu>, source: Option<Entity<'tu>>) -> Declaration<'tu> {
        Declaration { name: name, entity: entity, source: source }
    }
}

// Definition ____________________________________

/// A C preprocessor definition.
#[derive(Clone, Debug, PartialEq)]
pub struct Definition<'tu> {
    /// The name of the definition.
    pub name: String,
    /// The value of the definition.
    pub value: DefinitionValue,
    /// The entity that describes the definition.
    pub entity: Entity<'tu>,
}

impl<'tu> Definition<'tu> {
    //- Constructors -----------------------------

    fn new(name: String, value: DefinitionValue, entity: Entity<'tu>) -> Definition<'tu> {
        Definition { name: name, value: value, entity: entity }
    }
}

// Definitions ___________________________________

/// An iterator over preprocessor definition declarations.
#[allow(missing_debug_implementations)]
pub struct Definitions<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Definitions<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Definitions<'tu> {
        Definitions { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Definitions<'tu> {
    type Item = Definition<'tu>;

    fn next(&mut self) -> Option<Definition<'tu>> {
        for entity in &mut self.entities {
            if entity.get_kind() == EntityKind::MacroDefinition {
                let name = entity.get_name().unwrap();
                if !self.seen.contains(&name) {
                    if let Some(value) = DefinitionValue::from_entity(entity) {
                        self.seen.insert(name.clone());
                        return Some(Definition::new(name, value, entity));
                    }
                }
            }
        }
        None
    }
}

// Enums _________________________________________

/// An iterator over enum declarations.
#[allow(missing_debug_implementations)]
pub struct Enums<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Enums<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Enums<'tu> {
        Enums { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Enums<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        next(&mut self.entities, &mut self.seen, EntityKind::EnumDecl, "enum ")
    }
}

// Functions _____________________________________

/// An iterator over function declarations.
#[allow(missing_debug_implementations)]
pub struct Functions<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Functions<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Functions<'tu> {
        Functions { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Functions<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        for entity in &mut self.entities {
            if entity.get_kind() == EntityKind::FunctionDecl {
                let name = entity.get_name().unwrap();
                if !self.seen.contains(&name) {
                    self.seen.insert(name.clone());
                    return Some(Declaration::new(name, entity, None));
                }
            }
        }
        None
    }
}

// Structs _______________________________________

/// An iterator over struct declarations.
#[allow(missing_debug_implementations)]
pub struct Structs<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Structs<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Structs<'tu> {
        Structs { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Structs<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        next(&mut self.entities, &mut self.seen, EntityKind::StructDecl, "struct ")
    }
}

// Typedefs ______________________________________

/// An iterator over typedef declarations.
#[allow(missing_debug_implementations)]
pub struct Typedefs<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Typedefs<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Typedefs<'tu> {
        Typedefs { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Typedefs<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        for entity in &mut self.entities {
            if entity.get_kind() == EntityKind::TypedefDecl {
                let name = entity.get_name().unwrap();
                if !self.seen.contains(&name) {
                    let underlying = entity.get_typedef_underlying_type().unwrap();
                    let display = entity.get_type().unwrap().get_display_name();

                    let typedef = underlying.get_kind() != TypeKind::Unexposed ||
                        underlying.get_result_type().is_some() ||
                        is_alias(underlying, &display);

                    if typedef {
                        self.seen.insert(name.clone());
                        return Some(Declaration::new(name, entity, None));
                    }
                }
            }
        }
        None
    }
}

// Unions ________________________________________

/// An iterator over struct declarations.
#[allow(missing_debug_implementations)]
pub struct Unions<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Unions<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Unions<'tu> {
        Unions { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Unions<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        next(&mut self.entities, &mut self.seen, EntityKind::UnionDecl, "union ")
    }
}

//================================================
// Functions
//================================================

fn is(type_: Type, prefix: &str) -> bool {
    type_.get_kind() == TypeKind::Unexposed && type_.get_display_name().starts_with(prefix)
}

fn is_alias(type_: Type, name: &str) -> bool {
    for prefix in &["enum ", "struct ", "union "] {
        let display = type_.get_display_name();

        if display.starts_with(prefix) && &display[prefix.len()..] != name {
            return true;
        }
    }

    false
}

fn next<'tu>(
    entities: &mut vec::IntoIter<Entity<'tu>>,
    seen: &mut HashSet<String>,
    kind: EntityKind,
    prefix: &str,
) -> Option<Declaration<'tu>> {
    for entity in entities {
        if entity.get_kind() == kind {
            if let Some(name) = entity.get_name() {
                if !seen.contains(&name) {
                    seen.insert(name);
                    if entity.get_type().map_or(false, |t| t.get_sizeof().is_ok()) {
                        return Some(Declaration::new(entity.get_name().unwrap(), entity, None));
                    }
                }
            }
        } else if entity.get_kind() == EntityKind::TypedefDecl {
            let underlying = entity.get_typedef_underlying_type().unwrap();
            let name = entity.get_name().unwrap();

            println!("{:?}", underlying.get_kind());
            println!("{:?}", TypeKind::Unexposed);
            println!("{:?}", unsafe { ::std::mem::transmute::<_, ::libc::c_int>(underlying.get_kind()) });
            println!("{:?}", unsafe { ::std::mem::transmute::<_, ::libc::c_int>(TypeKind::Unexposed) });

            if is(underlying, prefix) && !seen.contains(&name) {
                let declaration = underlying.get_declaration().unwrap();

                let complete = declaration.get_type().map_or(false, |t| t.get_sizeof().is_ok());
                let anonymous = declaration.get_display_name().is_none();
                let same = entity.get_display_name() == declaration.get_display_name();

                seen.insert(name);
                if complete && (anonymous || same) {
                    let name = entity.get_name().unwrap();
                    return Some(Declaration::new(name, declaration, Some(entity)));
                }
            }
        }
    }
    None
}

/// Returns an iterator over the simple preprocessor definitions in the supplied entities.
///
/// Simple preprocessor definitions are those that consist only of a single integer or floating
/// point literal, optionally negated.
///
/// If a preprocessor definition is encountered multiple times, only the first instance is included.
pub fn find_definitions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Definitions<'tu> {
    Definitions::new(entities.into().into_iter())
}

/// Returns an iterator over the enums in the supplied entities.
///
/// If an enum is encountered multiple times, only the first instance is included.
pub fn find_enums<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Enums<'tu> {
    Enums::new(entities.into().into_iter())
}

/// Returns an iterator over the functions in the supplied entities.
///
/// If a function is encountered multiple times, only the first instance is included.
pub fn find_functions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Functions<'tu> {
    Functions::new(entities.into().into_iter())
}

/// Returns an iterator over the structs in the supplied entities.
///
/// If a struct is encountered multiple times, only the first instance is included.
pub fn find_structs<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Structs<'tu> {
    Structs::new(entities.into().into_iter())
}

/// Returns an iterator over the typedefs in the supplied entities.
///
/// If a typedef is encountered multiple times, only the first instance is included.
pub fn find_typedefs<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Typedefs<'tu> {
    Typedefs::new(entities.into().into_iter())
}

/// Returns an iterator over the unions in the supplied entities.
///
/// If a union is encountered multiple times, only the first instance is included.
pub fn find_unions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Unions<'tu> {
    Unions::new(entities.into().into_iter())
}
<commit_msg>Remove unnecessary println! usage<commit_after>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Finding C declarations.

use std::vec;
use std::collections::{HashSet};
use std::str::{FromStr};

use super::{Entity, EntityKind, Type, TypeKind};

type Seen = HashSet<String>;

//================================================
// Enums
//================================================

// DefinitionValue _______________________________

/// The value of a C preprocessor definition.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum DefinitionValue {
    /// An integer.
    Integer(bool, u64),
    /// A floating point number.
    Real(f64),
}

impl DefinitionValue {
    //- Constructors -----------------------------

    fn from_entity(entity: Entity) -> Option<DefinitionValue> {
        let mut tokens = entity.get_range().unwrap().tokenize();
        if tokens.last().map_or(false, |t| t.get_spelling() == "#") {
            tokens.pop();
        }

        let (negated, number) = if tokens.len() == 2 {
            (false, tokens[1].get_spelling())
        } else if tokens.len() == 3 && tokens[1].get_spelling() == "-" {
            (true, tokens[2].get_spelling())
        } else {
            return None;
        };

        if let Ok(integer) = u64::from_str(&number) {
            Some(DefinitionValue::Integer(negated, integer))
        } else if let Ok(real) = f64::from_str(&number) {
            if negated {
                Some(DefinitionValue::Real(-real))
            } else {
                Some(DefinitionValue::Real(real))
            }
        } else {
            None
        }
    }
}

//================================================
// Structs
//================================================

// Declaration ___________________________________

/// A C declaration.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Declaration<'tu> {
    /// The name of the declaration.
    pub name: String,
    /// The entity that describes the declaration (e.g., contains the fields of a struct).
    pub entity: Entity<'tu>,
    /// The entity the declaration originated from if it differs from `entity`.
    pub source: Option<Entity<'tu>>,
}

impl<'tu> Declaration<'tu> {
    //- Constructors -----------------------------

    fn new(name: String, entity: Entity<'tu>, source: Option<Entity<'tu>>) -> Declaration<'tu> {
        Declaration { name: name, entity: entity, source: source }
    }
}

// Definition ____________________________________

/// A C preprocessor definition.
#[derive(Clone, Debug, PartialEq)]
pub struct Definition<'tu> {
    /// The name of the definition.
    pub name: String,
    /// The value of the definition.
    pub value: DefinitionValue,
    /// The entity that describes the definition.
    pub entity: Entity<'tu>,
}

impl<'tu> Definition<'tu> {
    //- Constructors -----------------------------

    fn new(name: String, value: DefinitionValue, entity: Entity<'tu>) -> Definition<'tu> {
        Definition { name: name, value: value, entity: entity }
    }
}

// Definitions ___________________________________

/// An iterator over preprocessor definition declarations.
#[allow(missing_debug_implementations)]
pub struct Definitions<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Definitions<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Definitions<'tu> {
        Definitions { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Definitions<'tu> {
    type Item = Definition<'tu>;

    fn next(&mut self) -> Option<Definition<'tu>> {
        for entity in &mut self.entities {
            if entity.get_kind() == EntityKind::MacroDefinition {
                let name = entity.get_name().unwrap();
                if !self.seen.contains(&name) {
                    if let Some(value) = DefinitionValue::from_entity(entity) {
                        self.seen.insert(name.clone());
                        return Some(Definition::new(name, value, entity));
                    }
                }
            }
        }
        None
    }
}

// Enums _________________________________________

/// An iterator over enum declarations.
#[allow(missing_debug_implementations)]
pub struct Enums<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Enums<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Enums<'tu> {
        Enums { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Enums<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        next(&mut self.entities, &mut self.seen, EntityKind::EnumDecl, "enum ")
    }
}

// Functions _____________________________________

/// An iterator over function declarations.
#[allow(missing_debug_implementations)]
pub struct Functions<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Functions<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Functions<'tu> {
        Functions { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Functions<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        for entity in &mut self.entities {
            if entity.get_kind() == EntityKind::FunctionDecl {
                let name = entity.get_name().unwrap();
                if !self.seen.contains(&name) {
                    self.seen.insert(name.clone());
                    return Some(Declaration::new(name, entity, None));
                }
            }
        }
        None
    }
}

// Structs _______________________________________

/// An iterator over struct declarations.
#[allow(missing_debug_implementations)]
pub struct Structs<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Structs<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Structs<'tu> {
        Structs { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Structs<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        next(&mut self.entities, &mut self.seen, EntityKind::StructDecl, "struct ")
    }
}

// Typedefs ______________________________________

/// An iterator over typedef declarations.
#[allow(missing_debug_implementations)]
pub struct Typedefs<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Typedefs<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Typedefs<'tu> {
        Typedefs { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Typedefs<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        for entity in &mut self.entities {
            if entity.get_kind() == EntityKind::TypedefDecl {
                let name = entity.get_name().unwrap();
                if !self.seen.contains(&name) {
                    let underlying = entity.get_typedef_underlying_type().unwrap();
                    let display = entity.get_type().unwrap().get_display_name();

                    let typedef = underlying.get_kind() != TypeKind::Unexposed ||
                        underlying.get_result_type().is_some() ||
                        is_alias(underlying, &display);

                    if typedef {
                        self.seen.insert(name.clone());
                        return Some(Declaration::new(name, entity, None));
                    }
                }
            }
        }
        None
    }
}

// Unions ________________________________________

/// An iterator over struct declarations.
#[allow(missing_debug_implementations)]
pub struct Unions<'tu> {
    entities: vec::IntoIter<Entity<'tu>>,
    seen: HashSet<String>,
}

impl<'tu> Unions<'tu> {
    //- Constructors -----------------------------

    fn new(entities: vec::IntoIter<Entity<'tu>>) -> Unions<'tu> {
        Unions { entities: entities, seen: HashSet::new() }
    }
}

impl<'tu> Iterator for Unions<'tu> {
    type Item = Declaration<'tu>;

    fn next(&mut self) -> Option<Declaration<'tu>> {
        next(&mut self.entities, &mut self.seen, EntityKind::UnionDecl, "union ")
    }
}

//================================================
// Functions
//================================================

fn is(type_: Type, prefix: &str) -> bool {
    type_.get_kind() == TypeKind::Unexposed && type_.get_display_name().starts_with(prefix)
}

fn is_alias(type_: Type, name: &str) -> bool {
    for prefix in &["enum ", "struct ", "union "] {
        let display = type_.get_display_name();

        if display.starts_with(prefix) && &display[prefix.len()..] != name {
            return true;
        }
    }

    false
}

fn next<'tu>(
    entities: &mut vec::IntoIter<Entity<'tu>>,
    seen: &mut HashSet<String>,
    kind: EntityKind,
    prefix: &str,
) -> Option<Declaration<'tu>> {
    for entity in entities {
        if entity.get_kind() == kind {
            if let Some(name) = entity.get_name() {
                if !seen.contains(&name) {
                    seen.insert(name);
                    if entity.get_type().map_or(false, |t| t.get_sizeof().is_ok()) {
                        return Some(Declaration::new(entity.get_name().unwrap(), entity, None));
                    }
                }
            }
        } else if entity.get_kind() == EntityKind::TypedefDecl {
            let underlying = entity.get_typedef_underlying_type().unwrap();
            let name = entity.get_name().unwrap();

            if is(underlying, prefix) && !seen.contains(&name) {
                let declaration = underlying.get_declaration().unwrap();

                let complete = declaration.get_type().map_or(false, |t| t.get_sizeof().is_ok());
                let anonymous = declaration.get_display_name().is_none();
                let same = entity.get_display_name() == declaration.get_display_name();

                seen.insert(name);
                if complete && (anonymous || same) {
                    let name = entity.get_name().unwrap();
                    return Some(Declaration::new(name, declaration, Some(entity)));
                }
            }
        }
    }
    None
}

/// Returns an iterator over the simple preprocessor definitions in the supplied entities.
///
/// Simple preprocessor definitions are those that consist only of a single integer or floating
/// point literal, optionally negated.
///
/// If a preprocessor definition is encountered multiple times, only the first instance is included.
pub fn find_definitions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Definitions<'tu> {
    Definitions::new(entities.into().into_iter())
}

/// Returns an iterator over the enums in the supplied entities.
///
/// If an enum is encountered multiple times, only the first instance is included.
pub fn find_enums<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Enums<'tu> {
    Enums::new(entities.into().into_iter())
}

/// Returns an iterator over the functions in the supplied entities.
///
/// If a function is encountered multiple times, only the first instance is included.
pub fn find_functions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Functions<'tu> {
    Functions::new(entities.into().into_iter())
}

/// Returns an iterator over the structs in the supplied entities.
///
/// If a struct is encountered multiple times, only the first instance is included.
pub fn find_structs<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Structs<'tu> {
    Structs::new(entities.into().into_iter())
}

/// Returns an iterator over the typedefs in the supplied entities.
///
/// If a typedef is encountered multiple times, only the first instance is included.
pub fn find_typedefs<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Typedefs<'tu> {
    Typedefs::new(entities.into().into_iter())
}

/// Returns an iterator over the unions in the supplied entities.
///
/// If a union is encountered multiple times, only the first instance is included.
pub fn find_unions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Unions<'tu> {
    Unions::new(entities.into().into_iter())
}
<|endoftext|>


<commit_before>use ::CanSocket;

#[test]
fn test_nonexistant_device() {
    assert!(CanSocket::open("invalid").is_err());
}

#[cfg(feature = "vcan_tests")]
mod vcan_tests {
    use ::CanSocket;
    use std::time;
    use ::ShouldRetry;

    #[test]
    fn vcan0_timeout() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_read_timeout(time::Duration::from_millis(100)).unwrap();
        assert!(cs.read_frame().should_retry());
    }

    #[test]
    fn vcan0_set_error_mask() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.error_filter_drop_all().unwrap();
        cs.error_filter_accept_all().unwrap();
    }
}
<commit_msg>Fix error masking code.<commit_after>use ::CanSocket;

#[test]
fn test_nonexistant_device() {
    assert!(CanSocket::open("invalid").is_err());
}

#[cfg(feature = "vcan_tests")]
mod vcan_tests {
    use ::{CanSocket, ERR_MASK_ALL, ERR_MASK_NONE};
    use std::time;
    use ::ShouldRetry;

    #[test]
    fn vcan0_timeout() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_read_timeout(time::Duration::from_millis(100)).unwrap();
        assert!(cs.read_frame().should_retry());
    }

    #[test]
    fn vcan0_set_error_mask() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_error_mask(ERR_MASK_ALL).unwrap();
        cs.set_error_mask(ERR_MASK_NONE).unwrap();
    }
}
<|endoftext|>


<commit_before>use {AtomicDateTime, Run, Time, TimerPhase, TimingMethod, TimeStamp, TimeSpan, Segment};
use TimerPhase::*;
use run::PERSONAL_BEST_COMPARISON_NAME;
use parking_lot::RwLock;
use std::sync::Arc;

#[derive(Debug, Clone)]
pub struct Timer {
    run: Run,
    phase: TimerPhase,
    current_split_index: isize,
    current_timing_method: TimingMethod,
    current_comparison: String,
    attempt_started: Option<AtomicDateTime>,
    attempt_ended: Option<AtomicDateTime>,
    adjusted_start_time: TimeStamp,
    // Invariant: Offset isn't allowed to change during a run.
    // The Duration of the Attempt relies on it not changing.
    /// Stores the Time Stamp the timer started at adjusted by the run offset.
    start_time: TimeStamp,
    time_paused_at: TimeSpan,
    is_game_time_paused: bool,
    game_time_pause_time: Option<TimeSpan>,
    loading_times: Option<TimeSpan>,
}

pub type SharedTimer = Arc<RwLock<Timer>>;

impl Timer {
    #[inline]
    pub fn new(mut run: Run) -> Self {
        assert!(run.len() > 0);

        run.regenerate_comparisons();
        let now = TimeStamp::now();

        Timer {
            run: run,
            phase: NotRunning,
            current_split_index: -1,
            current_timing_method: TimingMethod::RealTime,
            current_comparison: PERSONAL_BEST_COMPARISON_NAME.into(),
            attempt_started: None,
            attempt_ended: None,
            adjusted_start_time: now,
            start_time: now,
            time_paused_at: TimeSpan::zero(),
            is_game_time_paused: false,
            game_time_pause_time: None,
            loading_times: None,
        }
    }

    pub fn into_shared(self) -> SharedTimer {
        Arc::new(RwLock::new(self))
    }

    #[inline]
    pub fn run(&self) -> &Run {
        &self.run
    }

    #[inline]
    pub fn current_phase(&self) -> TimerPhase {
        self.phase
    }

    pub fn current_time(&self) -> Time {
        let real_time = match self.phase {
            NotRunning => Some(self.run.offset()),
            Running => Some(TimeStamp::now() - self.adjusted_start_time),
            Paused => Some(self.time_paused_at),
            Ended => {
                self.run
                    .segments()
                    .last()
                    .unwrap()
                    .split_time()
                    .real_time
            }
        };

        let game_time = match self.phase {
            NotRunning => Some(self.run.offset()),
            Ended => {
                self.run
                    .segments()
                    .last()
                    .unwrap()
                    .split_time()
                    .game_time
            }
            _ => {
                if self.is_game_time_paused() {
                    self.game_time_pause_time
                } else {
                    TimeSpan::option_op(real_time,
                                        if self.is_game_time_initialized() {
                                            Some(self.loading_times())
                                        } else {
                                            None
                                        },
                                        |a, b| a - b)
                }
            }
        };

        Time::new()
            .with_real_time(real_time)
            .with_game_time(game_time)
    }

    #[inline]
    pub fn current_timing_method(&self) -> TimingMethod {
        self.current_timing_method
    }

    #[inline]
    pub fn set_current_timing_method(&mut self, method: TimingMethod) {
        self.current_timing_method = method;
    }

    #[inline]
    pub fn current_comparison(&self) -> &str {
        &self.current_comparison
    }

    pub fn current_split(&self) -> Option<&Segment> {
        if self.current_split_index >= 0 {
            self.run
                .segments()
                .get(self.current_split_index as usize)
        } else {
            None
        }
    }

    fn current_split_mut(&mut self) -> Option<&mut Segment> {
        if self.current_split_index >= 0 {
            self.run
                .segments_mut()
                .get_mut(self.current_split_index as usize)
        } else {
            None
        }
    }

    #[inline]
    pub fn current_split_index(&self) -> isize {
        self.current_split_index
    }

    pub fn split(&mut self) {
        if self.phase == NotRunning {
            self.phase = Running;
            self.current_split_index = 0;
            self.attempt_started = Some(AtomicDateTime::now());
            self.adjusted_start_time = TimeStamp::now() - self.run.offset();
            self.start_time = self.adjusted_start_time;
            self.time_paused_at = self.run.offset();
            self.uninitialize_game_time();
            self.run.start_next_run();

            // TODO OnStart
        } else {
            let current_time = self.current_time();
            if self.phase == Running &&
               current_time
                   .real_time
                   .map_or(false, |t| t >= TimeSpan::zero()) {
                self.current_split_mut()
                    .unwrap()
                    .set_split_time(current_time);
                self.current_split_index += 1;
                if self.run.len() as isize == self.current_split_index {
                    self.phase = Ended;
                    self.attempt_ended = Some(AtomicDateTime::now());
                }
                self.run.mark_as_changed();

                // TODO OnSplit
            }
        }
    }

    pub fn skip_split(&mut self) {
        if (self.phase == Running || self.phase == Paused) &&
           self.current_split_index < self.run.len() as isize - 1 {
            self.current_split_mut().unwrap().clear_split_time();
            self.current_split_index += 1;
            self.run.mark_as_changed();

            // TODO OnSkipSplit
        }
    }

    pub fn undo_split(&mut self) {
        if self.phase != NotRunning && self.current_split_index > 0 {
            if self.phase == Ended {
                self.phase = Running;
            }
            self.current_split_index -= 1;
            self.current_split_mut().unwrap().clear_split_time();
            self.run.mark_as_changed();

            // TODO OnUndoSplit
        }
    }

    pub fn reset(&mut self, update_splits: bool) {
        if self.phase != NotRunning {
            if self.phase != Ended {
                self.attempt_ended = Some(AtomicDateTime::now());
            }
            self.unpause_game_time();
            self.set_loading_times(TimeSpan::zero());

            if update_splits {
                self.update_attempt_history();
                self.update_best_segments();
                self.update_pb_splits();
                self.update_segment_history();
            }

            self.reset_splits();
            self.run.fix_splits();
            self.run.regenerate_comparisons();
        }
    }

    fn reset_splits(&mut self) {
        self.phase = NotRunning;
        self.current_split_index = -1;

        // Reset Splits
        for segment in self.run.segments_mut() {
            segment.clear_split_time();
        }

        // TODO OnReset
    }

    pub fn pause(&mut self) {
        match self.phase {
            Running => {
                self.time_paused_at = self.current_time().real_time.unwrap();
                self.phase = Paused;

                // TODO OnPause
            }
            Paused => {
                self.adjusted_start_time = TimeStamp::now() - self.time_paused_at;
                self.phase = Running;

                // TODO OnResume
            }
            NotRunning => self.split(), // Fuck abahbob
            _ => {}
        }
    }

    pub fn undo_all_pauses(&mut self) {
        match self.current_phase() {
            Paused => self.pause(),
            Ended => {
                let pause_time = Some(self.get_pause_time().unwrap_or_default());

                let split_time = self.run
                    .segments_mut()
                    .iter_mut()
                    .last()
                    .unwrap()
                    .split_time_mut();

                *split_time += Time::new()
                    .with_real_time(pause_time)
                    .with_game_time(pause_time);
            }
            _ => {}
        }

        self.adjusted_start_time = self.start_time;

        // TODO OnUndoAllPauses
    }

    pub fn switch_to_next_comparison(&mut self) {
        let mut comparisons = self.run.comparisons();
        let len = comparisons.len();
        let index = comparisons
            .position(|c| c == self.current_comparison)
            .unwrap();
        let index = (index + 1) % len;
        self.current_comparison = self.run.comparisons().nth(index).unwrap().to_owned();

        // TODO OnNextComparison
    }

    pub fn switch_to_previous_comparison(&mut self) {
        let mut comparisons = self.run.comparisons();
        let len = comparisons.len();
        let index = comparisons
            .position(|c| c == self.current_comparison)
            .unwrap();
        let index = (index + len - 1) % len;
        self.current_comparison = self.run.comparisons().nth(index).unwrap().to_owned();

        // TODO OnPreviousComparison
    }

    pub fn current_attempt_duration(&self) -> TimeSpan {
        match self.current_phase() {
            NotRunning => TimeSpan::zero(),
            Paused | Running => TimeStamp::now() - self.start_time - self.run.offset(),
            Ended => {
                self.run
                    .segments()
                    .last()
                    .unwrap()
                    .split_time()
                    .real_time
                    .unwrap()
            }
        }
    }

    pub fn get_pause_time(&self) -> Option<TimeSpan> {
        if self.current_phase() == Paused {
            Some(self.current_attempt_duration() - self.time_paused_at)
        } else if self.start_time != self.adjusted_start_time {
            Some(self.adjusted_start_time - self.start_time)
        } else {
            None
        }
    }

    #[inline]
    pub fn is_game_time_initialized(&self) -> bool {
        self.loading_times.is_some()
    }

    #[inline]
    pub fn initialize_game_time(&mut self) {
        self.loading_times = Some(self.loading_times());
    }

    #[inline]
    pub fn uninitialize_game_time(&mut self) {
        self.loading_times = None;
    }

    #[inline]
    pub fn is_game_time_paused(&self) -> bool {
        self.is_game_time_paused
    }

    pub fn pause_game_time(&mut self) {
        if !self.is_game_time_paused() {
            let current_time = self.current_time();
            self.game_time_pause_time = current_time.game_time.or(current_time.real_time);
            self.is_game_time_paused = true;
        }
    }

    pub fn unpause_game_time(&mut self) {
        if self.is_game_time_paused() {
            let current_time = self.current_time();
            self.set_loading_times(TimeSpan::option_op(current_time.real_time,
                                                       current_time.game_time,
                                                       |r, g| r - g)
                                           .unwrap_or_default());
            self.is_game_time_paused = false;
        }
    }

    #[inline]
    pub fn set_game_time(&mut self, game_time: TimeSpan) {
        if self.is_game_time_paused() {
            self.game_time_pause_time = Some(game_time);
        }
        let loading_times = self.current_time().real_time.unwrap() - game_time;
        self.loading_times = Some(loading_times);
    }

    #[inline]
    pub fn loading_times(&self) -> TimeSpan {
        self.loading_times.unwrap_or_default()
    }

    #[inline]
    pub fn set_loading_times(&mut self, time: TimeSpan) {
        self.loading_times = Some(time);
        if self.is_game_time_paused() {
            self.game_time_pause_time = Some(self.current_time().real_time.unwrap() - time);
        }
    }

    fn update_attempt_history(&mut self) {
        let (time, pause_time) = if self.phase == Ended {
            (self.current_time(), self.get_pause_time())
        } else {
            Default::default()
        };
        self.run
            .add_attempt(time, self.attempt_started, self.attempt_ended, pause_time);
    }

    fn update_best_segments(&mut self) {
        let mut previous_split_time_rta = Some(TimeSpan::zero());
        let mut previous_split_time_game_time = Some(TimeSpan::zero());

        for split in self.run.segments_mut() {
            let mut new_best_segment = split.best_segment_time();
            if let Some(split_time) = split.split_time().real_time {
                let current_segment = previous_split_time_rta.map(|previous| split_time - previous);
                previous_split_time_rta = Some(split_time);
                if split
                       .best_segment_time()
                       .real_time
                       .map_or(true, |b| current_segment.map_or(false, |c| c < b)) {
                    new_best_segment.real_time = current_segment;
                }
            }
            if let Some(split_time) = split.split_time().game_time {
                let current_segment =
                    previous_split_time_game_time.map(|previous| split_time - previous);
                previous_split_time_game_time = Some(split_time);
                if split
                       .best_segment_time()
                       .game_time
                       .map_or(true, |b| current_segment.map_or(false, |c| c < b)) {
                    new_best_segment.game_time = current_segment;
                }
            }
            split.set_best_segment_time(new_best_segment);
        }
    }

    fn update_pb_splits(&mut self) {
        let method = self.current_timing_method;
        let (split_time, pb_split_time) = {
            let last_segment = self.run.segments().last().unwrap();
            (last_segment.split_time()[method], last_segment.personal_best_split_time()[method])
        };
        if split_time.map_or(false, |s| pb_split_time.map_or(true, |pb| s < pb)) {
            self.set_run_as_pb();
        }
    }

    fn update_segment_history(&mut self) {
        self.run.update_segment_history(self.current_split_index);
    }

    fn set_run_as_pb(&mut self) {
        self.run.import_segment_history();
        self.run.fix_splits();
        for segment in self.run.segments_mut() {
            let split_time = segment.split_time();
            segment.set_personal_best_split_time(split_time);
        }
    }
}
<commit_msg>Fix Current Attempt Duration and Pause Time<commit_after>use {AtomicDateTime, Run, Time, TimerPhase, TimingMethod, TimeStamp, TimeSpan, Segment};
use TimerPhase::*;
use run::PERSONAL_BEST_COMPARISON_NAME;
use parking_lot::RwLock;
use std::sync::Arc;

#[derive(Debug, Clone)]
pub struct Timer {
    run: Run,
    phase: TimerPhase,
    current_split_index: isize,
    current_timing_method: TimingMethod,
    current_comparison: String,
    attempt_started: Option<AtomicDateTime>,
    attempt_ended: Option<AtomicDateTime>,
    adjusted_start_time: TimeStamp,
    // Invariant: Offset isn't allowed to change during a run.
    // The Duration of the Attempt relies on it not changing.
    /// Stores the Time Stamp the timer started at adjusted by the run offset.
    start_time: TimeStamp,
    time_paused_at: TimeSpan,
    is_game_time_paused: bool,
    game_time_pause_time: Option<TimeSpan>,
    loading_times: Option<TimeSpan>,
}

pub type SharedTimer = Arc<RwLock<Timer>>;

impl Timer {
    #[inline]
    pub fn new(mut run: Run) -> Self {
        assert!(run.len() > 0);

        run.regenerate_comparisons();
        let now = TimeStamp::now();

        Timer {
            run: run,
            phase: NotRunning,
            current_split_index: -1,
            current_timing_method: TimingMethod::RealTime,
            current_comparison: PERSONAL_BEST_COMPARISON_NAME.into(),
            attempt_started: None,
            attempt_ended: None,
            adjusted_start_time: now,
            start_time: now,
            time_paused_at: TimeSpan::zero(),
            is_game_time_paused: false,
            game_time_pause_time: None,
            loading_times: None,
        }
    }

    pub fn into_shared(self) -> SharedTimer {
        Arc::new(RwLock::new(self))
    }

    #[inline]
    pub fn run(&self) -> &Run {
        &self.run
    }

    #[inline]
    pub fn current_phase(&self) -> TimerPhase {
        self.phase
    }

    pub fn current_time(&self) -> Time {
        let real_time = match self.phase {
            NotRunning => Some(self.run.offset()),
            Running => Some(TimeStamp::now() - self.adjusted_start_time),
            Paused => Some(self.time_paused_at),
            Ended => {
                self.run
                    .segments()
                    .last()
                    .unwrap()
                    .split_time()
                    .real_time
            }
        };

        let game_time = match self.phase {
            NotRunning => Some(self.run.offset()),
            Ended => {
                self.run
                    .segments()
                    .last()
                    .unwrap()
                    .split_time()
                    .game_time
            }
            _ => {
                if self.is_game_time_paused() {
                    self.game_time_pause_time
                } else {
                    TimeSpan::option_op(real_time,
                                        if self.is_game_time_initialized() {
                                            Some(self.loading_times())
                                        } else {
                                            None
                                        },
                                        |a, b| a - b)
                }
            }
        };

        Time::new()
            .with_real_time(real_time)
            .with_game_time(game_time)
    }

    #[inline]
    pub fn current_timing_method(&self) -> TimingMethod {
        self.current_timing_method
    }

    #[inline]
    pub fn set_current_timing_method(&mut self, method: TimingMethod) {
        self.current_timing_method = method;
    }

    #[inline]
    pub fn current_comparison(&self) -> &str {
        &self.current_comparison
    }

    pub fn current_split(&self) -> Option<&Segment> {
        if self.current_split_index >= 0 {
            self.run
                .segments()
                .get(self.current_split_index as usize)
        } else {
            None
        }
    }

    fn current_split_mut(&mut self) -> Option<&mut Segment> {
        if self.current_split_index >= 0 {
            self.run
                .segments_mut()
                .get_mut(self.current_split_index as usize)
        } else {
            None
        }
    }

    #[inline]
    pub fn current_split_index(&self) -> isize {
        self.current_split_index
    }

    pub fn split(&mut self) {
        if self.phase == NotRunning {
            self.phase = Running;
            self.current_split_index = 0;
            self.attempt_started = Some(AtomicDateTime::now());
            self.adjusted_start_time = TimeStamp::now() - self.run.offset();
            self.start_time = self.adjusted_start_time;
            self.time_paused_at = self.run.offset();
            self.uninitialize_game_time();
            self.run.start_next_run();

            // TODO OnStart
        } else {
            let current_time = self.current_time();
            if self.phase == Running &&
               current_time
                   .real_time
                   .map_or(false, |t| t >= TimeSpan::zero()) {
                self.current_split_mut()
                    .unwrap()
                    .set_split_time(current_time);
                self.current_split_index += 1;
                if self.run.len() as isize == self.current_split_index {
                    self.phase = Ended;
                    self.attempt_ended = Some(AtomicDateTime::now());
                }
                self.run.mark_as_changed();

                // TODO OnSplit
            }
        }
    }

    pub fn skip_split(&mut self) {
        if (self.phase == Running || self.phase == Paused) &&
           self.current_split_index < self.run.len() as isize - 1 {
            self.current_split_mut().unwrap().clear_split_time();
            self.current_split_index += 1;
            self.run.mark_as_changed();

            // TODO OnSkipSplit
        }
    }

    pub fn undo_split(&mut self) {
        if self.phase != NotRunning && self.current_split_index > 0 {
            if self.phase == Ended {
                self.phase = Running;
            }
            self.current_split_index -= 1;
            self.current_split_mut().unwrap().clear_split_time();
            self.run.mark_as_changed();

            // TODO OnUndoSplit
        }
    }

    pub fn reset(&mut self, update_splits: bool) {
        if self.phase != NotRunning {
            if self.phase != Ended {
                self.attempt_ended = Some(AtomicDateTime::now());
            }
            self.unpause_game_time();
            self.set_loading_times(TimeSpan::zero());

            if update_splits {
                self.update_attempt_history();
                self.update_best_segments();
                self.update_pb_splits();
                self.update_segment_history();
            }

            self.reset_splits();
            self.run.fix_splits();
            self.run.regenerate_comparisons();
        }
    }

    fn reset_splits(&mut self) {
        self.phase = NotRunning;
        self.current_split_index = -1;

        // Reset Splits
        for segment in self.run.segments_mut() {
            segment.clear_split_time();
        }

        // TODO OnReset
    }

    pub fn pause(&mut self) {
        match self.phase {
            Running => {
                self.time_paused_at = self.current_time().real_time.unwrap();
                self.phase = Paused;

                // TODO OnPause
            }
            Paused => {
                self.adjusted_start_time = TimeStamp::now() - self.time_paused_at;
                self.phase = Running;

                // TODO OnResume
            }
            NotRunning => self.split(), // Fuck abahbob
            _ => {}
        }
    }

    pub fn undo_all_pauses(&mut self) {
        match self.current_phase() {
            Paused => self.pause(),
            Ended => {
                let pause_time = Some(self.get_pause_time().unwrap_or_default());

                let split_time = self.run
                    .segments_mut()
                    .iter_mut()
                    .last()
                    .unwrap()
                    .split_time_mut();

                *split_time += Time::new()
                    .with_real_time(pause_time)
                    .with_game_time(pause_time);
            }
            _ => {}
        }

        self.adjusted_start_time = self.start_time;

        // TODO OnUndoAllPauses
    }

    pub fn switch_to_next_comparison(&mut self) {
        let mut comparisons = self.run.comparisons();
        let len = comparisons.len();
        let index = comparisons
            .position(|c| c == self.current_comparison)
            .unwrap();
        let index = (index + 1) % len;
        self.current_comparison = self.run.comparisons().nth(index).unwrap().to_owned();

        // TODO OnNextComparison
    }

    pub fn switch_to_previous_comparison(&mut self) {
        let mut comparisons = self.run.comparisons();
        let len = comparisons.len();
        let index = comparisons
            .position(|c| c == self.current_comparison)
            .unwrap();
        let index = (index + len - 1) % len;
        self.current_comparison = self.run.comparisons().nth(index).unwrap().to_owned();

        // TODO OnPreviousComparison
    }

    pub fn current_attempt_duration(&self) -> TimeSpan {
        match self.current_phase() {
            NotRunning => TimeSpan::zero(),
            Paused | Running => TimeStamp::now() - self.start_time - self.run.offset(),
            Ended => self.attempt_ended.unwrap() - self.attempt_started.unwrap(),
        }
    }

    pub fn get_pause_time(&self) -> Option<TimeSpan> {
        if self.current_phase() == Paused {
            Some(TimeStamp::now() - self.start_time - self.time_paused_at)
        } else if self.start_time != self.adjusted_start_time {
            Some(self.adjusted_start_time - self.start_time)
        } else {
            None
        }
    }

    #[inline]
    pub fn is_game_time_initialized(&self) -> bool {
        self.loading_times.is_some()
    }

    #[inline]
    pub fn initialize_game_time(&mut self) {
        self.loading_times = Some(self.loading_times());
    }

    #[inline]
    pub fn uninitialize_game_time(&mut self) {
        self.loading_times = None;
    }

    #[inline]
    pub fn is_game_time_paused(&self) -> bool {
        self.is_game_time_paused
    }

    pub fn pause_game_time(&mut self) {
        if !self.is_game_time_paused() {
            let current_time = self.current_time();
            self.game_time_pause_time = current_time.game_time.or(current_time.real_time);
            self.is_game_time_paused = true;
        }
    }

    pub fn unpause_game_time(&mut self) {
        if self.is_game_time_paused() {
            let current_time = self.current_time();
            self.set_loading_times(TimeSpan::option_op(current_time.real_time,
                                                       current_time.game_time,
                                                       |r, g| r - g)
                                           .unwrap_or_default());
            self.is_game_time_paused = false;
        }
    }

    #[inline]
    pub fn set_game_time(&mut self, game_time: TimeSpan) {
        if self.is_game_time_paused() {
            self.game_time_pause_time = Some(game_time);
        }
        let loading_times = self.current_time().real_time.unwrap() - game_time;
        self.loading_times = Some(loading_times);
    }

    #[inline]
    pub fn loading_times(&self) -> TimeSpan {
        self.loading_times.unwrap_or_default()
    }

    #[inline]
    pub fn set_loading_times(&mut self, time: TimeSpan) {
        self.loading_times = Some(time);
        if self.is_game_time_paused() {
            self.game_time_pause_time = Some(self.current_time().real_time.unwrap() - time);
        }
    }

    fn update_attempt_history(&mut self) {
        let (time, pause_time) = if self.phase == Ended {
            (self.current_time(), self.get_pause_time())
        } else {
            Default::default()
        };
        self.run
            .add_attempt(time, self.attempt_started, self.attempt_ended, pause_time);
    }

    fn update_best_segments(&mut self) {
        let mut previous_split_time_rta = Some(TimeSpan::zero());
        let mut previous_split_time_game_time = Some(TimeSpan::zero());

        for split in self.run.segments_mut() {
            let mut new_best_segment = split.best_segment_time();
            if let Some(split_time) = split.split_time().real_time {
                let current_segment = previous_split_time_rta.map(|previous| split_time - previous);
                previous_split_time_rta = Some(split_time);
                if split
                       .best_segment_time()
                       .real_time
                       .map_or(true, |b| current_segment.map_or(false, |c| c < b)) {
                    new_best_segment.real_time = current_segment;
                }
            }
            if let Some(split_time) = split.split_time().game_time {
                let current_segment =
                    previous_split_time_game_time.map(|previous| split_time - previous);
                previous_split_time_game_time = Some(split_time);
                if split
                       .best_segment_time()
                       .game_time
                       .map_or(true, |b| current_segment.map_or(false, |c| c < b)) {
                    new_best_segment.game_time = current_segment;
                }
            }
            split.set_best_segment_time(new_best_segment);
        }
    }

    fn update_pb_splits(&mut self) {
        let method = self.current_timing_method;
        let (split_time, pb_split_time) = {
            let last_segment = self.run.segments().last().unwrap();
            (last_segment.split_time()[method], last_segment.personal_best_split_time()[method])
        };
        if split_time.map_or(false, |s| pb_split_time.map_or(true, |pb| s < pb)) {
            self.set_run_as_pb();
        }
    }

    fn update_segment_history(&mut self) {
        self.run.update_segment_history(self.current_split_index);
    }

    fn set_run_as_pb(&mut self) {
        self.run.import_segment_history();
        self.run.fix_splits();
        for segment in self.run.segments_mut() {
            let split_time = segment.split_time();
            segment.set_personal_best_split_time(split_time);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
#![allow(improper_ctypes)]

use std::slice;
use std::os::raw::c_char;

#[repr(C)]
pub struct mpc_state_t
{
    pub pos: i64,
    pub row: i64,
    pub col: i64,
}

#[repr(C)]
pub struct mpc_ast_t
{
    pub tag: *mut c_char,
    pub contents: *mut c_char,
    pub state: mpc_state_t,
    pub children_num: i32,
    pub children: *const *const mpc_ast_t,
}

#[repr(C)]
pub struct vector;

//TODO map structs to C

#[repr(C)]
pub struct module
{
    pub name: *mut c_char,
    pub imports: *mut vector,
    pub functions: *mut vector,
    pub types: *mut vector,
}

#[repr(C)]
pub struct import
{
    pub name: *mut c_char,
    pub alias: *mut c_char,
    pub local: bool,
    pub w_alias: bool,
}

#[repr(C)]
pub struct function
{
    pub name: *mut c_char,
    pub public : bool,
    pub param_count : i32,
    pub params: *mut vector,
    pub ret_type: symbol_type,
}

#[repr(C)]
pub struct param
{
    pub p_type: symbol_type,
    pub name: *mut c_char,
}

#[repr(C)]
pub struct symbol_type
{
    pub name: *mut c_char,
    pub indirection: i32,
    pub constant: bool,
    pub volatile: bool,
}

#[repr(C)]
pub struct user_type
{
    pub name: *mut c_char,
    pub t_type: type_kind,
}

#[repr(C)]
pub enum type_kind
{
    ALIAS,
    STRUCT,
    ENUM,
}

impl mpc_ast_t
{
    pub unsafe fn get_children(&self) -> &'static[*const mpc_ast_t]
    {
        slice::from_raw_parts(self.children, self.children_num as usize)
    }
}
<commit_msg>add more fields to enums and structs in types.rs<commit_after>#![allow(unused_variables)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
#![allow(improper_ctypes)]

use std::slice;
use std::os::raw::c_char;

#[repr(C)]
pub struct mpc_state_t
{
    pub pos: i64,
    pub row: i64,
    pub col: i64,
}

#[repr(C)]
pub struct mpc_ast_t
{
    pub tag: *mut c_char,
    pub contents: *mut c_char,
    pub state: mpc_state_t,
    pub children_num: i32,
    pub children: *const *const mpc_ast_t,
}

#[repr(C)]
pub struct vector;

//TODO map structs to C

#[repr(C)]
pub struct module
{
    pub name: *mut c_char,
    pub imports: *mut vector,
    pub functions: *mut vector,
    pub types: *mut vector,
}

#[repr(C)]
pub struct import
{
    pub name: *mut c_char,
    pub alias: *mut c_char,
    pub local: bool,
    pub w_alias: bool,
}

#[repr(C)]
pub struct function
{
    pub name: *mut c_char,
    pub public : bool,
    pub param_count : i32,
    pub params: *mut vector,
    pub ret_type: symbol_type,
}

#[repr(C)]
pub struct param
{
    pub p_type: symbol_type,
    pub name: *mut c_char,
}

#[repr(C)]
pub struct symbol_type
{
    pub name: *mut c_char,
    pub indirection: i32,
    pub constant: bool,
    pub volatile: bool,
}

#[repr(C)]
pub struct user_type
{
    pub name: *mut c_char,
    pub t_type: type_kind,
    pub public: bool,
}

#[repr(C)]
pub enum type_kind
{
    ALIAS,
    STRUCT,
    UNION,
    ENUM,
    FUNC,
    TEMP
}

impl mpc_ast_t
{
    pub unsafe fn get_children(&self) -> &'static[*const mpc_ast_t]
    {
        slice::from_raw_parts(self.children, self.children_num as usize)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
//! Traits for loading/saving Registry values
extern crate winapi;
pub use winapi::{HKEY_CLASSES_ROOT,
                 HKEY_CURRENT_USER,
                 HKEY_LOCAL_MACHINE,
                 HKEY_USERS,
                 HKEY_PERFORMANCE_DATA,
                 HKEY_PERFORMANCE_TEXT,
                 HKEY_PERFORMANCE_NLSTEXT,
                 HKEY_CURRENT_CONFIG,
                 HKEY_DYN_DATA,
                 HKEY_CURRENT_USER_LOCAL_SETTINGS};
pub use winapi::{KEY_QUERY_VALUE,
                 KEY_SET_VALUE,
                 KEY_CREATE_SUB_KEY,
                 KEY_ENUMERATE_SUB_KEYS,
                 KEY_NOTIFY,
                 KEY_CREATE_LINK,
                 KEY_WOW64_32KEY,
                 KEY_WOW64_64KEY,
                 KEY_WOW64_RES,
                 KEY_READ,
                 KEY_WRITE,
                 KEY_EXECUTE,
                 KEY_ALL_ACCESS};
pub use winapi::{REG_NONE,
                 REG_SZ,
                 REG_EXPAND_SZ,
                 REG_BINARY,
                 REG_DWORD,
                 REG_DWORD_LITTLE_ENDIAN,
                 REG_DWORD_BIG_ENDIAN,
                 REG_LINK,
                 REG_MULTI_SZ,
                 REG_RESOURCE_LIST,
                 REG_FULL_RESOURCE_DESCRIPTOR,
                 REG_RESOURCE_REQUIREMENTS_LIST,
                 REG_QWORD,
                 REG_QWORD_LITTLE_ENDIAN};
use super::{RegError,RegResult,RegValue};
use super::{to_utf16,v16_to_v8};

/// A trait for types that can be loaded from registry values.
pub trait FromReg {
    fn convert_from_bytes(val: &RegValue) -> RegResult<Self>;
}

impl FromReg for String {
    fn convert_from_bytes(val: &RegValue) -> RegResult<String> {
        match val.vtype {
            REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
                let words = unsafe {
                    let pwords = val.bytes.as_ptr() as *mut [u16; 2048 as usize];
                    *pwords
                };
                match String::from_utf16(&words[..(val.bytes.len()/2)]) {
                    Ok(mut s) => {
                        s.pop(); // remove trailing \0
                        if val.vtype == REG_MULTI_SZ {
                            return Ok(s.replace("\u{0}", "\n"))
                        }
                        Ok(s)
                    },
                    Err(_) => Err(RegError{ err: winapi::ERROR_INVALID_BLOCK })
                }
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

impl FromReg for u32 {
    fn convert_from_bytes(val: &RegValue) -> RegResult<u32> {
        match val.vtype {
            REG_DWORD => {
                Ok(unsafe{ *(val.bytes.as_ptr() as *const u32) })
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

impl FromReg for u64 {
    fn convert_from_bytes(val: &RegValue) -> RegResult<u64> {
        match val.vtype {
            REG_QWORD => {
                Ok(unsafe{ *(val.bytes.as_ptr() as *const u64) })
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

/// A trait for types that can be written into registry values.
pub trait ToReg {
    fn convert_to_bytes(&self) -> RegValue;
}

impl ToReg for String {
    fn convert_to_bytes(&self) -> RegValue {
        RegValue{
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ
        }
    }
}

impl<'a> ToReg for &'a str {
    fn convert_to_bytes(&self) -> RegValue {
        RegValue{
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ
        }
    }
}

impl ToReg for u32 {
    fn convert_to_bytes(&self) -> RegValue {
        let bytes: Vec<u8> = unsafe {
            Vec::from_raw_buf((self as *const u32) as *const u8, 4)
        };
        RegValue{
            bytes: bytes,
            vtype: REG_DWORD
        }
    }
}

impl ToReg for u64 {
    fn convert_to_bytes(&self) -> RegValue {
        let bytes: Vec<u8> = unsafe {
            Vec::from_raw_buf((self as *const u64) as *const u8, 8)
        };
        RegValue{
            bytes: bytes,
            vtype: REG_QWORD
        }
    }
}
<commit_msg>Use String::from_utf16_lossy<commit_after>// Copyright 2015, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
//! Traits for loading/saving Registry values
extern crate winapi;
pub use winapi::{HKEY_CLASSES_ROOT,
                 HKEY_CURRENT_USER,
                 HKEY_LOCAL_MACHINE,
                 HKEY_USERS,
                 HKEY_PERFORMANCE_DATA,
                 HKEY_PERFORMANCE_TEXT,
                 HKEY_PERFORMANCE_NLSTEXT,
                 HKEY_CURRENT_CONFIG,
                 HKEY_DYN_DATA,
                 HKEY_CURRENT_USER_LOCAL_SETTINGS};
pub use winapi::{KEY_QUERY_VALUE,
                 KEY_SET_VALUE,
                 KEY_CREATE_SUB_KEY,
                 KEY_ENUMERATE_SUB_KEYS,
                 KEY_NOTIFY,
                 KEY_CREATE_LINK,
                 KEY_WOW64_32KEY,
                 KEY_WOW64_64KEY,
                 KEY_WOW64_RES,
                 KEY_READ,
                 KEY_WRITE,
                 KEY_EXECUTE,
                 KEY_ALL_ACCESS};
pub use winapi::{REG_NONE,
                 REG_SZ,
                 REG_EXPAND_SZ,
                 REG_BINARY,
                 REG_DWORD,
                 REG_DWORD_LITTLE_ENDIAN,
                 REG_DWORD_BIG_ENDIAN,
                 REG_LINK,
                 REG_MULTI_SZ,
                 REG_RESOURCE_LIST,
                 REG_FULL_RESOURCE_DESCRIPTOR,
                 REG_RESOURCE_REQUIREMENTS_LIST,
                 REG_QWORD,
                 REG_QWORD_LITTLE_ENDIAN};
use super::{RegError,RegResult,RegValue};
use super::{to_utf16,v16_to_v8};

/// A trait for types that can be loaded from registry values.
pub trait FromReg {
    fn convert_from_bytes(val: &RegValue) -> RegResult<Self>;
}

impl FromReg for String {
    fn convert_from_bytes(val: &RegValue) -> RegResult<String> {
        match val.vtype {
            REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
                let words = unsafe {
                    let pwords = val.bytes.as_ptr() as *mut [u16; 2048 as usize];
                    *pwords
                };
                let mut s:String = String::from_utf16_lossy(&words[..(val.bytes.len()/2)]);
                s.pop(); // remove trailing \0
                if val.vtype == REG_MULTI_SZ {
                    return Ok(s.replace("\u{0}", "\n"))
                }
                Ok(s)
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

impl FromReg for u32 {
    fn convert_from_bytes(val: &RegValue) -> RegResult<u32> {
        match val.vtype {
            REG_DWORD => {
                Ok(unsafe{ *(val.bytes.as_ptr() as *const u32) })
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

impl FromReg for u64 {
    fn convert_from_bytes(val: &RegValue) -> RegResult<u64> {
        match val.vtype {
            REG_QWORD => {
                Ok(unsafe{ *(val.bytes.as_ptr() as *const u64) })
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

/// A trait for types that can be written into registry values.
pub trait ToReg {
    fn convert_to_bytes(&self) -> RegValue;
}

impl ToReg for String {
    fn convert_to_bytes(&self) -> RegValue {
        RegValue{
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ
        }
    }
}

impl<'a> ToReg for &'a str {
    fn convert_to_bytes(&self) -> RegValue {
        RegValue{
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ
        }
    }
}

impl ToReg for u32 {
    fn convert_to_bytes(&self) -> RegValue {
        let bytes: Vec<u8> = unsafe {
            Vec::from_raw_buf((self as *const u32) as *const u8, 4)
        };
        RegValue{
            bytes: bytes,
            vtype: REG_DWORD
        }
    }
}

impl ToReg for u64 {
    fn convert_to_bytes(&self) -> RegValue {
        let bytes: Vec<u8> = unsafe {
            Vec::from_raw_buf((self as *const u64) as *const u8, 8)
        };
        RegValue{
            bytes: bytes,
            vtype: REG_QWORD
        }
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io::BufReader;
use std::io::Result;
use std::fs::File;
use std::option::Option;

#[derive(Debug, Clone)]
pub struct User {
    pub username: String,
    pub phone_number: Option<String>,
    pub slack_username: Option<String>
}

pub fn read_users(path: String) -> Result<Vec<User>> {
    let f = try!(File::open(path));
    let reader = BufReader::new(f);
    let mut users: Vec<User> = Vec::new();

    for line in reader.lines() {
        let line = try!(line);
        match parse_user(&line) {
            Some(user) => { users.push(user) },
            None => { warn!("Invalid user line: {}", line); }
        }
    }
    info!("Read {} users", users.len());
    return Ok(users);
}

fn parse_user(line: &str) -> Option<User> {
    let parts: Vec<String> = line.split(",").map( |s| s.to_owned() ).collect();
    let username = parts.get(0);

    if username.is_none() || username.unwrap().is_empty() {
        return None;
    }

    let phone_number = match parts.get(1) {
        Some(number) => Some(number.to_owned()),
        None => None
    };
    let slack_username = match parts.get(2) {
        Some(number) => Some(number.to_owned()),
        None => None
    };

    if phone_number.is_some() || slack_username.is_some() {
        return Some(User {
            username: username.unwrap().to_owned(),
            phone_number: phone_number,
            slack_username: slack_username
        });
    } else {
        return None;
    }
}

#[test]
fn test_parse_user() {
    let line = "patrickod,+16507017829,patrickod".to_string();
    let user = parse_user(line).unwrap();

    assert_eq!(user.username, "patrickod".to_string());
    assert_eq!(user.slack_username.unwrap(), "patrickod".to_string());
    assert_eq!(user.phone_number.unwrap(), "+16507017829".to_string());
}

#[test]
fn test_parse_empty_user() {
    let line = "".to_string();
    assert!(parse_user(line).is_none());
}

#[test]
fn test_parse_user_username_only() {
    let line = "patrickod".to_string();
    assert!(parse_user(line).is_none());
}
<commit_msg>Fix user tests<commit_after>use std::io::prelude::*;
use std::io::BufReader;
use std::io::Result;
use std::fs::File;
use std::option::Option;

#[derive(Debug, Clone)]
pub struct User {
    pub username: String,
    pub phone_number: Option<String>,
    pub slack_username: Option<String>
}

pub fn read_users(path: String) -> Result<Vec<User>> {
    let f = try!(File::open(path));
    let reader = BufReader::new(f);
    let mut users: Vec<User> = Vec::new();

    for line in reader.lines() {
        let line = try!(line);
        match parse_user(&line) {
            Some(user) => { users.push(user) },
            None => { warn!("Invalid user line: {}", line); }
        }
    }
    info!("Read {} users", users.len());
    return Ok(users);
}

fn parse_user(line: &str) -> Option<User> {
    let parts: Vec<String> = line.split(",").map( |s| s.to_owned() ).collect();
    let username = parts.get(0);

    if username.is_none() || username.unwrap().is_empty() {
        return None;
    }

    let phone_number = match parts.get(1) {
        Some(number) => Some(number.to_owned()),
        None => None
    };
    let slack_username = match parts.get(2) {
        Some(number) => Some(number.to_owned()),
        None => None
    };

    if phone_number.is_some() || slack_username.is_some() {
        return Some(User {
            username: username.unwrap().to_owned(),
            phone_number: phone_number,
            slack_username: slack_username
        });
    } else {
        return None;
    }
}

#[test]
fn test_parse_user() {
    let line = "patrickod,+16507017829,patrickod";
    let user = parse_user(line).unwrap();

    assert_eq!(user.username, "patrickod".to_string());
    assert_eq!(user.slack_username.unwrap(), "patrickod".to_string());
    assert_eq!(user.phone_number.unwrap(), "+16507017829".to_string());
}

#[test]
fn test_parse_empty_user() {
    let line = "";
    assert!(parse_user(line).is_none());
}

#[test]
fn test_parse_user_username_only() {
    let line = "patrickod";
    assert!(parse_user(line).is_none());
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{CString, OsString};
use std::os::unix::ffi::OsStringExt;
use std::ptr;

use libc;

fn osstring2cstring(s: &OsString) -> CString {
    unsafe { CString::from_vec_unchecked(s.clone().into_vec()) }
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<&OsString>) {
    let mut args = Vec::new();
    for arg in &argv {
        args.push(osstring2cstring(arg).as_ptr());
    }
    args.push(ptr::null());
    assert!(unsafe { libc::execvp(args[0], args.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

fn which(exec: &str) -> Option<OsString> {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            let candidate = path.join(exec);
            if path.join(exec).exists() {
                return Some(candidate.into_os_string());
            }
        }
    }
    None
}

pub fn find_pager(env: &str) -> Option<OsString> {
    if env::var_os("NOPAGER").is_some() {
        return None
    }
    let default_pager = || which("more");
    env::var_os(env).or_else(default_pager)
}

#[cfg(test)]
mod tests {
    use super::{find_pager, which};
    use std::ffi::OsString;

    #[cfg(target_os = "linux")]
    const MORE: &'static str = "/bin/more";

    #[cfg(target_os = "macos")]
    const MORE: &'static str = "/usr/bin/more";

    #[test]
    fn more_found_in_path() {
        assert!(which("more").is_some())
    }

    #[test]
    fn erom_not_found_in_path() {
        assert!(which("erom").is_none())
    }

    #[test]
    fn which_more() {
        assert_eq!(which("more"), Some(OsString::from(MORE)));
    }

    #[test]
    fn usr_bin_more_default_pager() {
        assert_eq!(find_pager("__RANDOM_NAME"), Some(OsString::from(MORE)));
    }
}
<commit_msg>args array always has at least 2 elements<commit_after>use std::env;
use std::ffi::{CString, OsString};
use std::os::unix::ffi::OsStringExt;
use std::ptr;

use libc;

fn osstring2cstring(s: &OsString) -> CString {
    unsafe { CString::from_vec_unchecked(s.clone().into_vec()) }
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<&OsString>) {
    let mut args = Vec::with_capacity(2);
    for arg in &argv {
        args.push(osstring2cstring(arg).as_ptr());
    }
    args.push(ptr::null());
    assert!(unsafe { libc::execvp(args[0], args.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

fn which(exec: &str) -> Option<OsString> {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            let candidate = path.join(exec);
            if path.join(exec).exists() {
                return Some(candidate.into_os_string());
            }
        }
    }
    None
}

pub fn find_pager(env: &str) -> Option<OsString> {
    if env::var_os("NOPAGER").is_some() {
        return None
    }
    let default_pager = || which("more");
    env::var_os(env).or_else(default_pager)
}

#[cfg(test)]
mod tests {
    use super::{find_pager, which};
    use std::ffi::OsString;

    #[cfg(target_os = "linux")]
    const MORE: &'static str = "/bin/more";

    #[cfg(target_os = "macos")]
    const MORE: &'static str = "/usr/bin/more";

    #[test]
    fn more_found_in_path() {
        assert!(which("more").is_some())
    }

    #[test]
    fn erom_not_found_in_path() {
        assert!(which("erom").is_none())
    }

    #[test]
    fn which_more() {
        assert_eq!(which("more"), Some(OsString::from(MORE)));
    }

    #[test]
    fn usr_bin_more_default_pager() {
        assert_eq!(find_pager("__RANDOM_NAME"), Some(OsString::from(MORE)));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std::env;
use std::fs::File;
use std::path::PathBuf;
use std::io::prelude::*;
use chrono::{UTC, DateTime, TimeZone};
use std::time::{UNIX_EPOCH, SystemTime};
use response::{ToOutput, Response};
use request::Request;

/// Convenience method for creating a response from the basic components
/// required (a request body, content type, and response status).
///
/// # Examples
///
/// ```rust
/// use canteen::{Request, Response};
/// use canteen::utils;
///
/// fn handler(_: &Request) -> Response {
///     utils::make_response("Hello, world!", "text/plain", 200)
/// }
/// ```
pub fn make_response<T: ToOutput>(body: T, c_type: &str, status: u16) -> Response {
    let mut res = Response::new();

    res.set_status(status);
    res.set_content_type(c_type);
    res.append(body);

    res
}

/// Converts std::time::SystemTime to chrono::DateTime<UTC>
///
/// Code from: https://users.rust-lang.org/t/convert-std-time-systemtime-to-chrono-datetime-datetime/7684/4
fn _conv_systemtime(t: SystemTime) -> DateTime<UTC> {
    let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
        Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
        Err(e) => {
            let dur = e.duration();
            let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());

            if nsec == 0 {
                (-sec, 0)
            } else {
                (-sec - 1, 1_000_000_000 - nsec)
            }
        },
    };

    UTC.timestamp(sec, nsec)
}

/// Replace the URI escape codes with their ASCII equivalents.
pub fn replace_escape(path: &str) -> String {
    let mut fixed = String::from(path);
    let replaces: [(&str, &str); 175] = [
        ("%20", " "),
        ("%21", "!"),
        ("%22", "\""),
        ("%23", "#"),
        ("%24", "$"),
        ("%25", "%"),
        ("%26", "&"),
        ("%27", "'"),
        ("%28", "("),
        ("%29", ")"),
        ("%2A", "*"),
        ("%2B", "+"),
        ("%2C", ","),
        ("%2D", "-"),
        ("%2E", "."),
        ("%2F", "/"),
        ("%30", "0"),
        ("%31", "1"),
        ("%32", "2"),
        ("%33", "3"),
        ("%34", "4"),
        ("%35", "5"),
        ("%36", "6"),
        ("%37", "7"),
        ("%38", "8"),
        ("%39", "9"),
        ("%3A", ":"),
        ("%3B", ";"),
        ("%3C", "<"),
        ("%3D", "="),
        ("%3E", ">"),
        ("%3F", "?"),
        ("%40", "@"),
        ("%41", "A"),
        ("%42", "B"),
        ("%43", "C"),
        ("%44", "D"),
        ("%45", "E"),
        ("%46", "F"),
        ("%47", "G"),
        ("%48", "H"),
        ("%49", "I"),
        ("%4A", "J"),
        ("%4B", "K"),
        ("%4C", "L"),
        ("%4D", "M"),
        ("%4E", "N"),
        ("%4F", "O"),
        ("%50", "P"),
        ("%51", "Q"),
        ("%52", "R"),
        ("%53", "S"),
        ("%54", "T"),
        ("%55", "U"),
        ("%56", "V"),
        ("%57", "W"),
        ("%58", "X"),
        ("%59", "Y"),
        ("%5A", "Z"),
        ("%5B", "["),
        ("%5C", "\\"),
        ("%5D", "]"),
        ("%5E", "^"),
        ("%5F", "_"),
        ("%60", "`"),
        ("%61", "a"),
        ("%62", "b"),
        ("%63", "c"),
        ("%64", "d"),
        ("%65", "e"),
        ("%66", "f"),
        ("%67", "g"),
        ("%68", "h"),
        ("%69", "i"),
        ("%6A", "j"),
        ("%6B", "k"),
        ("%6C", "l"),
        ("%6D", "m"),
        ("%6E", "n"),
        ("%6F", "o"),
        ("%70", "p"),
        ("%71", "q"),
        ("%72", "r"),
        ("%73", "s"),
        ("%74", "t"),
        ("%75", "u"),
        ("%76", "v"),
        ("%77", "w"),
        ("%78", "x"),
        ("%79", "y"),
        ("%7A", "z"),
        ("%7B", "{"),
        ("%7C", "|"),
        ("%7D", "}"),
        ("%7E", "~"),
        ("%A2", "¢"),
        ("%A3", "£"),
        ("%A5", "¥"),
        ("%A6", "|"),
        ("%A7", "§"),
        ("%AB", "«"),
        ("%AC", "¬"),
        ("%AD", "¯"),
        ("%B0", "º"),
        ("%B1", "±"),
        ("%B2", "ª"),
        ("%B4", ","),
        ("%B5", "µ"),
        ("%BB", "»"),
        ("%BC", "¼"),
        ("%BD", "½"),
        ("%BF", "¿"),
        ("%C0", "À"),
        ("%C1", "Á"),
        ("%C2", "Â"),
        ("%C3", "Ã"),
        ("%C4", "Ä"),
        ("%C5", "Å"),
        ("%C6", "Æ"),
        ("%C7", "Ç"),
        ("%C8", "È"),
        ("%C9", "É"),
        ("%CA", "Ê"),
        ("%CB", "Ë"),
        ("%CC", "Ì"),
        ("%CD", "Í"),
        ("%CE", "Î"),
        ("%CF", "Ï"),
        ("%D0", "Ð"),
        ("%D1", "Ñ"),
        ("%D2", "Ò"),
        ("%D3", "Ó"),
        ("%D4", "Ô"),
        ("%D5", "Õ"),
        ("%D6", "Ö"),
        ("%D8", "Ø"),
        ("%D9", "Ù"),
        ("%DA", "Ú"),
        ("%DB", "Û"),
        ("%DC", "Ü"),
        ("%DD", "Ý"),
        ("%DE", "Þ"),
        ("%DF", "ß"),
        ("%E0", "à"),
        ("%E1", "á"),
        ("%E2", "â"),
        ("%E3", "ã"),
        ("%E4", "ä"),
        ("%E5", "å"),
        ("%E6", "æ"),
        ("%E7", "ç"),
        ("%E8", "è"),
        ("%E9", "é"),
        ("%EA", "ê"),
        ("%EB", "ë"),
        ("%EC", "ì"),
        ("%ED", "í"),
        ("%EE", "î"),
        ("%EF", "ï"),
        ("%F0", "ð"),
        ("%F1", "ñ"),
        ("%F2", "ò"),
        ("%F3", "ó"),
        ("%F4", "ô"),
        ("%F5", "õ"),
        ("%F6", "ö"),
        ("%F7", "÷"),
        ("%F8", "ø"),
        ("%F9", "ù"),
        ("%FA", "ú"),
        ("%FB", "û"),
        ("%FC", "ü"),
        ("%FD", "ý"),
        ("%FE", "þ"),
        ("%FF", "ÿ"),
    ];

    if !fixed.contains("%") {
        return fixed;
    }

    for &(from, to) in replaces.iter() {
        fixed = fixed.replace(from, to);
    }

    fixed
}

fn err_body(message: &str, path: &str) -> String {
    format!("\
             \

Your request failed

{}: {}
", message, path)
}

/// Default handler function for HTTP 403 errors.
pub fn err_403(req: &Request) -> Response {
    make_response(err_body("forbidden", &req.path), "text/html", 403)
}

/// Default handler function for HTTP 403 errors for XHR.
pub fn err_403_json(message: &str) -> Response {
    make_response(format!("{{ message: 'forbidden: {}' }}", message), "application/json", 403)
}

/// Default handler function for HTTP 404 errors.
pub fn err_404(req: &Request) -> Response {
    make_response(err_body("not found", &req.path), "text/html", 404)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_404_json(message: &str) -> Response {
    make_response(format!("{{ message: 'not found: {}' }}", message), "application/json", 404)
}

/// Default handler function for HTTP 500 errors.
pub fn err_500(req: &Request) -> Response {
    make_response(err_body("internal server error", &req.path), "text/html", 500)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_500_json(message: &str) -> Response {
    make_response(format!("{{ message: 'internal server error: {}' }}", message), "application/json", 500)
}

/// Handler that sends static files relative to the current working directory.
pub fn static_file(req: &Request) -> Response {
    let mut res = Response::new();

    let cwd = env::current_dir().unwrap();
    let clean = replace_escape(&req.path);
    let mut fpath = PathBuf::from(&cwd);
    let mut fbuf: Vec<u8> = Vec::new();

    for chunk in clean.split('/') {
        if chunk == "" || chunk == "." || chunk == ".." {
            /* bzzzzt */
            continue;
        }

        fpath.push(&chunk);
    }

    let file = File::open(&fpath);

    match file {
        Ok(mut f)   => {
            let last = match f.metadata() {
                Err(_)  => UTC::now(),
                Ok(md)  => {
                    match md.modified() {
                        Err(_)  => UTC::now(), // should never happen...
                        Ok(st)  => _conv_systemtime(st),
                    }
                }
            };

            if let Some(hdr) = req.get_header("If-Modified-Since") {
                if let Ok(dt_utc) = UTC.datetime_from_str(&hdr, "%a, %d %b %Y, %H:%M:%S UTC") {
                    if dt_utc >= last {
                        // it hasn't been modified, return a 304
                        res.set_status(304);
                        return res;
                    }
                }
            }

            match f.read_to_end(&mut fbuf) {
                Ok(_)   => {
                    res.add_header("Last-Modified", &last.format("%a, %d %b %Y, %H:%M:%S %Z").to_string());
                    res.set_status(200);
                    res.set_content_type("text/plain");
                    res.append(fbuf);
                },
                Err(_)  => {
                    return err_500(&req);
                },
            }
        },
        Err(_)      => {
            return err_404(&req);
        }
    }

    res
}

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

    #[test]
    fn test_replace_escape() {
        let path = "%61%62%63%64%65%66%67%68%69%6A%6B%6C%6D%6E%6F%70%71%72%73%74%75%76%77%78%79%7A";
        assert_eq!("abcdefghijklmnopqrstuvwxyz", replace_escape(&path));
    }
}
<commit_msg>add a test for utils::_conv_systemtime<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std::env;
use std::fs::File;
use std::path::PathBuf;
use std::io::prelude::*;
use chrono::{UTC, DateTime, TimeZone};
use std::time::{UNIX_EPOCH, SystemTime};
use response::{ToOutput, Response};
use request::Request;

/// Convenience method for creating a response from the basic components
/// required (a request body, content type, and response status).
///
/// # Examples
///
/// ```rust
/// use canteen::{Request, Response};
/// use canteen::utils;
///
/// fn handler(_: &Request) -> Response {
///     utils::make_response("Hello, world!", "text/plain", 200)
/// }
/// ```
pub fn make_response<T: ToOutput>(body: T, c_type: &str, status: u16) -> Response {
    let mut res = Response::new();

    res.set_status(status);
    res.set_content_type(c_type);
    res.append(body);

    res
}

/// Converts std::time::SystemTime to chrono::DateTime<UTC>
///
/// Code from: https://users.rust-lang.org/t/convert-std-time-systemtime-to-chrono-datetime-datetime/7684/4
pub fn _conv_systemtime(t: SystemTime) -> DateTime<UTC> {
    let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
        Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
        Err(e) => {
            let dur = e.duration();
            let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());

            if nsec == 0 {
                (-sec, 0)
            } else {
                (-sec - 1, 1_000_000_000 - nsec)
            }
        },
    };

    UTC.timestamp(sec, nsec)
}

/// Replace the URI escape codes with their ASCII equivalents.
pub fn replace_escape(path: &str) -> String {
    let mut fixed = String::from(path);
    let replaces: [(&str, &str); 175] = [
        ("%20", " "),
        ("%21", "!"),
        ("%22", "\""),
        ("%23", "#"),
        ("%24", "$"),
        ("%25", "%"),
        ("%26", "&"),
        ("%27", "'"),
        ("%28", "("),
        ("%29", ")"),
        ("%2A", "*"),
        ("%2B", "+"),
        ("%2C", ","),
        ("%2D", "-"),
        ("%2E", "."),
        ("%2F", "/"),
        ("%30", "0"),
        ("%31", "1"),
        ("%32", "2"),
        ("%33", "3"),
        ("%34", "4"),
        ("%35", "5"),
        ("%36", "6"),
        ("%37", "7"),
        ("%38", "8"),
        ("%39", "9"),
        ("%3A", ":"),
        ("%3B", ";"),
        ("%3C", "<"),
        ("%3D", "="),
        ("%3E", ">"),
        ("%3F", "?"),
        ("%40", "@"),
        ("%41", "A"),
        ("%42", "B"),
        ("%43", "C"),
        ("%44", "D"),
        ("%45", "E"),
        ("%46", "F"),
        ("%47", "G"),
        ("%48", "H"),
        ("%49", "I"),
        ("%4A", "J"),
        ("%4B", "K"),
        ("%4C", "L"),
        ("%4D", "M"),
        ("%4E", "N"),
        ("%4F", "O"),
        ("%50", "P"),
        ("%51", "Q"),
        ("%52", "R"),
        ("%53", "S"),
        ("%54", "T"),
        ("%55", "U"),
        ("%56", "V"),
        ("%57", "W"),
        ("%58", "X"),
        ("%59", "Y"),
        ("%5A", "Z"),
        ("%5B", "["),
        ("%5C", "\\"),
        ("%5D", "]"),
        ("%5E", "^"),
        ("%5F", "_"),
        ("%60", "`"),
        ("%61", "a"),
        ("%62", "b"),
        ("%63", "c"),
        ("%64", "d"),
        ("%65", "e"),
        ("%66", "f"),
        ("%67", "g"),
        ("%68", "h"),
        ("%69", "i"),
        ("%6A", "j"),
        ("%6B", "k"),
        ("%6C", "l"),
        ("%6D", "m"),
        ("%6E", "n"),
        ("%6F", "o"),
        ("%70", "p"),
        ("%71", "q"),
        ("%72", "r"),
        ("%73", "s"),
        ("%74", "t"),
        ("%75", "u"),
        ("%76", "v"),
        ("%77", "w"),
        ("%78", "x"),
        ("%79", "y"),
        ("%7A", "z"),
        ("%7B", "{"),
        ("%7C", "|"),
        ("%7D", "}"),
        ("%7E", "~"),
        ("%A2", "¢"),
        ("%A3", "£"),
        ("%A5", "¥"),
        ("%A6", "|"),
        ("%A7", "§"),
        ("%AB", "«"),
        ("%AC", "¬"),
        ("%AD", "¯"),
        ("%B0", "º"),
        ("%B1", "±"),
        ("%B2", "ª"),
        ("%B4", ","),
        ("%B5", "µ"),
        ("%BB", "»"),
        ("%BC", "¼"),
        ("%BD", "½"),
        ("%BF", "¿"),
        ("%C0", "À"),
        ("%C1", "Á"),
        ("%C2", "Â"),
        ("%C3", "Ã"),
        ("%C4", "Ä"),
        ("%C5", "Å"),
        ("%C6", "Æ"),
        ("%C7", "Ç"),
        ("%C8", "È"),
        ("%C9", "É"),
        ("%CA", "Ê"),
        ("%CB", "Ë"),
        ("%CC", "Ì"),
        ("%CD", "Í"),
        ("%CE", "Î"),
        ("%CF", "Ï"),
        ("%D0", "Ð"),
        ("%D1", "Ñ"),
        ("%D2", "Ò"),
        ("%D3", "Ó"),
        ("%D4", "Ô"),
        ("%D5", "Õ"),
        ("%D6", "Ö"),
        ("%D8", "Ø"),
        ("%D9", "Ù"),
        ("%DA", "Ú"),
        ("%DB", "Û"),
        ("%DC", "Ü"),
        ("%DD", "Ý"),
        ("%DE", "Þ"),
        ("%DF", "ß"),
        ("%E0", "à"),
        ("%E1", "á"),
        ("%E2", "â"),
        ("%E3", "ã"),
        ("%E4", "ä"),
        ("%E5", "å"),
        ("%E6", "æ"),
        ("%E7", "ç"),
        ("%E8", "è"),
        ("%E9", "é"),
        ("%EA", "ê"),
        ("%EB", "ë"),
        ("%EC", "ì"),
        ("%ED", "í"),
        ("%EE", "î"),
        ("%EF", "ï"),
        ("%F0", "ð"),
        ("%F1", "ñ"),
        ("%F2", "ò"),
        ("%F3", "ó"),
        ("%F4", "ô"),
        ("%F5", "õ"),
        ("%F6", "ö"),
        ("%F7", "÷"),
        ("%F8", "ø"),
        ("%F9", "ù"),
        ("%FA", "ú"),
        ("%FB", "û"),
        ("%FC", "ü"),
        ("%FD", "ý"),
        ("%FE", "þ"),
        ("%FF", "ÿ"),
    ];

    if !fixed.contains("%") {
        return fixed;
    }

    for &(from, to) in replaces.iter() {
        fixed = fixed.replace(from, to);
    }

    fixed
}

fn err_body(message: &str, path: &str) -> String {
    format!("\
             \

Your request failed

{}: {}
", message, path)
}

/// Default handler function for HTTP 403 errors.
pub fn err_403(req: &Request) -> Response {
    make_response(err_body("forbidden", &req.path), "text/html", 403)
}

/// Default handler function for HTTP 403 errors for XHR.
pub fn err_403_json(message: &str) -> Response {
    make_response(format!("{{ message: 'forbidden: {}' }}", message), "application/json", 403)
}

/// Default handler function for HTTP 404 errors.
pub fn err_404(req: &Request) -> Response {
    make_response(err_body("not found", &req.path), "text/html", 404)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_404_json(message: &str) -> Response {
    make_response(format!("{{ message: 'not found: {}' }}", message), "application/json", 404)
}

/// Default handler function for HTTP 500 errors.
pub fn err_500(req: &Request) -> Response {
    make_response(err_body("internal server error", &req.path), "text/html", 500)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_500_json(message: &str) -> Response {
    make_response(format!("{{ message: 'internal server error: {}' }}", message), "application/json", 500)
}

/// Handler that sends static files relative to the current working directory.
pub fn static_file(req: &Request) -> Response {
    let mut res = Response::new();

    let cwd = env::current_dir().unwrap();
    let clean = replace_escape(&req.path);
    let mut fpath = PathBuf::from(&cwd);
    let mut fbuf: Vec<u8> = Vec::new();

    for chunk in clean.split('/') {
        if chunk == "" || chunk == "." || chunk == ".." {
            /* bzzzzt */
            continue;
        }

        fpath.push(&chunk);
    }

    let file = File::open(&fpath);

    match file {
        Ok(mut f)   => {
            let last = match f.metadata() {
                Err(_)  => UTC::now(),
                Ok(md)  => {
                    match md.modified() {
                        Err(_)  => UTC::now(), // should never happen...
                        Ok(st)  => _conv_systemtime(st),
                    }
                }
            };

            if let Some(hdr) = req.get_header("If-Modified-Since") {
                if let Ok(dt_utc) = UTC.datetime_from_str(&hdr, "%a, %d %b %Y, %H:%M:%S UTC") {
                    if dt_utc >= last {
                        // it hasn't been modified, return a 304
                        res.set_status(304);
                        return res;
                    }
                }
            }

            match f.read_to_end(&mut fbuf) {
                Ok(_)   => {
                    res.add_header("Last-Modified", &last.format("%a, %d %b %Y, %H:%M:%S %Z").to_string());
                    res.set_status(200);
                    res.set_content_type("text/plain");
                    res.append(fbuf);
                },
                Err(_)  => {
                    return err_500(&req);
                },
            }
        },
        Err(_)      => {
            return err_404(&req);
        }
    }

    res
}

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::{UTC, TimeZone};
    use std::time::UNIX_EPOCH;

    #[test]
    fn test_replace_escape() {
        let path = "%61%62%63%64%65%66%67%68%69%6A%6B%6C%6D%6E%6F%70%71%72%73%74%75%76%77%78%79%7A";
        assert_eq!("abcdefghijklmnopqrstuvwxyz", replace_escape(&path));
    }

    #[test]
    fn test_conv_systemtime() {
        assert_eq!(_conv_systemtime(UNIX_EPOCH), UTC.timestamp(0, 0));
    }
}
<|endoftext|>