<commit_before>//! Checks that all error codes have at least one test to prevent having error
//! codes that are silently not thrown by the compiler anymore.

use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::read_to_string;
use std::path::Path;

use regex::Regex;

// A few of those error codes can't be tested but all the others can and *should* be tested!
const EXEMPTED_FROM_TEST: &[&str] = &[
    "E0227", "E0279", "E0280", "E0313", "E0314", "E0315", "E0377", "E0461", "E0462", "E0464",
    "E0465", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", "E0481", "E0482", "E0483",
    "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", "E0519", "E0523", "E0553",
    "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0729",
];

// Some error codes don't have any tests apparently...
const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];

#[derive(Default, Debug)]
struct ErrorCodeStatus {
    has_test: bool,
    has_explanation: bool,
    is_used: bool,
}

fn check_error_code_explanation(
    f: &str,
    error_codes: &mut HashMap<String, ErrorCodeStatus>,
    err_code: String,
) -> bool {
    let mut invalid_compile_fail_format = false;
    let mut found_error_code = false;

    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("```") {
            if s.contains("compile_fail") && s.contains('E') {
                if !found_error_code {
                    error_codes.get_mut(&err_code).map(|x| x.has_test = true);
                    found_error_code = true;
                }
            } else if s.contains("compile-fail") {
                invalid_compile_fail_format = true;
            }
        } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
            if !found_error_code {
                error_codes.get_mut(&err_code).map(|x| x.has_test = true);
                found_error_code = true;
            }
        }
    }
    invalid_compile_fail_format
}

fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &str) -> bool {
    let mut ignore_found = false;

    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
            return true;
        }
        if s.starts_with("```") {
            if s.contains("compile_fail") && s.contains(err_code) {
                return true;
            } else if s.contains("ignore") {
                // It's very likely that we can't actually make it fail compilation...
                ignore_found = true;
            }
        }
    }
    ignore_found
}

macro_rules! some_or_continue {
    ($e:expr) => {
        match $e {
            Some(e) => e,
            None => continue,
        }
    };
}

fn extract_error_codes(
    f: &str,
    error_codes: &mut HashMap<String, ErrorCodeStatus>,
    path: &Path,
    errors: &mut Vec<String>,
) {
    let mut reached_no_explanation = false;

    for line in f.lines() {
        let s = line.trim();
        if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") {
            let err_code = s
                .split_once(':')
                .expect(
                    format!(
                        "Expected a line with the format `E0xxx: include_str!(\"..\")`, but got {} \
                         without a `:` delimiter",
                        s,
                    )
                    .as_str(),
                )
                .0
                .to_owned();
            match error_codes.entry(err_code.clone()) {
                Entry::Occupied(mut e) => {
                    let mut entry = e.get_mut();
                    entry.has_explanation = true
                }
                Entry::Vacant(e) => {
                    e.insert(ErrorCodeStatus {
                        has_test: false,
                        is_used: false,
                        has_explanation: true,
                    });
                }
            }
            // Now we extract the tests from the markdown file!
            let md_file_name = match s.split_once("include_str!(\"") {
                None => continue,
                Some((_, md)) => match md.split_once("\")") {
                    None => continue,
                    Some((file_name, _)) => file_name,
                },
            };
            let path = some_or_continue!(path.parent())
                .join(md_file_name)
                .canonicalize()
                .expect("failed to canonicalize error explanation file path");
            match read_to_string(&path) {
                Ok(content) => {
                    let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
                    if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                        errors.push(format!(
                            "`{}` doesn't use its own error code in compile_fail example",
                            path.display(),
                        ));
                    } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                        errors.push(format!(
                            "`{}` has a compile_fail example with its own error code, it shouldn't \
                             be listed in IGNORE_EXPLANATION_CHECK!",
                            path.display(),
                        ));
                    }
                    if check_error_code_explanation(&content, error_codes, err_code) {
                        errors.push(format!(
                            "`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
                            path.display(),
                        ));
                    }
                }
                Err(e) => {
                    eprintln!("Couldn't read `{}`: {}", path.display(), e);
                }
            }
        } else if reached_no_explanation && s.starts_with('E') {
            let err_code = match s.split_once(',') {
                None => s,
                Some((err_code, _)) => err_code,
            }
            .to_string();
            if !error_codes.contains_key(&err_code) {
                // this check should *never* fail!
                error_codes.insert(err_code, ErrorCodeStatus::default());
            }
        } else if s == ";" {
            reached_no_explanation = true;
        }
    }
}

fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, ErrorCodeStatus>) {
    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("error[E") || s.starts_with("warning[E") {
            let err_code = match s.split_once(']') {
                None => continue,
                Some((err_code, _)) => match err_code.split_once('[') {
                    None => continue,
                    Some((_, err_code)) => err_code,
                },
            };
            match error_codes.entry(err_code.to_owned()) {
                Entry::Occupied(mut e) => {
                    let mut entry = e.get_mut();
                    entry.has_test = true
                }
                Entry::Vacant(e) => {
                    e.insert(ErrorCodeStatus {
                        has_test: true,
                        is_used: false,
                        has_explanation: false,
                    });
                }
            }
        }
    }
}

fn extract_error_codes_from_source(
    f: &str,
    error_codes: &mut HashMap<String, ErrorCodeStatus>,
    regex: &Regex,
) {
    for line in f.lines() {
        if line.trim_start().starts_with("//") {
            continue;
        }
        for cap in regex.captures_iter(line) {
            if let Some(error_code) = cap.get(1) {
                match error_codes.entry(error_code.as_str().to_owned()) {
                    Entry::Occupied(mut e) => {
                        let mut entry = e.get_mut();
                        entry.is_used = true
                    }
                    Entry::Vacant(e) => {
                        e.insert(ErrorCodeStatus {
                            has_test: false,
                            is_used: true,
                            has_explanation: false,
                        });
                    }
                }
            }
        }
    }
}

pub fn check(paths: &[&Path], bad: &mut bool) {
    let mut errors = Vec::new();
    let mut found_explanations = 0;
    let mut found_tests = 0;
    let mut error_codes: HashMap<String, ErrorCodeStatus> = HashMap::new();
    // We want error codes which match the following cases:
    //
    // * foo(a, E0111, a)
    // * foo(a, E0111)
    // * foo(E0111, a)
    // * #[error = "E0111"]
    let regex = Regex::new(r#"[(,"\s](E\d{4})[,)"]"#).unwrap();

    println!("Checking which error codes lack tests...");

    for path in paths {
        super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| {
            let file_name = entry.file_name();
            if file_name == "error_codes.rs" {
                extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
                found_explanations += 1;
            } else if entry.path().extension() == Some(OsStr::new("stderr")) {
                extract_error_codes_from_tests(contents, &mut error_codes);
                found_tests += 1;
            } else if entry.path().extension() == Some(OsStr::new("rs")) {
                let path = entry.path().to_string_lossy();
                if ["src/test/", "src/doc/", "src/tools/"].iter().all(|c| !path.contains(c)) {
                    extract_error_codes_from_source(contents, &mut error_codes, &regex);
                }
            }
        });
    }
    if found_explanations == 0 {
        eprintln!("No error code explanation was tested!");
        *bad = true;
    }
    if found_tests == 0 {
        eprintln!("No error code was found in compilation errors!");
        *bad = true;
    }
    if errors.is_empty() {
        println!("Found {} error codes", error_codes.len());

        for (err_code, error_status) in &error_codes {
            if !error_status.has_test && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
            } else if error_status.has_test && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                errors.push(format!(
                    "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
                    err_code
                ));
            }
            if !error_status.is_used && !error_status.has_explanation {
                errors.push(format!(
                    "Error code {} isn't used and doesn't have an error explanation, it should be \
                     commented in error_codes.rs file",
                    err_code
                ));
            }
        }
    }
    errors.sort();
    for err in &errors {
        eprintln!("{}", err);
    }
    println!("Found {} error codes with no tests", errors.len());
    if !errors.is_empty() {
        *bad = true;
    }
    println!("Done!");
}
<commit_msg>Add check on constant to ensure it's up to date<commit_after>//! Checks that all error codes have at least one test to prevent having error
//! codes that are silently not thrown by the compiler anymore.

use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::read_to_string;
use std::path::Path;

use regex::Regex;

// A few of those error codes can't be tested but all the others can and *should* be tested!
const EXEMPTED_FROM_TEST: &[&str] = &[
    "E0227", "E0279", "E0280", "E0313", "E0315", "E0377", "E0461", "E0462", "E0464", "E0465",
    "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", "E0481", "E0482", "E0483", "E0484",
    "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", "E0519", "E0523", "E0554", "E0570",
    "E0640", "E0717", "E0729",
];

// Some error codes don't have any tests apparently...
const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];

#[derive(Default, Debug)]
struct ErrorCodeStatus {
    has_test: bool,
    has_explanation: bool,
    is_used: bool,
}

fn check_error_code_explanation(
    f: &str,
    error_codes: &mut HashMap<String, ErrorCodeStatus>,
    err_code: String,
) -> bool {
    let mut invalid_compile_fail_format = false;
    let mut found_error_code = false;

    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("```") {
            if s.contains("compile_fail") && s.contains('E') {
                if !found_error_code {
                    error_codes.get_mut(&err_code).map(|x| x.has_test = true);
                    found_error_code = true;
                }
            } else if s.contains("compile-fail") {
                invalid_compile_fail_format = true;
            }
        } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
            if !found_error_code {
                error_codes.get_mut(&err_code).map(|x| x.has_test = true);
                found_error_code = true;
            }
        }
    }
    invalid_compile_fail_format
}

fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &str) -> bool {
    let mut ignore_found = false;

    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
            return true;
        }
        if s.starts_with("```") {
            if s.contains("compile_fail") && s.contains(err_code) {
                return true;
            } else if s.contains("ignore") {
                // It's very likely that we can't actually make it fail compilation...
                ignore_found = true;
            }
        }
    }
    ignore_found
}

macro_rules! some_or_continue {
    ($e:expr) => {
        match $e {
            Some(e) => e,
            None => continue,
        }
    };
}

fn extract_error_codes(
    f: &str,
    error_codes: &mut HashMap<String, ErrorCodeStatus>,
    path: &Path,
    errors: &mut Vec<String>,
) {
    let mut reached_no_explanation = false;

    for line in f.lines() {
        let s = line.trim();
        if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") {
            let err_code = s
                .split_once(':')
                .expect(
                    format!(
                        "Expected a line with the format `E0xxx: include_str!(\"..\")`, but got {} \
                         without a `:` delimiter",
                        s,
                    )
                    .as_str(),
                )
                .0
                .to_owned();
            match error_codes.entry(err_code.clone()) {
                Entry::Occupied(mut e) => {
                    let mut entry = e.get_mut();
                    entry.has_explanation = true
                }
                Entry::Vacant(e) => {
                    e.insert(ErrorCodeStatus {
                        has_test: false,
                        is_used: false,
                        has_explanation: true,
                    });
                }
            }
            // Now we extract the tests from the markdown file!
            let md_file_name = match s.split_once("include_str!(\"") {
                None => continue,
                Some((_, md)) => match md.split_once("\")") {
                    None => continue,
                    Some((file_name, _)) => file_name,
                },
            };
            let path = some_or_continue!(path.parent())
                .join(md_file_name)
                .canonicalize()
                .expect("failed to canonicalize error explanation file path");
            match read_to_string(&path) {
                Ok(content) => {
                    let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
                    if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                        errors.push(format!(
                            "`{}` doesn't use its own error code in compile_fail example",
                            path.display(),
                        ));
                    } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                        errors.push(format!(
                            "`{}` has a compile_fail example with its own error code, it shouldn't \
                             be listed in IGNORE_EXPLANATION_CHECK!",
                            path.display(),
                        ));
                    }
                    if check_error_code_explanation(&content, error_codes, err_code) {
                        errors.push(format!(
                            "`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
                            path.display(),
                        ));
                    }
                }
                Err(e) => {
                    eprintln!("Couldn't read `{}`: {}", path.display(), e);
                }
            }
        } else if reached_no_explanation && s.starts_with('E') {
            let err_code = match s.split_once(',') {
                None => s,
                Some((err_code, _)) => err_code,
            }
            .to_string();
            if !error_codes.contains_key(&err_code) {
                // this check should *never* fail!
                error_codes.insert(err_code, ErrorCodeStatus::default());
            }
        } else if s == ";" {
            reached_no_explanation = true;
        }
    }
}

fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, ErrorCodeStatus>) {
    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("error[E") || s.starts_with("warning[E") {
            let err_code = match s.split_once(']') {
                None => continue,
                Some((err_code, _)) => match err_code.split_once('[') {
                    None => continue,
                    Some((_, err_code)) => err_code,
                },
            };
            match error_codes.entry(err_code.to_owned()) {
                Entry::Occupied(mut e) => {
                    let mut entry = e.get_mut();
                    entry.has_test = true
                }
                Entry::Vacant(e) => {
                    e.insert(ErrorCodeStatus {
                        has_test: true,
                        is_used: false,
                        has_explanation: false,
                    });
                }
            }
        }
    }
}

fn extract_error_codes_from_source(
    f: &str,
    error_codes: &mut HashMap<String, ErrorCodeStatus>,
    regex: &Regex,
) {
    for line in f.lines() {
        if line.trim_start().starts_with("//") {
            continue;
        }
        for cap in regex.captures_iter(line) {
            if let Some(error_code) = cap.get(1) {
                match error_codes.entry(error_code.as_str().to_owned()) {
                    Entry::Occupied(mut e) => {
                        let mut entry = e.get_mut();
                        entry.is_used = true
                    }
                    Entry::Vacant(e) => {
                        e.insert(ErrorCodeStatus {
                            has_test: false,
                            is_used: true,
                            has_explanation: false,
                        });
                    }
                }
            }
        }
    }
}

pub fn check(paths: &[&Path], bad: &mut bool) {
    let mut errors = Vec::new();
    let mut found_explanations = 0;
    let mut found_tests = 0;
    let mut error_codes: HashMap<String, ErrorCodeStatus> = HashMap::new();
    // We want error codes which match the following cases:
    //
    // * foo(a, E0111, a)
    // * foo(a, E0111)
    // * foo(E0111, a)
    // * #[error = "E0111"]
    let regex = Regex::new(r#"[(,"\s](E\d{4})[,)"]"#).unwrap();

    println!("Checking which error codes lack tests...");

    for path in paths {
        super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| {
            let file_name = entry.file_name();
            if file_name == "error_codes.rs" {
                extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
                found_explanations += 1;
            } else if entry.path().extension() == Some(OsStr::new("stderr")) {
                extract_error_codes_from_tests(contents, &mut error_codes);
                found_tests += 1;
            } else if entry.path().extension() == Some(OsStr::new("rs")) {
                let path = entry.path().to_string_lossy();
                if ["src/test/", "src/doc/", "src/tools/"].iter().all(|c| !path.contains(c)) {
                    extract_error_codes_from_source(contents, &mut error_codes, &regex);
                }
            }
        });
    }
    if found_explanations == 0 {
        eprintln!("No error code explanation was tested!");
        *bad = true;
    }
    if found_tests == 0 {
        eprintln!("No error code was found in compilation errors!");
        *bad = true;
    }
    if errors.is_empty() {
        println!("Found {} error codes", error_codes.len());

        for (err_code, error_status) in &error_codes {
            if !error_status.has_test && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
            } else if error_status.has_test && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                errors.push(format!(
                    "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
                    err_code
                ));
            }
            if !error_status.is_used && !error_status.has_explanation {
                errors.push(format!(
                    "Error code {} isn't used and doesn't have an error explanation, it should be \
                     commented in error_codes.rs file",
                    err_code
                ));
            }
        }
    }
    if errors.is_empty() {
        // Checking if local constants need to be cleaned.
        for err_code in EXEMPTED_FROM_TEST {
            match error_codes.get(err_code.to_owned()) {
                Some(status) => {
                    if status.has_test {
                        errors.push(format!(
                            "{} error code has a test and therefore should be \
                            removed from the `EXEMPTED_FROM_TEST` constant",
                            err_code
                        ));
                    }
                }
                None => errors.push(format!(
                    "{} error code isn't used anymore and therefore should be removed \
                        from `EXEMPTED_FROM_TEST` constant",
                    err_code
                )),
            }
        }
    }
    errors.sort();
    for err in &errors {
        eprintln!("{}", err);
    }
    println!("Found {} error codes with no tests", errors.len());
    if !errors.is_empty() {
        *bad = true;
    }
    println!("Done!");
}
<|endoftext|>


<commit_before>use core::fmt;

/// Represents a physical memory address
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PhysicalAddress(u64);

impl From<u64> for PhysicalAddress {
    fn from(value: u64) -> Self {
        PhysicalAddress(value)
    }
}

impl PhysicalAddress {
    /// Convert to `u64`
    pub const fn as_u64(&self) -> u64 {
        self.0
    }
}

impl fmt::Binary for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Represent a virtual (linear) memory address
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct VirtualAddress(usize);

impl From<usize> for VirtualAddress {
    fn from(value: usize) -> Self {
        VirtualAddress(value)
    }
}

impl VirtualAddress {
    /// Convert to `usize`
    pub const fn as_usize(&self) -> usize {
        self.0
    }
}

impl fmt::Binary for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}
<commit_msg>Implement more From conversions for VirtualAddress and PhysicalAddress<commit_after>use core::fmt;

/// Represents a physical memory address
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PhysicalAddress(u64);

impl From<u64> for PhysicalAddress {
    fn from(value: u64) -> Self {
        PhysicalAddress(value)
    }
}

impl From<usize> for PhysicalAddress {
    fn from(value: usize) -> Self {
        PhysicalAddress(value as u64)
    }
}

impl PhysicalAddress {
    /// Convert to `u64`
    pub const fn as_u64(&self) -> u64 {
        self.0
    }
}

impl fmt::Binary for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for PhysicalAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Represent a virtual (linear) memory address
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct VirtualAddress(usize);

impl From<usize> for VirtualAddress {
    fn from(value: usize) -> Self {
        VirtualAddress(value)
    }
}

impl From<u64> for VirtualAddress {
    fn from(value: u64) -> Self {
        VirtualAddress(value as usize)
    }
}

impl VirtualAddress {
    /// Convert to `usize`
    pub const fn as_usize(&self) -> usize {
        self.0
    }
}

impl fmt::Binary for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for VirtualAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}
<|endoftext|>


<commit_before>use clap;
use std::io::{self, Write};
use std::process;
use std::path::PathBuf;
use std::error;
use std::result;
use std::fmt;
use structopt::StructOpt;
use mprovision as mp;

#[derive(Debug, PartialEq, StructOpt)]
/// A tool that helps iOS developers to manage mobileprovision files.
pub enum Command {
    #[structopt(name = "list", raw(display_order = "0"))]
    /// Lists provisioning profiles
    List(ListParams),
    #[structopt(name = "show", raw(display_order = "1"))]
    /// Shows details of a provisioning profile using its uuid
    ShowUuid(ShowUuidParams),
    #[structopt(name = "show-file", raw(display_order = "2"))]
    /// Shows details of a provisioning profile
    ShowFile(ShowFileParams),
    #[structopt(name = "remove", raw(display_order = "3"))]
    /// Removes provisioning profiles
    Remove(RemoveParams),
    #[structopt(name = "clean", raw(display_order = "4"))]
    /// Removes expired provisioning profiles
    Clean(CleanParams),
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct ListParams {
    #[structopt(short = "t", long = "text", raw(empty_values = "false"))]
    /// Lists provisioning profiles that contain this text
    pub text: Option<String>,
    #[structopt(short = "d", long = "expire-in-days", parse(try_from_str = "parse_days"))]
    /// Lists provisioning profiles that will expire in days
    pub expire_in_days: Option<i64>,
    #[structopt(long = "source", parse(from_os_str))]
    /// A directory where to search provisioning profiles
    pub directory: Option<PathBuf>,
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct ShowUuidParams {
    #[structopt(raw(empty_values = "false"))]
    /// An uuid of a provisioning profile
    pub uuid: String,
    #[structopt(long = "source", parse(from_os_str))]
    /// A directory where to search provisioning profiles
    pub directory: Option<PathBuf>,
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct ShowFileParams {
    #[structopt(parse(from_os_str))]
    /// A file path of a provisioning profile
    pub file: PathBuf,
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct RemoveParams {
    /// uuid(s) of provisioning profiles
    pub uuids: Vec<String>,
    #[structopt(long = "source", parse(from_os_str))]
    /// A directory where to search provisioning profiles
    pub directory: Option<PathBuf>,
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct CleanParams {
    #[structopt(long = "source", parse(from_os_str))]
    /// A directory where to clean
    pub directory: Option<PathBuf>,
}

pub type Result = result::Result<Command, Error>;

#[derive(Debug)]
pub enum Error {
    Lib(mp::Error),
    Clap(clap::Error),
    Custom(String),
}

impl Error {
    pub fn exit(&self) -> ! {
        match *self {
            Error::Clap(ref e) => e.exit(),
            _ => {
                writeln!(&mut io::stderr(), "{}", self).unwrap();
                process::exit(1);
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Lib(ref e) => e.description(),
            Error::Clap(ref e) => e.description(),
            Error::Custom(ref e) => e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Lib(ref e) => Some(e),
            Error::Clap(ref e) => Some(e),
            Error::Custom(_) => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Lib(ref e) => error::Error::description(e).fmt(f),
            Error::Clap(ref e) => error::Error::description(e).fmt(f),
            Error::Custom(ref e) => e.fmt(f),
        }
    }
}

impl From<mp::Error> for Error {
    fn from(e: mp::Error) -> Self {
        Error::Lib(e)
    }
}

impl From<clap::Error> for Error {
    fn from(e: clap::Error) -> Self {
        Error::Clap(e)
    }
}

/// Parses arguments and returns a `Command`.
pub fn parse<I, S>(args: I) -> Result
where
    I: IntoIterator<Item = S>,
    S: Clone,
    ::std::ffi::OsString: From<S>,
{
    let app = Command::clap();
    let matches = app.get_matches_from_safe(args)?;
    Ok(Command::from_clap(&matches))
}

/// Parses and validates days argument.
fn parse_days(s: &str) -> result::Result<i64, Error> {
    let days = s.parse::<i64>()
        .map_err(|err| Error::Custom(err.to_string()))?;
    if days < 0 || days > 365 {
        let message = format!("should be between 0 and 365, got {}", days);
        return Err(Error::Custom(message));
    }
    Ok(days)
}

// pub fn parse<I, S>(args: I) -> Result
// where
//     I: IntoIterator<Item = S>,
//     S: Clone,
//     ::std::ffi::OsString: From<S>,
// {
//     let app = App::new("mprovision")
//         .about("A tool that helps iOS developers to manage mobileprovision files.")
//         .version(crate_version!())
//         .subcommand(
//             SubCommand::with_name("list")
//                 .about("Lists provisioning profiles")
//                 .display_order(0)
//                 .setting(AppSettings::DisableVersion)
//                 .arg(
//                     Arg::with_name("TEXT")
//                         .long("text")
//                         .short("t")
//                         .help("Lists provisioning profiles that contain this text")
//                         .display_order(0)
//                         .required(false)
//                         .empty_values(false)
//                         .takes_value(true),
//                 )
//                 .arg(
//                     Arg::with_name("DAYS")
//                         .long("expire-in-days")
//                         .short("d")
//                         .help("Lists provisioning profiles that will expire in days")
//                         .display_order(1)
//                         .required(false)
//                         .empty_values(false)
//                         .takes_value(true),
//                 )
//                 .arg(
//                     Arg::with_name("DIRECTORY")
//                         .long("source")
//                         .help("A directory where to search provisioning profiles")
//                         .required(false)
//                         .empty_values(false)
//                         .takes_value(true),
//                 ),
//         )
//         .subcommand(
//             SubCommand::with_name("show")
//                 .about("Shows details of a provisioning profile using its uuid")
//                 .display_order(1)
//                 .setting(AppSettings::DisableVersion)
//                 .arg(
//                     Arg::with_name("UUID")
//                         .help("An uuid of a provisioning profile")
//                         .required(true)
//                         .empty_values(false)
//                         .takes_value(true),
//                 )
//                 .arg(
//                     Arg::with_name("DIRECTORY")
//                         .long("source")
//                         .help("A directory where to search a provisioning profile")
//                         .required(false)
//                         .empty_values(false)
//                         .takes_value(true),
//                 ),
//         )
//         .subcommand(
//             SubCommand::with_name("show-file")
//                 .about("Shows details of a provisioning profile")
//                 .display_order(2)
//                 .setting(AppSettings::DisableVersion)
//                 .arg(
//                     Arg::with_name("PATH")
//                         .help("A file path of a provisioning profile")
//                         .required(true)
//                         .empty_values(false)
//                         .takes_value(true),
//                 ),
//         )
//         .subcommand(
//             SubCommand::with_name("remove")
//                 .about("Removes a provisioning profile")
//                 .display_order(3)
//                 .setting(AppSettings::DisableVersion)
//                 .arg(
//                     Arg::with_name("UUID")
//                         .help("An uuid of a provisioning profile")
//                         .required(true)
//                         .empty_values(false)
//                         .multiple(true)
//                         .takes_value(true),
//                 )
//                 .arg(
//                     Arg::with_name("DIRECTORY")
//                         .long("source")
//                         .help("A directory where to search a provisioning profile")
//                         .required(false)
//                         .empty_values(false)
//                         .takes_value(true),
//                 ),
//         )
//         .subcommand(
//             SubCommand::with_name("clean")
//                 .about("Removes expired provisioning profiles")
//                 .display_order(4)
//                 .setting(AppSettings::DisableVersion)
//                 .arg(
//                     Arg::with_name("DIRECTORY")
//                         .long("source")
//                         .help("A directory where to clean")
//                         .required(false)
//                         .empty_values(false)
//                         .takes_value(true),
//                 ),
//         );

//     let matches = app.get_matches_from_safe(args)?;
//     if let Some(list_matches) = matches.subcommand_matches("list") {
//         let mut params = ListParams::default();
//         params.filter = list_matches.value_of("TEXT").map(|text| text.to_string());
//         if let Some(days) = list_matches
//             .value_of("DAYS")
//             .and_then(|days| days.parse::<i64>().ok())
//         {
//             if days < 0 || days > 365 {
//                 return Err(Error::Custom(
//                     "DAYS should be between 0 and 365".to_string(),
//                 ));
//             }
//             params.expire_in_days = Some(days);
//         }
//         params.directory = list_matches.value_of("DIRECTORY").map(|dir| dir.into());
//         Ok(Command::List(params))
//     } else if let Some(show_matches) = matches.subcommand_matches("show") {
//         let uuid = show_matches
//             .value_of("UUID")
//             .map(|uuid| uuid.to_string())
//             .unwrap();
//         let directory = show_matches.value_of("DIRECTORY").map(|dir| dir.into());
//         Ok(Command::ShowUuid(uuid, directory))
//     } else if let Some(show_file_matches) = matches.subcommand_matches("show-file") {
//         let path = show_file_matches
//             .value_of("PATH")
//             .map(|path| path.into())
//             .unwrap();
//         Ok(Command::ShowFile(path))
//     } else if let Some(remove_matches) = matches.subcommand_matches("remove") {
//         let uuids = remove_matches
//             .values_of("UUID")
//             .unwrap()
//             .map(String::from)
//             .collect();
//         let directory = remove_matches.value_of("DIRECTORY").map(|dir| dir.into());
//         Ok(Command::Remove(uuids, directory))
//     } else if let Some(clean_matches) = matches.subcommand_matches("clean") {
//         let directory = clean_matches.value_of("DIRECTORY").map(|dir| dir.into());
//         Ok(Command::Clean(directory))
//     } else {
//         Err(Error::Custom("Command isn't implemented".to_string()))
//     }
// }

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

    #[test]
    fn list_command() {
        expect!(parse(&["mprovision", "list"]))
            .to(be_ok().value(Command::List(ListParams::default())));

        expect!(parse(&["mprovision", "list", "--source", "."])).to(be_ok().value(Command::List(
            ListParams {
                text: None,
                expire_in_days: None,
                directory: Some(".".into()),
            },
        )));

        expect!(parse(&["mprovision", "list", "--text", "abc"])).to(be_ok().value(Command::List(
            ListParams {
                text: Some("abc".to_string()),
                expire_in_days: None,
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "list", "-t", "abc"])).to(be_ok().value(Command::List(
            ListParams {
                text: Some("abc".to_string()),
                expire_in_days: None,
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "list", "--text", ""])).to(be_err());

        expect!(parse(&["mprovision", "list", "-t", ""])).to(be_err());

        expect!(parse(&["mprovision", "list", "--expire-in-days", "3"])).to(be_ok().value(
            Command::List(ListParams {
                text: None,
                expire_in_days: Some(3),
                directory: None,
            }),
        ));

        expect!(parse(&["mprovision", "list", "-d", "3"])).to(be_ok().value(Command::List(
            ListParams {
                text: None,
                expire_in_days: Some(3),
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "list", "--expire-in-days", "-3"])).to(be_err());
        expect!(parse(&["mprovision", "list", "-d", "-3"])).to(be_err());
        expect!(parse(&["mprovision", "list", "--expire-in-days", "366"])).to(be_err());
        expect!(parse(&["mprovision", "list", "-d", "366"])).to(be_err());

        expect!(parse(&[
            "mprovision",
            "list",
            "--text",
            "abc",
            "--expire-in-days",
            "3",
            "--source",
            "."
        ])).to(be_ok().value(Command::List(ListParams {
            text: Some("abc".to_string()),
            expire_in_days: Some(3),
            directory: Some(".".into()),
        })));

        expect!(parse(&[
            "mprovision",
            "list",
            "-t",
            "abc",
            "-d",
            "3",
            "--source",
            "."
        ])).to(be_ok().value(Command::List(ListParams {
            text: Some("abc".to_string()),
            expire_in_days: Some(3),
            directory: Some(".".into()),
        })));
    }

    #[test]
    fn show_uuid_command() {
        expect!(parse(&["mprovision", "show", "abcd"])).to(be_ok().value(Command::ShowUuid(
            ShowUuidParams {
                uuid: "abcd".to_string(),
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "show", ""])).to(be_err());

        expect!(parse(&["mprovision", "show", "abcd", "--source", "."])).to(be_ok().value(
            Command::ShowUuid(ShowUuidParams {
                uuid: "abcd".to_string(),
                directory: Some(".".into()),
            }),
        ));
    }

    #[test]
    fn show_path_command() {
        expect!(parse(&["mprovision", "show-file", "file.mprovision"])).to(be_ok().value(
            Command::ShowFile(ShowFileParams {
                file: "file.mprovision".into(),
            }),
        ));

        expect!(parse(&["mprovision", "show-file", "file.mprovision", "."])).to(be_err());
    }

    #[test]
    fn remove_uuid_command() {
        expect!(parse(&["mprovision", "remove", "abcd"])).to(be_ok().value(Command::Remove(
            RemoveParams {
                uuids: vec!["abcd".to_string()],
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "remove", "abcd", "ef"])).to(be_ok().value(
            Command::Remove(RemoveParams {
                uuids: vec!["abcd".to_string(), "ef".to_string()],
                directory: None,
            }),
        ));

        expect!(parse(&["mprovision", "remove", "abcd", "--source", "."])).to(be_ok().value(
            Command::Remove(RemoveParams {
                uuids: vec!["abcd".to_string()],
                directory: Some(".".into()),
            }),
        ));

        expect!(parse(&[
            "mprovision",
            "remove",
            "abcd",
            "ef",
            "--source",
            "."
        ])).to(be_ok().value(Command::Remove(RemoveParams {
            uuids: vec!["abcd".to_string(), "ef".to_string()],
            directory: Some(".".into()),
        })));
    }

    #[test]
    fn clean_command() {
        expect!(parse(&["mprovision", "clean"]))
            .to(be_ok().value(Command::Clean(CleanParams { directory: None })));

        expect!(parse(&["mprovision", "clean", "--source", "."])).to(be_ok().value(
            Command::Clean(CleanParams {
                directory: Some(".".into()),
            }),
        ));
    }
}
<commit_msg>Remove commented code<commit_after>use clap;
use std::io::{self, Write};
use std::process;
use std::path::PathBuf;
use std::error;
use std::result;
use std::fmt;
use structopt::StructOpt;
use mprovision as mp;

#[derive(Debug, PartialEq, StructOpt)]
/// A tool that helps iOS developers to manage mobileprovision files.
pub enum Command {
    #[structopt(name = "list", raw(display_order = "0"))]
    /// Lists provisioning profiles
    List(ListParams),
    #[structopt(name = "show", raw(display_order = "1"))]
    /// Shows details of a provisioning profile using its uuid
    ShowUuid(ShowUuidParams),
    #[structopt(name = "show-file", raw(display_order = "2"))]
    /// Shows details of a provisioning profile
    ShowFile(ShowFileParams),
    #[structopt(name = "remove", raw(display_order = "3"))]
    /// Removes provisioning profiles
    Remove(RemoveParams),
    #[structopt(name = "clean", raw(display_order = "4"))]
    /// Removes expired provisioning profiles
    Clean(CleanParams),
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct ListParams {
    #[structopt(short = "t", long = "text", raw(empty_values = "false"))]
    /// Lists provisioning profiles that contain this text
    pub text: Option<String>,
    #[structopt(short = "d", long = "expire-in-days", parse(try_from_str = "parse_days"))]
    /// Lists provisioning profiles that will expire in days
    pub expire_in_days: Option<i64>,
    #[structopt(long = "source", parse(from_os_str))]
    /// A directory where to search provisioning profiles
    pub directory: Option<PathBuf>,
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct ShowUuidParams {
    #[structopt(raw(empty_values = "false"))]
    /// An uuid of a provisioning profile
    pub uuid: String,
    #[structopt(long = "source", parse(from_os_str))]
    /// A directory where to search provisioning profiles
    pub directory: Option<PathBuf>,
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct ShowFileParams {
    #[structopt(parse(from_os_str))]
    /// A file path of a provisioning profile
    pub file: PathBuf,
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct RemoveParams {
    /// uuid(s) of provisioning profiles
    pub uuids: Vec<String>,
    #[structopt(long = "source", parse(from_os_str))]
    /// A directory where to search provisioning profiles
    pub directory: Option<PathBuf>,
}

#[derive(Debug, Default, PartialEq, StructOpt)]
pub struct CleanParams {
    #[structopt(long = "source", parse(from_os_str))]
    /// A directory where to clean
    pub directory: Option<PathBuf>,
}

pub type Result = result::Result<Command, Error>;

#[derive(Debug)]
pub enum Error {
    Lib(mp::Error),
    Clap(clap::Error),
    Custom(String),
}

impl Error {
    pub fn exit(&self) -> ! {
        match *self {
            Error::Clap(ref e) => e.exit(),
            _ => {
                writeln!(&mut io::stderr(), "{}", self).unwrap();
                process::exit(1);
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Lib(ref e) => e.description(),
            Error::Clap(ref e) => e.description(),
            Error::Custom(ref e) => e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Lib(ref e) => Some(e),
            Error::Clap(ref e) => Some(e),
            Error::Custom(_) => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Lib(ref e) => error::Error::description(e).fmt(f),
            Error::Clap(ref e) => error::Error::description(e).fmt(f),
            Error::Custom(ref e) => e.fmt(f),
        }
    }
}

impl From<mp::Error> for Error {
    fn from(e: mp::Error) -> Self {
        Error::Lib(e)
    }
}

impl From<clap::Error> for Error {
    fn from(e: clap::Error) -> Self {
        Error::Clap(e)
    }
}

/// Parses arguments and returns a `Command`.
pub fn parse<I, S>(args: I) -> Result
where
    I: IntoIterator<Item = S>,
    S: Clone,
    ::std::ffi::OsString: From<S>,
{
    let app = Command::clap();
    let matches = app.get_matches_from_safe(args)?;
    Ok(Command::from_clap(&matches))
}

/// Parses and validates days argument.
fn parse_days(s: &str) -> result::Result<i64, Error> {
    let days = s.parse::<i64>()
        .map_err(|err| Error::Custom(err.to_string()))?;
    if days < 0 || days > 365 {
        let message = format!("should be between 0 and 365, got {}", days);
        return Err(Error::Custom(message));
    }
    Ok(days)
}

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

    #[test]
    fn list_command() {
        expect!(parse(&["mprovision", "list"]))
            .to(be_ok().value(Command::List(ListParams::default())));

        expect!(parse(&["mprovision", "list", "--source", "."])).to(be_ok().value(Command::List(
            ListParams {
                text: None,
                expire_in_days: None,
                directory: Some(".".into()),
            },
        )));

        expect!(parse(&["mprovision", "list", "--text", "abc"])).to(be_ok().value(Command::List(
            ListParams {
                text: Some("abc".to_string()),
                expire_in_days: None,
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "list", "-t", "abc"])).to(be_ok().value(Command::List(
            ListParams {
                text: Some("abc".to_string()),
                expire_in_days: None,
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "list", "--text", ""])).to(be_err());

        expect!(parse(&["mprovision", "list", "-t", ""])).to(be_err());

        expect!(parse(&["mprovision", "list", "--expire-in-days", "3"])).to(be_ok().value(
            Command::List(ListParams {
                text: None,
                expire_in_days: Some(3),
                directory: None,
            }),
        ));

        expect!(parse(&["mprovision", "list", "-d", "3"])).to(be_ok().value(Command::List(
            ListParams {
                text: None,
                expire_in_days: Some(3),
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "list", "--expire-in-days", "-3"])).to(be_err());
        expect!(parse(&["mprovision", "list", "-d", "-3"])).to(be_err());
        expect!(parse(&["mprovision", "list", "--expire-in-days", "366"])).to(be_err());
        expect!(parse(&["mprovision", "list", "-d", "366"])).to(be_err());

        expect!(parse(&[
            "mprovision",
            "list",
            "--text",
            "abc",
            "--expire-in-days",
            "3",
            "--source",
            "."
        ])).to(be_ok().value(Command::List(ListParams {
            text: Some("abc".to_string()),
            expire_in_days: Some(3),
            directory: Some(".".into()),
        })));

        expect!(parse(&[
            "mprovision",
            "list",
            "-t",
            "abc",
            "-d",
            "3",
            "--source",
            "."
        ])).to(be_ok().value(Command::List(ListParams {
            text: Some("abc".to_string()),
            expire_in_days: Some(3),
            directory: Some(".".into()),
        })));
    }

    #[test]
    fn show_uuid_command() {
        expect!(parse(&["mprovision", "show", "abcd"])).to(be_ok().value(Command::ShowUuid(
            ShowUuidParams {
                uuid: "abcd".to_string(),
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "show", ""])).to(be_err());

        expect!(parse(&["mprovision", "show", "abcd", "--source", "."])).to(be_ok().value(
            Command::ShowUuid(ShowUuidParams {
                uuid: "abcd".to_string(),
                directory: Some(".".into()),
            }),
        ));
    }

    #[test]
    fn show_path_command() {
        expect!(parse(&["mprovision", "show-file", "file.mprovision"])).to(be_ok().value(
            Command::ShowFile(ShowFileParams {
                file: "file.mprovision".into(),
            }),
        ));

        expect!(parse(&["mprovision", "show-file", "file.mprovision", "."])).to(be_err());
    }

    #[test]
    fn remove_uuid_command() {
        expect!(parse(&["mprovision", "remove", "abcd"])).to(be_ok().value(Command::Remove(
            RemoveParams {
                uuids: vec!["abcd".to_string()],
                directory: None,
            },
        )));

        expect!(parse(&["mprovision", "remove", "abcd", "ef"])).to(be_ok().value(
            Command::Remove(RemoveParams {
                uuids: vec!["abcd".to_string(), "ef".to_string()],
                directory: None,
            }),
        ));

        expect!(parse(&["mprovision", "remove", "abcd", "--source", "."])).to(be_ok().value(
            Command::Remove(RemoveParams {
                uuids: vec!["abcd".to_string()],
                directory: Some(".".into()),
            }),
        ));

        expect!(parse(&[
            "mprovision",
            "remove",
            "abcd",
            "ef",
            "--source",
            "."
        ])).to(be_ok().value(Command::Remove(RemoveParams {
            uuids: vec!["abcd".to_string(), "ef".to_string()],
            directory: Some(".".into()),
        })));
    }

    #[test]
    fn clean_command() {
        expect!(parse(&["mprovision", "clean"]))
            .to(be_ok().value(Command::Clean(CleanParams { directory: None })));

        expect!(parse(&["mprovision", "clean", "--source", "."])).to(be_ok().value(
            Command::Clean(CleanParams {
                directory: Some(".".into()),
            }),
        ));
    }
}
<|endoftext|>


<commit_before>use collections::slice::{mod, AsSlice, SlicePrelude};
use collections::vec::{mod, Vec};
use core::mem;
use core::iter::{mod, AdditiveIterator, Iterator};
use core::option::{mod, Some, None, Option};

use iobuf::Iobuf;

/// A span over potentially many Iobufs. This is useful as a "string" type where
/// the contents of the string can come from multiple IObufs, and you want to
/// avoid copying the buffer contents unnecessarily.
///
/// As an optimization, pushing an Iobuf that points to data immediately after
/// the range represented by the last Iobuf pushed will result in just expanding
/// the held Iobuf's range. This prevents allocating lots of unnecessary
/// intermediate buffers, while still maintaining the illusion of "pushing lots
/// of buffers" while incrementally parsing.
///
/// A `BufSpan` is internally represented as either an `Iobuf` or a `Vec<Iobuf>`,
/// depending on how many different buffers were used.
pub enum BufSpan<Buf> {
  Empty,
  One (Buf),
  Many(Vec<Buf>),
}

impl<Buf: Iobuf> BufSpan<Buf> {
  /// Creates a new, empty `Bufspan`.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf};
  ///
  /// let s: BufSpan<ROIobuf<'static>> = BufSpan::new();
  /// assert!(s.is_empty());
  /// ```
  #[inline]
  pub fn new() -> BufSpan<Buf> {
    Empty
  }

  /// Creates a new `BufSpan` from a slice of bytes.
  ///
  /// ```
  /// use iobuf::{BufSpan, Iobuf, ROIobuf};
  /// use std::iter::AdditiveIterator;
  ///
  /// let s = BufSpan::from_buf(ROIobuf::from_slice(b"hello"));
  /// assert_eq!(s.iter().count(), 1);
  /// assert_eq!(s.iter().map(|b| b.len()).sum(), 5);
  /// ```
  #[inline]
  pub fn from_buf(b: Buf) -> BufSpan<Buf> {
    One(b)
  }

  /// Returns `true` iff the span is over an empty range.
  ///
  /// ```
  /// use iobuf::{BufSpan, Iobuf, ROIobuf};
  ///
  /// let mut s = BufSpan::new();
  ///
  /// assert!(s.is_empty());
  ///
  /// s.push(ROIobuf::from_str(""));
  /// assert!(s.is_empty());
  ///
  /// s.push(ROIobuf::from_str("hello, world!"));
  /// assert!(!s.is_empty());
  /// ```
  #[inline]
  pub fn is_empty(&self) -> bool {
    match *self {
      Empty => true,
      _     => false,
    }
  }

  /// The fast path during pushing -- either fills in the first buffer, or
  /// extends an existing one.
  ///
  /// Returns `None` if the fast path was taken and nothing more needs to be
  /// done. Returns `Some` if we need to do a slow push.
  fn try_to_extend(&mut self, b: Buf) -> Option<Buf> {
    let len = b.len();
    if len == 0 { return None; }

    match *self {
      Empty => {},
      One(ref mut b0) => {
        unsafe {
          if b0.is_extended_by(&b) {
            b0.unsafe_extend(len);
            return None;
          } else {
            return Some(b); // Upgrade the `One` into a `Many` in the slow path.
          }
        }
      }
      Many(ref mut v) => {
        // I wish this wouldn't unwind, and just abort... :(
        let last = v.last_mut().unwrap();
        unsafe {
          if last.is_extended_by(&b) {
            last.unsafe_extend(len);
            return None;
          } else {
            return Some(b);
          }
        }
      }
    }

    // Handle this case in the fast path, instead of leaving it for slow_push
    // to clean up.
    *self = One(b);
    None
  }

  /// Appends a buffer to a `BufSpan`. If the buffer is an extension of the
  /// previously pushed buffer, the range will be extended. Otherwise, the new
  /// non-extension buffer will be added to the end of a vector.
  pub fn push(&mut self, b: Buf) {
    match self.try_to_extend(b) {
      None    => {},
      Some(b) => self.slow_push(b),
    }
  }

  /// The slow path during a push. This is only taken if a `BufSpan` must span
  /// multiple backing buffers.
  #[cold]
  fn slow_push(&mut self, b: Buf) {
    let this = mem::replace(self, Empty);
    *self =
      match this {
        Empty   => One(b),
        One(b0) => {
          let mut v = Vec::with_capacity(2);
          v.push(b0);
          v.push(b);
          Many(v)
        },
        Many(mut bs) => { bs.push(b); Many(bs) }
      };
  }

  /// Returns an iterator over references to the buffers inside the `BufSpan`.
  #[inline]
  pub fn iter<'a>(&'a self) -> SpanIter<'a, Buf> {
    match *self {
      Empty       => Opt(None.into_iter()),
      One (ref b) => Opt(Some(b).into_iter()),
      Many(ref v) => Lot(v.as_slice().iter()),
    }
  }

  /// Returns a moving iterator over the buffers inside the `BufSpan`.
  #[inline]
  pub fn into_iter(self) -> SpanMoveIter<Buf> {
    match self {
      Empty   => MoveOpt(None.into_iter()),
      One (b) => MoveOpt(Some(b).into_iter()),
      Many(v) => MoveLot(v.into_iter()),
    }
  }

  /// Returns an iterator over the bytes in the `BufSpan`.
  #[inline]
  pub fn iter_bytes<'a>(&'a self) -> ByteIter<'a, Buf> {
    self.iter()
        .flat_map(|buf| unsafe { buf.as_window_slice().iter() })
        .map(|&b| b)
  }

  /// Returns `true` iff the bytes in this `BufSpan` are the same as the bytes
  /// in the other `BufSpan`.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf, RWIobuf};
  ///
  /// let a = BufSpan::from_buf(ROIobuf::from_str("hello"));
  /// let b = BufSpan::from_buf(RWIobuf::from_string("hello".into_string()));
  ///
  /// assert!(a.byte_equal(&b));
  ///
  /// let mut c = BufSpan::from_buf(ROIobuf::from_str("hel"));
  /// c.push(ROIobuf::from_str("lo"));
  ///
  /// assert!(a.byte_equal(&c)); assert!(c.byte_equal(&a));
  ///
  /// let d = BufSpan::from_buf(ROIobuf::from_str("helo"));
  /// assert!(!a.byte_equal(&d));
  /// ```
  #[inline]
  pub fn byte_equal<Buf2: Iobuf>(&self, other: &BufSpan<Buf2>) -> bool {
    self.count_bytes() == other.count_bytes()
    && self.iter_bytes().zip(other.iter_bytes()).all(|(a, b)| a == b)
  }

  /// A more efficient version of byte_equal, specialized to work exclusively on
  /// slices.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf};
  ///
  /// let a = BufSpan::from_buf(ROIobuf::from_str("hello"));
  ///
  /// assert!(a.byte_equal_slice(b"hello"));
  /// assert!(!a.byte_equal_slice(b"helo"));
  /// ```
  #[inline]
  pub fn byte_equal_slice(&self, other: &[u8]) -> bool {
    self.count_bytes() as uint == other.len()
    && self.iter_bytes().zip(other.iter()).all(|(a, &b)| a == b)
  }

  /// Counts the number of bytes this `BufSpan` is over. This is
  /// `O(self.iter().len())`.
  #[inline]
  pub fn count_bytes(&self) -> u32 {
    // `self.iter().map(|b| b.len()).sum()` would be shorter, but I like to
    // specialize for the much more common case of empty or singular `BufSpan`s.
    match *self {
      Empty       => 0,
      One (ref b) => b.len(),
      Many(ref v) => v.iter().map(|b| b.len()).sum(),
    }
  }
}

/// An iterator over the bytes in a `BufSpan`.
pub type ByteIter<'a, Buf> =
  iter::Map<'static, &'a u8, u8,
    iter::FlatMap<'static, &'a Buf,
      SpanIter<'a, Buf>,
      slice::Items<'a, u8>>>;

/// An iterator over references to buffers inside a `BufSpan`.
pub enum SpanIter<'a, Buf: 'a> {
  Opt(option::Item<&'a Buf>),
  Lot(slice::Items<'a, Buf>),
}

impl<'a, Buf: Iobuf> Iterator<&'a Buf> for SpanIter<'a, Buf> {
  #[inline(always)]
  fn next(&mut self) -> Option<&'a Buf> {
    // I'm couting on this match getting lifted out of the loop with
    // loop-invariant code motion.
    match *self {
      Opt(ref mut iter) => iter.next(),
      Lot(ref mut iter) => iter.next(),
    }
  }
}

/// A moving iterator over buffers inside a `BufSpan`.
pub enum SpanMoveIter<Buf> {
  MoveOpt(option::Item<Buf>),
  MoveLot(vec::MoveItems<Buf>),
}

impl<Buf: Iobuf> Iterator<Buf> for SpanMoveIter<Buf> {
  #[inline(always)]
  fn next(&mut self) -> Option<Buf> {
    // I'm couting on this match getting lifted out of the loop with
    // loop-invariant code motion.
    match *self {
      MoveOpt(ref mut iter) => iter.next(),
      MoveLot(ref mut iter) => iter.next(),
    }
  }
}
<commit_msg>add size hints<commit_after>use collections::slice::{mod, AsSlice, SlicePrelude};
use collections::vec::{mod, Vec};
use core::mem;
use core::iter::{mod, AdditiveIterator, Iterator};
use core::option::{mod, Some, None, Option};

use iobuf::Iobuf;

/// A span over potentially many Iobufs. This is useful as a "string" type where
/// the contents of the string can come from multiple IObufs, and you want to
/// avoid copying the buffer contents unnecessarily.
///
/// As an optimization, pushing an Iobuf that points to data immediately after
/// the range represented by the last Iobuf pushed will result in just expanding
/// the held Iobuf's range. This prevents allocating lots of unnecessary
/// intermediate buffers, while still maintaining the illusion of "pushing lots
/// of buffers" while incrementally parsing.
///
/// A `BufSpan` is internally represented as either an `Iobuf` or a `Vec<Iobuf>`,
/// depending on how many different buffers were used.
pub enum BufSpan<Buf> {
  Empty,
  One (Buf),
  Many(Vec<Buf>),
}

impl<Buf: Iobuf> BufSpan<Buf> {
  /// Creates a new, empty `Bufspan`.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf};
  ///
  /// let s: BufSpan<ROIobuf<'static>> = BufSpan::new();
  /// assert!(s.is_empty());
  /// ```
  #[inline]
  pub fn new() -> BufSpan<Buf> {
    Empty
  }

  /// Creates a new `BufSpan` from a slice of bytes.
  ///
  /// ```
  /// use iobuf::{BufSpan, Iobuf, ROIobuf};
  /// use std::iter::AdditiveIterator;
  ///
  /// let s = BufSpan::from_buf(ROIobuf::from_slice(b"hello"));
  /// assert_eq!(s.iter().count(), 1);
  /// assert_eq!(s.iter().map(|b| b.len()).sum(), 5);
  /// ```
  #[inline]
  pub fn from_buf(b: Buf) -> BufSpan<Buf> {
    One(b)
  }

  /// Returns `true` iff the span is over an empty range.
  ///
  /// ```
  /// use iobuf::{BufSpan, Iobuf, ROIobuf};
  ///
  /// let mut s = BufSpan::new();
  ///
  /// assert!(s.is_empty());
  ///
  /// s.push(ROIobuf::from_str(""));
  /// assert!(s.is_empty());
  ///
  /// s.push(ROIobuf::from_str("hello, world!"));
  /// assert!(!s.is_empty());
  /// ```
  #[inline]
  pub fn is_empty(&self) -> bool {
    match *self {
      Empty => true,
      _     => false,
    }
  }

  /// The fast path during pushing -- either fills in the first buffer, or
  /// extends an existing one.
  ///
  /// Returns `None` if the fast path was taken and nothing more needs to be
  /// done. Returns `Some` if we need to do a slow push.
  fn try_to_extend(&mut self, b: Buf) -> Option<Buf> {
    let len = b.len();
    if len == 0 { return None; }

    match *self {
      Empty => {},
      One(ref mut b0) => {
        unsafe {
          if b0.is_extended_by(&b) {
            b0.unsafe_extend(len);
            return None;
          } else {
            return Some(b); // Upgrade the `One` into a `Many` in the slow path.
          }
        }
      }
      Many(ref mut v) => {
        // I wish this wouldn't unwind, and just abort... :(
        let last = v.last_mut().unwrap();
        unsafe {
          if last.is_extended_by(&b) {
            last.unsafe_extend(len);
            return None;
          } else {
            return Some(b);
          }
        }
      }
    }

    // Handle this case in the fast path, instead of leaving it for slow_push
    // to clean up.
    *self = One(b);
    None
  }

  /// Appends a buffer to a `BufSpan`. If the buffer is an extension of the
  /// previously pushed buffer, the range will be extended. Otherwise, the new
  /// non-extension buffer will be added to the end of a vector.
  pub fn push(&mut self, b: Buf) {
    match self.try_to_extend(b) {
      None    => {},
      Some(b) => self.slow_push(b),
    }
  }

  /// The slow path during a push. This is only taken if a `BufSpan` must span
  /// multiple backing buffers.
  #[cold]
  fn slow_push(&mut self, b: Buf) {
    let this = mem::replace(self, Empty);
    *self =
      match this {
        Empty   => One(b),
        One(b0) => {
          let mut v = Vec::with_capacity(2);
          v.push(b0);
          v.push(b);
          Many(v)
        },
        Many(mut bs) => { bs.push(b); Many(bs) }
      };
  }

  /// Returns an iterator over references to the buffers inside the `BufSpan`.
  #[inline]
  pub fn iter<'a>(&'a self) -> SpanIter<'a, Buf> {
    match *self {
      Empty       => Opt(None.into_iter()),
      One (ref b) => Opt(Some(b).into_iter()),
      Many(ref v) => Lot(v.as_slice().iter()),
    }
  }

  /// Returns a moving iterator over the buffers inside the `BufSpan`.
  #[inline]
  pub fn into_iter(self) -> SpanMoveIter<Buf> {
    match self {
      Empty   => MoveOpt(None.into_iter()),
      One (b) => MoveOpt(Some(b).into_iter()),
      Many(v) => MoveLot(v.into_iter()),
    }
  }

  /// Returns an iterator over the bytes in the `BufSpan`.
  #[inline]
  pub fn iter_bytes<'a>(&'a self) -> ByteIter<'a, Buf> {
    self.iter()
        .flat_map(|buf| unsafe { buf.as_window_slice().iter() })
        .map(|&b| b)
  }

  /// Returns `true` iff the bytes in this `BufSpan` are the same as the bytes
  /// in the other `BufSpan`.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf, RWIobuf};
  ///
  /// let a = BufSpan::from_buf(ROIobuf::from_str("hello"));
  /// let b = BufSpan::from_buf(RWIobuf::from_string("hello".into_string()));
  ///
  /// assert!(a.byte_equal(&b));
  ///
  /// let mut c = BufSpan::from_buf(ROIobuf::from_str("hel"));
  /// c.push(ROIobuf::from_str("lo"));
  ///
  /// assert!(a.byte_equal(&c)); assert!(c.byte_equal(&a));
  ///
  /// let d = BufSpan::from_buf(ROIobuf::from_str("helo"));
  /// assert!(!a.byte_equal(&d));
  /// ```
  #[inline]
  pub fn byte_equal<Buf2: Iobuf>(&self, other: &BufSpan<Buf2>) -> bool {
    self.count_bytes() == other.count_bytes()
    && self.iter_bytes().zip(other.iter_bytes()).all(|(a, b)| a == b)
  }

  /// A more efficient version of byte_equal, specialized to work exclusively on
  /// slices.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf};
  ///
  /// let a = BufSpan::from_buf(ROIobuf::from_str("hello"));
  ///
  /// assert!(a.byte_equal_slice(b"hello"));
  /// assert!(!a.byte_equal_slice(b"helo"));
  /// ```
  #[inline]
  pub fn byte_equal_slice(&self, other: &[u8]) -> bool {
    self.count_bytes() as uint == other.len()
    && self.iter_bytes().zip(other.iter()).all(|(a, &b)| a == b)
  }

  /// Counts the number of bytes this `BufSpan` is over. This is
  /// `O(self.iter().len())`.
  #[inline]
  pub fn count_bytes(&self) -> u32 {
    // `self.iter().map(|b| b.len()).sum()` would be shorter, but I like to
    // specialize for the much more common case of empty or singular `BufSpan`s.
    match *self {
      Empty       => 0,
      One (ref b) => b.len(),
      Many(ref v) => v.iter().map(|b| b.len()).sum(),
    }
  }
}

/// An iterator over the bytes in a `BufSpan`.
pub type ByteIter<'a, Buf> =
  iter::Map<'static, &'a u8, u8,
    iter::FlatMap<'static, &'a Buf,
      SpanIter<'a, Buf>,
      slice::Items<'a, u8>>>;

/// An iterator over references to buffers inside a `BufSpan`.
pub enum SpanIter<'a, Buf: 'a> {
  Opt(option::Item<&'a Buf>),
  Lot(slice::Items<'a, Buf>),
}

impl<'a, Buf: Iobuf> Iterator<&'a Buf> for SpanIter<'a, Buf> {
  #[inline(always)]
  fn next(&mut self) -> Option<&'a Buf> {
    // I'm couting on this match getting lifted out of the loop with
    // loop-invariant code motion.
    match *self {
      Opt(ref mut iter) => iter.next(),
      Lot(ref mut iter) => iter.next(),
    }
  }

  #[inline(always)]
  fn size_hint(&self) -> (uint, Option<uint>) {
    match *self {
      Opt(ref iter) => iter.size_hint(),
      Lot(ref iter) => iter.size_hint(),
    }
  }
}

/// A moving iterator over buffers inside a `BufSpan`.
pub enum SpanMoveIter<Buf> {
  MoveOpt(option::Item<Buf>),
  MoveLot(vec::MoveItems<Buf>),
}

impl<Buf: Iobuf> Iterator<Buf> for SpanMoveIter<Buf> {
  #[inline(always)]
  fn next(&mut self) -> Option<Buf> {
    // I'm couting on this match getting lifted out of the loop with
    // loop-invariant code motion.
    match *self {
      MoveOpt(ref mut iter) => iter.next(),
      MoveLot(ref mut iter) => iter.next(),
    }
  }

  #[inline(always)]
  fn size_hint(&self) -> (uint, Option<uint>) {
    match *self {
      MoveOpt(ref iter) => iter.size_hint(),
      MoveLot(ref iter) => iter.size_hint(),
    }
  }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::net::SocketAddr;
use std::rc::{Rc, Weak};
use std::cell::RefCell;

use mioco::udp::UdpSocket;
use bincode::rustc_serialize as bcode_rcs;
use sodiumoxide::crypto::secretbox as crypto_secretbox;

use ::Result;
use identity::{Identity, RemoteServer, Extension};
use packet::*;
use keys::*;
use boxes::*;
use nonces::*;

pub struct Stream {

}

impl Stream {
    pub fn new() -> Stream {
        Stream {}
    }
}

pub struct Demultiplexor {
    sock: UdpSocket,
    listeners: HashMap<Extension, Weak<RefCell<Listener>>>,
}

impl Demultiplexor {
    pub fn new(sock: UdpSocket) -> Demultiplexor {
        Demultiplexor {
            sock: sock,
            listeners: HashMap::new(),
        }
    }

    pub fn create_listener(&mut self, listener_id: Identity) -> Rc<RefCell<Listener>> {
        let listener_extension = listener_id.extension.clone();
        let listener = Rc::new(RefCell::new(Listener::new(listener_id)));

        self.listeners.insert(listener_extension, Rc::downgrade(&listener));

        listener
    }

    pub fn listen(&mut self) -> Result<()> {
        let mut buf = [0u8; PACKET_MAX_SIZE];
        loop {
            let (recv_len, rem_addr) = try!(self.sock.recv(&mut buf));
            let packet: Packet = try!(bcode_rcs::decode(&buf[..recv_len]));

            if let Some(ref mut listener) = {
                let dst_extension = packet.get_destination_extension();
                self.listeners.get_mut(dst_extension).and_then(|listener_weak|
                    listener_weak.upgrade()
                )
            } {
                try!(listener.borrow_mut().process(packet, &mut self.sock, rem_addr));
            }
        }
    }
}

pub struct Listener {
    my_extension: Extension,
    my_long_term_pk: server_long_term::PublicKey,
    my_long_term_sk: server_long_term::SecretKey,
    minute_key: crypto_secretbox::Key,
    last_minute_key: crypto_secretbox::Key,
    streams: HashMap<(Extension, client_short_term::PublicKey), Weak<RefCell<Stream>>>,
}

impl Listener {
    fn new(my_id: Identity) -> Listener {
        let (my_long_term_pk, my_long_term_sk, my_extension) = my_id.as_server();

        Listener {
            my_extension: my_extension,
            my_long_term_pk: my_long_term_pk,
            my_long_term_sk: my_long_term_sk,
            minute_key: crypto_secretbox::gen_key(),
            last_minute_key: crypto_secretbox::gen_key(),
            streams: HashMap::new(),
        }
    }

    pub fn accept(&mut self) -> Result<Stream> {
        Ok(Stream::new())
    }

    pub fn process(&mut self, packet: Packet, sock: &mut UdpSocket, rem_addr: SocketAddr) -> Result<()> {
        match packet {
            Packet::ClientMessage(client_msg_packet) => {
                if let Some(stream) = {
                    let conn_key = (client_msg_packet.client_extension.clone(), client_msg_packet.client_short_term_pk.clone());
                    self.streams.get_mut(&conn_key)
                } {

                }
            },
            Packet::Initiate(initiate_packet) => {
            },
            Packet::Hello(hello_packet) => {
                try!(self.process_hello(hello_packet, sock, rem_addr));
            },
            _ => {
                debug!("Unvalid packet type");
            }
        }

        Ok(())
    }

    fn process_hello(&self, hello_packet: HelloPacket, sock: &mut UdpSocket, rem_addr: SocketAddr) -> Result<()> {
        let client_short_term_pk = hello_packet.client_short_term_pk;
        let conn_key = (hello_packet.client_extension.clone(), client_short_term_pk.clone());

        if self.streams.contains_key(&conn_key) {
            debug!("Hello packet received on open connection");
        } else {
            hello_packet.hello_box.open(&client_short_term_pk, &self.my_long_term_sk).unwrap();

            let (server_short_term_pk, server_short_term_sk) = server_short_term::gen_keypair();

            let cookie_packet: Packet = CookiePacket {
                client_extension: hello_packet.client_extension.clone(),
                server_extension: self.my_extension.clone(),
                cookie_box: PlainCookieBox {
                    server_short_term_pk: server_short_term_pk,
                    server_cookie: PlainCookie {
                        client_short_term_pk: client_short_term_pk.clone(),
                        server_short_term_sk: server_short_term_sk.clone(),
                    }.seal(&CookieNonce::new_random(), &self.minute_key),
                }.seal(&Nonce16::new_random(), &client_short_term_pk, &self.my_long_term_sk),
            }.into();

            try!(cookie_packet.send(sock, &rem_addr));
        }

        Ok(())
    }
}
<commit_msg>Sending () to streams on ClientMsg<commit_after>use std::collections::HashMap;
use std::net::SocketAddr;
use std::rc::{Rc, Weak};
use std::cell::RefCell;

use mioco::udp::UdpSocket;
use mioco::sync::mpsc::{channel, Receiver, Sender};
use bincode::rustc_serialize as bcode_rcs;
use sodiumoxide::crypto::secretbox as crypto_secretbox;

use ::Result;
use identity::{Identity, RemoteServer, Extension};
use packet::*;
use keys::*;
use boxes::*;
use nonces::*;

pub struct Stream {

}

impl Stream {
    pub fn new() -> Stream {
        Stream {}
    }
}

pub struct Demultiplexor {
    sock: UdpSocket,
    listeners: HashMap<Extension, Weak<RefCell<Listener>>>,
}

impl Demultiplexor {
    pub fn new(sock: UdpSocket) -> Demultiplexor {
        Demultiplexor {
            sock: sock,
            listeners: HashMap::new(),
        }
    }

    pub fn create_listener(&mut self, listener_id: Identity) -> Rc<RefCell<Listener>> {
        let listener_extension = listener_id.extension.clone();
        let listener = Rc::new(RefCell::new(Listener::new(listener_id)));

        self.listeners.insert(listener_extension, Rc::downgrade(&listener));

        listener
    }

    pub fn listen(&mut self) -> Result<()> {
        let mut buf = [0u8; PACKET_MAX_SIZE];
        loop {
            let (recv_len, rem_addr) = try!(self.sock.recv(&mut buf));
            let packet: Packet = try!(bcode_rcs::decode(&buf[..recv_len]));

            if let Some(ref mut listener) = {
                let dst_extension = packet.get_destination_extension();
                self.listeners.get_mut(dst_extension).and_then(|listener_weak|
                    listener_weak.upgrade()
                )
            } {
                try!(listener.borrow_mut().process(packet, &mut self.sock, rem_addr));
            }
        }
    }
}

pub struct Listener {
    my_extension: Extension,
    my_long_term_pk: server_long_term::PublicKey,
    my_long_term_sk: server_long_term::SecretKey,
    minute_key: crypto_secretbox::Key,
    last_minute_key: crypto_secretbox::Key,
    streams: HashMap<(Extension, client_short_term::PublicKey), Sender<()>>,
}

impl Listener {
    fn new(my_id: Identity) -> Listener {
        let (my_long_term_pk, my_long_term_sk, my_extension) = my_id.as_server();

        Listener {
            my_extension: my_extension,
            my_long_term_pk: my_long_term_pk,
            my_long_term_sk: my_long_term_sk,
            minute_key: crypto_secretbox::gen_key(),
            last_minute_key: crypto_secretbox::gen_key(),
            streams: HashMap::new(),
        }
    }

    pub fn accept(&mut self) -> Result<Stream> {
        Ok(Stream::new())
    }

    pub fn process(&mut self, packet: Packet, sock: &mut UdpSocket, rem_addr: SocketAddr) -> Result<()> {
        match packet {
            Packet::ClientMessage(client_msg_packet) => {
                let mut preserve = true;
                let conn_key = (client_msg_packet.client_extension.clone(),
                                client_msg_packet.client_short_term_pk.clone());

                if let Some(stream_ch) = self.streams.get_mut(&conn_key) {
                    let send_res = stream_ch.send(());
                    preserve = send_res.is_ok();
                }

                if !preserve {
                    self.streams.remove(&conn_key);
                }
            },
            Packet::Initiate(initiate_packet) => {
            },
            Packet::Hello(hello_packet) => {
                try!(self.process_hello(hello_packet, sock, rem_addr));
            },
            _ => {
                debug!("Unvalid packet type");
            }
        }

        Ok(())
    }

    fn process_hello(&self, hello_packet: HelloPacket, sock: &mut UdpSocket, rem_addr: SocketAddr) -> Result<()> {
        let client_short_term_pk = hello_packet.client_short_term_pk;
        let conn_key = (hello_packet.client_extension.clone(), client_short_term_pk.clone());

        if self.streams.contains_key(&conn_key) {
            debug!("Hello packet received on open connection");
        } else {
            hello_packet.hello_box.open(&client_short_term_pk, &self.my_long_term_sk).unwrap();

            let (server_short_term_pk, server_short_term_sk) = server_short_term::gen_keypair();

            let cookie_packet: Packet = CookiePacket {
                client_extension: hello_packet.client_extension.clone(),
                server_extension: self.my_extension.clone(),
                cookie_box: PlainCookieBox {
                    server_short_term_pk: server_short_term_pk,
                    server_cookie: PlainCookie {
                        client_short_term_pk: client_short_term_pk.clone(),
                        server_short_term_sk: server_short_term_sk.clone(),
                    }.seal(&CookieNonce::new_random(), &self.minute_key),
                }.seal(&Nonce16::new_random(), &client_short_term_pk, &self.my_long_term_sk),
            }.into();

            try!(cookie_packet.send(sock, &rem_addr));
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::TextUnit;

use std::str::Chars;

/// A simple view into the characters of a string.
pub(crate) struct Ptr<'s> {
    text: &'s str,
    len: TextUnit,
}

impl<'s> Ptr<'s> {
    /// Creates a new `Ptr` from a string.
    pub fn new(text: &'s str) -> Ptr<'s> {
        Ptr {
            text,
            len: 0.into(),
        }
    }

    /// Gets the length of the remaining string.
    pub fn into_len(self) -> TextUnit {
        self.len
    }

    /// Gets the current character, if one exists.
    pub fn current(&self) -> Option<char> {
        self.chars().next()
    }

    /// Gets the nth character from the current.
    /// For example, 0 will return the current token, 1 will return the next, etc.
    pub fn nth(&self, n: u32) -> Option<char> {
        self.chars().nth(n as usize)
    }

    /// Checks whether the current character is `c`.
    pub fn at(&self, c: char) -> bool {
        self.current() == Some(c)
    }

    /// Checks whether the next characters match `s`.
    pub fn at_str(&self, s: &str) -> bool {
        let chars = self.chars();
        chars.as_str().starts_with(s)
    }

    /// Checks whether the current character satisfies the predicate `p`.
    pub fn at_p<P: Fn(char) -> bool>(&self, p: P) -> bool {
        self.current().map(p) == Some(true)
    }

    /// Checks whether the nth character satisfies the predicate `p`.
    pub fn nth_is_p<P: Fn(char) -> bool>(&self, n: u32, p: P) -> bool {
        self.nth(n).map(p) == Some(true)
    }

    /// Moves to the next character.
    pub fn bump(&mut self) -> Option<char> {
        let ch = self.chars().next()?;
        self.len += TextUnit::of_char(ch);
        Some(ch)
    }

    /// Moves to the next character as long as `pred` is satisfied.
    pub fn bump_while<F: Fn(char) -> bool>(&mut self, pred: F) {
        loop {
            match self.current() {
                Some(c) if pred(c) => {
                    self.bump();
                }
                _ => return,
            }
        }
    }

    /// Returns the text up to the current point.
    pub fn current_token_text(&self) -> &str {
        let len: u32 = self.len.into();
        &self.text[..len as usize]
    }

    /// Returns an iterator over the remaining characters.
    fn chars(&self) -> Chars {
        let len: u32 = self.len.into();
        self.text[len as usize..].chars()
    }
}

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

    #[test]
    fn test_current() {
        let ptr = Ptr::new("test");
        assert_eq!(ptr.current(), Some('t'));
    }

    #[test]
    fn test_nth() {
        let ptr = Ptr::new("test");
        assert_eq!(ptr.nth(0), Some('t'));
        assert_eq!(ptr.nth(1), Some('e'));
        assert_eq!(ptr.nth(2), Some('s'));
        assert_eq!(ptr.nth(3), Some('t'));
        assert_eq!(ptr.nth(4), None);
    }

    #[test]
    fn test_at() {
        let ptr = Ptr::new("test");
        assert!(ptr.at('t'));
        assert!(!ptr.at('a'));
    }

    #[test]
    fn test_at_str() {
        let ptr = Ptr::new("test");
        assert!(ptr.at_str("t"));
        assert!(ptr.at_str("te"));
        assert!(ptr.at_str("test"));
        assert!(!ptr.at_str("tests"));
        assert!(!ptr.at_str("rust"));
    }

    #[test]
    fn test_at_p() {
        let ptr = Ptr::new("test");
        assert!(ptr.at_p(|c| c == 't'));
        assert!(!ptr.at_p(|c| c == 'e'));
    }

    #[test]
    fn test_nth_is_p() {
        let ptr = Ptr::new("test");
        assert!(ptr.nth_is_p(0, |c| c == 't'));
        assert!(!ptr.nth_is_p(1, |c| c == 't'));
        assert!(ptr.nth_is_p(3, |c| c == 't'));
        assert!(!ptr.nth_is_p(150, |c| c == 't'));
    }

    #[test]
    fn test_bump() {
        let mut ptr = Ptr::new("test");
        assert_eq!(ptr.current(), Some('t'));
        ptr.bump();
        assert_eq!(ptr.current(), Some('e'));
        ptr.bump();
        assert_eq!(ptr.current(), Some('s'));
        ptr.bump();
        assert_eq!(ptr.current(), Some('t'));
        ptr.bump();
        assert_eq!(ptr.current(), None);
        ptr.bump();
        assert_eq!(ptr.current(), None);
    }

    #[test]
    fn test_bump_while() {
        let mut ptr = Ptr::new("test");
        assert_eq!(ptr.current(), Some('t'));
        ptr.bump_while(|c| c != 's');
        assert_eq!(ptr.current(), Some('s'));
    }
}
<commit_msg>Fix a copy and pasting typo<commit_after>use crate::TextUnit;

use std::str::Chars;

/// A simple view into the characters of a string.
pub(crate) struct Ptr<'s> {
    text: &'s str,
    len: TextUnit,
}

impl<'s> Ptr<'s> {
    /// Creates a new `Ptr` from a string.
    pub fn new(text: &'s str) -> Ptr<'s> {
        Ptr {
            text,
            len: 0.into(),
        }
    }

    /// Gets the length of the remaining string.
    pub fn into_len(self) -> TextUnit {
        self.len
    }

    /// Gets the current character, if one exists.
    pub fn current(&self) -> Option<char> {
        self.chars().next()
    }

    /// Gets the nth character from the current.
    /// For example, 0 will return the current character, 1 will return the next, etc.
    pub fn nth(&self, n: u32) -> Option<char> {
        self.chars().nth(n as usize)
    }

    /// Checks whether the current character is `c`.
    pub fn at(&self, c: char) -> bool {
        self.current() == Some(c)
    }

    /// Checks whether the next characters match `s`.
    pub fn at_str(&self, s: &str) -> bool {
        let chars = self.chars();
        chars.as_str().starts_with(s)
    }

    /// Checks whether the current character satisfies the predicate `p`.
    pub fn at_p<P: Fn(char) -> bool>(&self, p: P) -> bool {
        self.current().map(p) == Some(true)
    }

    /// Checks whether the nth character satisfies the predicate `p`.
    pub fn nth_is_p<P: Fn(char) -> bool>(&self, n: u32, p: P) -> bool {
        self.nth(n).map(p) == Some(true)
    }

    /// Moves to the next character.
    pub fn bump(&mut self) -> Option<char> {
        let ch = self.chars().next()?;
        self.len += TextUnit::of_char(ch);
        Some(ch)
    }

    /// Moves to the next character as long as `pred` is satisfied.
    pub fn bump_while<F: Fn(char) -> bool>(&mut self, pred: F) {
        loop {
            match self.current() {
                Some(c) if pred(c) => {
                    self.bump();
                }
                _ => return,
            }
        }
    }

    /// Returns the text up to the current point.
    pub fn current_token_text(&self) -> &str {
        let len: u32 = self.len.into();
        &self.text[..len as usize]
    }

    /// Returns an iterator over the remaining characters.
    fn chars(&self) -> Chars {
        let len: u32 = self.len.into();
        self.text[len as usize..].chars()
    }
}

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

    #[test]
    fn test_current() {
        let ptr = Ptr::new("test");
        assert_eq!(ptr.current(), Some('t'));
    }

    #[test]
    fn test_nth() {
        let ptr = Ptr::new("test");
        assert_eq!(ptr.nth(0), Some('t'));
        assert_eq!(ptr.nth(1), Some('e'));
        assert_eq!(ptr.nth(2), Some('s'));
        assert_eq!(ptr.nth(3), Some('t'));
        assert_eq!(ptr.nth(4), None);
    }

    #[test]
    fn test_at() {
        let ptr = Ptr::new("test");
        assert!(ptr.at('t'));
        assert!(!ptr.at('a'));
    }

    #[test]
    fn test_at_str() {
        let ptr = Ptr::new("test");
        assert!(ptr.at_str("t"));
        assert!(ptr.at_str("te"));
        assert!(ptr.at_str("test"));
        assert!(!ptr.at_str("tests"));
        assert!(!ptr.at_str("rust"));
    }

    #[test]
    fn test_at_p() {
        let ptr = Ptr::new("test");
        assert!(ptr.at_p(|c| c == 't'));
        assert!(!ptr.at_p(|c| c == 'e'));
    }

    #[test]
    fn test_nth_is_p() {
        let ptr = Ptr::new("test");
        assert!(ptr.nth_is_p(0, |c| c == 't'));
        assert!(!ptr.nth_is_p(1, |c| c == 't'));
        assert!(ptr.nth_is_p(3, |c| c == 't'));
        assert!(!ptr.nth_is_p(150, |c| c == 't'));
    }

    #[test]
    fn test_bump() {
        let mut ptr = Ptr::new("test");
        assert_eq!(ptr.current(), Some('t'));
        ptr.bump();
        assert_eq!(ptr.current(), Some('e'));
        ptr.bump();
        assert_eq!(ptr.current(), Some('s'));
        ptr.bump();
        assert_eq!(ptr.current(), Some('t'));
        ptr.bump();
        assert_eq!(ptr.current(), None);
        ptr.bump();
        assert_eq!(ptr.current(), None);
    }

    #[test]
    fn test_bump_while() {
        let mut ptr = Ptr::new("test");
        assert_eq!(ptr.current(), Some('t'));
        ptr.bump_while(|c| c != 's');
        assert_eq!(ptr.current(), Some('s'));
    }
}
<|endoftext|>