<commit_before>//! Defines the core functionality.
use getopts::Matches;
use std::fs::OpenOptions;
use std::io;
use std::io::BufWriter;
use std::io::Result;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use super::error;
use super::opts;
use super::text;

/// Named constants used to indicate the authorization context.
pub enum Auth {
    /// The path is absolute (has root).
    Absolute,
    /// The 'interactive' option is present.
    Interactive,
}

/// Authorizes directory and file access by prompting the user and reading the
/// standard input. `true` will be returned if the user grants permission and
/// `false` will be returned otherwise.
/// # Issues
/// - If the standard input is closed or empty, no error will be raised and the
/// loop will continue indefinitely.
pub fn auth(path: &Path, auth: Auth) -> bool {
    let stdin_err = format_sys!("{}", error::MSTDINERR);

    // Determine the appropriate prompt
    let prompt = match auth {
        Auth::Absolute => text::ABSOLUTE,
        Auth::Interactive => text::INTERACTIVE,
    };

    loop {
        // Reset the input buffer with every pass
        let mut input = String::new();

        // Print a confirmation prompt and wait for input
        sys!("'{}' {} {} ", path.display(), prompt, text::CONTINUE).unwrap();
        io::stdin().read_line(&mut input).expect(&stdin_err);

        // Normalize the input for comparison
        input = input.trim().to_lowercase();

        // The response must be YES or NO
        match input.as_str() {
            text::YES => return true,
            text::NO => {
                sysln!("{}", text::SKIP).unwrap();
                return false;
            },
            _ => continue,
        }
    }
}

/// Adds all files *in* the given directory to the `list`. If the 'recursive'
/// option is present, all files *under* the given directory will be added to
/// the `list`.
pub fn collect_files(dir: &Path, list: &mut Vec<PathBuf>, matches: &Matches) -> Result<()> {

    // Iterate over all entries in the directory
    for entry in try!(dir.read_dir()) {
        let path = try!(entry).path();

        // Recurse if the entry is a directory (optional)
        if matches.opt_present(opts::RECURSIVE.short) && path.is_dir() {
            try!(collect_files(&path, list, matches));

        // If the entry is a file, add it to the list
        } else if path.is_file() {
            list.push(path);
        }
    }
    return Ok(());
}

/// Overwrites the given file. Authorization may be requested and additional
/// information may be printed if the 'interactive' and 'verbose' options are
/// present. The file will not be overwritten during a 'dry-run'.
pub fn overwrite_file(path: &Path, matches: &Matches) -> Result<()> {

    // Authorize every file (optional)
    if matches.opt_present(opts::INTERACTIVE.short) && !matches.opt_present(opts::SUPPRESS.short) {
        match auth(&path, Auth::Interactive) {
            true => (),
            false => return Ok(()),
        }
    }

    // Unwrap the file metadata
    let metadata = try!(path.metadata());

    // Overwrite the file or perform a dry run (optional)
    if !matches.opt_present(opts::DRYRUN.short) {

        // Open the file and wrap it in a buffered writer
        let mut file = try!(OpenOptions::new().write(true).open(path));
        let mut buffer = BufWriter::new(file);

        // Overwrite the file
        for _ in 0..metadata.len() {
            try!(buffer.write(b"\0"));
        }

        // Flush the buffer and write to the disk
        file = try!(buffer.into_inner());
        try!(file.sync_all());

        // Print the result to the standard output (optional)
        if matches.opt_present(opts::VERBOSE.short) {
            println!("'{}': {} {}", path.display(), metadata.len(), text::OVERWRITE);
        }
    } else {
        println!("'{}': {} {}", path.display(), metadata.len(), text::DRYRUN);
    }
    return Ok(());
}

/// Calls `overwrite_file` for each file in the `list` and handles all
/// associated errors internally.
pub fn overwrite_files(list: &Vec<PathBuf>, matches: &Matches) {
    for file in list.iter() {
        match overwrite_file(file, matches) {
            Ok(_) => (),
            Err(e) => {
                sysln!("{} '{}': {}", error::MACCESS, file.display(), e).unwrap();
                continue;
            },
        }
    }
}
<commit_msg>Replaced the try macro (1.13)<commit_after>//! Defines the core functionality.
use getopts::Matches;
use std::fs::OpenOptions;
use std::io;
use std::io::BufWriter;
use std::io::Result;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use super::error;
use super::opts;
use super::text;

/// Named constants used to indicate the authorization context.
pub enum Auth {
    /// The path is absolute (has root).
    Absolute,
    /// The 'interactive' option is present.
    Interactive,
}

/// Authorizes directory and file access by prompting the user and reading the
/// standard input. `true` will be returned if the user grants permission and
/// `false` will be returned otherwise.
/// # Issues
/// - If the standard input is closed or empty, no error will be raised and the
/// loop will continue indefinitely.
pub fn auth(path: &Path, auth: Auth) -> bool {
    let stdin_err = format_sys!("{}", error::MSTDINERR);

    // Determine the appropriate prompt
    let prompt = match auth {
        Auth::Absolute => text::ABSOLUTE,
        Auth::Interactive => text::INTERACTIVE,
    };

    loop {
        // Reset the input buffer with every pass
        let mut input = String::new();

        // Print a confirmation prompt and wait for input
        sys!("'{}' {} {} ", path.display(), prompt, text::CONTINUE).unwrap();
        io::stdin().read_line(&mut input).expect(&stdin_err);

        // Normalize the input for comparison
        input = input.trim().to_lowercase();

        // The response must be YES or NO
        match input.as_str() {
            text::YES => return true,
            text::NO => {
                sysln!("{}", text::SKIP).unwrap();
                return false;
            },
            _ => continue,
        }
    }
}

/// Adds all files *in* the given directory to the `list`. If the 'recursive'
/// option is present, all files *under* the given directory will be added to
/// the `list`.
pub fn collect_files(dir: &Path, list: &mut Vec<PathBuf>, matches: &Matches) -> Result<()> {

    // Iterate over all entries in the directory
    for entry in dir.read_dir()? {
        let path = entry?.path();

        // Recurse if the entry is a directory (optional)
        if matches.opt_present(opts::RECURSIVE.short) && path.is_dir() {
            collect_files(&path, list, matches)?;

        // If the entry is a file, add it to the list
        } else if path.is_file() {
            list.push(path);
        }
    }
    return Ok(());
}

/// Overwrites the given file. Authorization may be requested and additional
/// information may be printed if the 'interactive' and 'verbose' options are
/// present. The file will not be overwritten during a 'dry-run'.
pub fn overwrite_file(path: &Path, matches: &Matches) -> Result<()> {

    // Authorize every file (optional)
    if matches.opt_present(opts::INTERACTIVE.short) && !matches.opt_present(opts::SUPPRESS.short) {
        match auth(&path, Auth::Interactive) {
            true => (),
            false => return Ok(()),
        }
    }

    // Unwrap the file metadata
    let metadata = path.metadata()?;

    // Overwrite the file or perform a dry run (optional)
    if !matches.opt_present(opts::DRYRUN.short) {

        // Open the file and wrap it in a buffered writer
        let mut file = OpenOptions::new().write(true).open(path)?;
        let mut buffer = BufWriter::new(file);

        // Overwrite the file
        for _ in 0..metadata.len() {
            buffer.write(b"\0")?;
        }

        // Flush the buffer and write to the disk
        file = buffer.into_inner()?;
        file.sync_all()?;

        // Print the result to the standard output (optional)
        if matches.opt_present(opts::VERBOSE.short) {
            println!("'{}': {} {}", path.display(), metadata.len(), text::OVERWRITE);
        }
    } else {
        println!("'{}': {} {}", path.display(), metadata.len(), text::DRYRUN);
    }
    return Ok(());
}

/// Calls `overwrite_file` for each file in the `list` and handles all
/// associated errors internally.
pub fn overwrite_files(list: &Vec<PathBuf>, matches: &Matches) {
    for file in list.iter() {
        match overwrite_file(file, matches) {
            Ok(_) => (),
            Err(e) => {
                sysln!("{} '{}': {}", error::MACCESS, file.display(), e).unwrap();
                continue;
            },
        }
    }
}
<|endoftext|>


<commit_before>/// Literal kind.
///
/// E.g. `"foo"`, `42`, `12.34` or `bool`
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Lit {
    /// A string literal (`"foo"`)
    Str(String, StrStyle),
    /// A byte string (`b"foo"`)
    ByteStr(Vec<u8>, StrStyle),
    /// A byte char (`b'f'`)
    Byte(u8),
    /// A character literal (`'a'`)
    Char(char),
    /// An integer literal (`1`)
    Int(u64, IntTy),
    /// A float literal (`1f64` or `1E10f64` or `1.0E10`)
    Float(String, FloatTy),
    /// A boolean literal
    Bool(bool),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum StrStyle {
    /// A regular string, like `"foo"`
    Cooked,
    /// A raw string, like `r##"foo"##`
    ///
    /// The uint is the number of `#` symbols used
    Raw(usize),
}

impl From<String> for Lit {
    fn from(input: String) -> Lit {
        Lit::Str(input, StrStyle::Cooked)
    }
}

impl<'a> From<&'a str> for Lit {
    fn from(input: &str) -> Lit {
        Lit::Str(input.into(), StrStyle::Cooked)
    }
}

impl From<Vec<u8>> for Lit {
    fn from(input: Vec<u8>) -> Lit {
        Lit::ByteStr(input, StrStyle::Cooked)
    }
}

impl<'a> From<&'a [u8]> for Lit {
    fn from(input: &[u8]) -> Lit {
        Lit::ByteStr(input.into(), StrStyle::Cooked)
    }
}

impl From<char> for Lit {
    fn from(input: char) -> Lit {
        Lit::Char(input)
    }
}

impl From<bool> for Lit {
    fn from(input: bool) -> Lit {
        Lit::Bool(input)
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IntTy {
    Isize,
    I8,
    I16,
    I32,
    I64,
    Usize,
    U8,
    U16,
    U32,
    U64,
    Unsuffixed,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum FloatTy {
    F32,
    F64,
    Unsuffixed,
}

macro_rules! impl_from_for_lit {
    (Int, [$($rust_type:ty => $syn_type:expr),+]) => {
        $(
            impl From<$rust_type> for Lit {
                fn from(input: $rust_type) -> Lit {
                    Lit::Int(input as u64, $syn_type)
                }
            }
        )+
    };
    (Float, [$($rust_type:ty => $syn_type:expr),+]) => {
        $(
            impl From<$rust_type> for Lit {
                fn from(input: $rust_type) -> Lit {
                    Lit::Float(format!("{}", input), $syn_type)
                }
            }
        )+
    };
}

impl_from_for_lit! {Int, [
    isize => IntTy::Isize,
    i8 => IntTy::I8,
    i16 => IntTy::I16,
    i32 => IntTy::I32,
    i64 => IntTy::I64,
    usize => IntTy::Usize,
    u8 => IntTy::U8,
    u16 => IntTy::U16,
    u32 => IntTy::U32,
    u64 => IntTy::U64
]}

impl_from_for_lit! {Float, [
    f32 => FloatTy::F32,
    f64 => FloatTy::F64
]}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use escape::{cooked_char, cooked_string, raw_string};
    use space::whitespace;
    use nom::IResult;
    use unicode_xid::UnicodeXID;

    named!(pub lit -> Lit, alt!(
        string
        |
        byte_string
        |
        byte
        |
        character
        |
        float // must be before int
        |
        int => { |(value, ty)| Lit::Int(value, ty) }
        |
        boolean
    ));

    named!(string -> Lit, alt!(
        quoted_string => { |s| Lit::Str(s, StrStyle::Cooked) }
        |
        preceded!(
            punct!("r"),
            raw_string
        ) => { |(s, n)| Lit::Str(s, StrStyle::Raw(n)) }
    ));

    named!(pub quoted_string -> String, delimited!(
        punct!("\""),
        cooked_string,
        tag!("\"")
    ));

    named!(byte_string -> Lit, alt!(
        delimited!(
            punct!("b\""),
            cooked_string,
            tag!("\"")
        ) => { |s: String| Lit::ByteStr(s.into_bytes(), StrStyle::Cooked) }
        |
        preceded!(
            punct!("br"),
            raw_string
        ) => { |(s, n): (String, _)| Lit::ByteStr(s.into_bytes(), StrStyle::Raw(n)) }
    ));

    named!(byte -> Lit, do_parse!(
        punct!("b") >>
        tag!("'") >>
        ch: cooked_char >>
        tag!("'") >>
        (Lit::Byte(ch as u8))
    ));

    named!(character -> Lit, do_parse!(
        punct!("'") >>
        ch: cooked_char >>
        tag!("'") >>
        (Lit::Char(ch))
    ));

    named!(float -> Lit, do_parse!(
        option!(whitespace) >>
        value: float_string >>
        suffix: alt!(
            tag!("f32") => { |_| FloatTy::F32 }
            |
            tag!("f64") => { |_| FloatTy::F64 }
            |
            epsilon!() => { |_| FloatTy::Unsuffixed }
        ) >>
        (Lit::Float(value, suffix))
    ));

    named!(pub int -> (u64, IntTy), tuple!(
        preceded!(
            option!(whitespace),
            digits
        ),
        alt!(
            tag!("isize") => { |_| IntTy::Isize }
            |
            tag!("i8") => { |_| IntTy::I8 }
            |
            tag!("i16") => { |_| IntTy::I16 }
            |
            tag!("i32") => { |_| IntTy::I32 }
            |
            tag!("i64") => { |_| IntTy::I64 }
            |
            tag!("usize") => { |_| IntTy::Usize }
            |
            tag!("u8") => { |_| IntTy::U8 }
            |
            tag!("u16") => { |_| IntTy::U16 }
            |
            tag!("u32") => { |_| IntTy::U32 }
            |
            tag!("u64") => { |_| IntTy::U64 }
            |
            epsilon!() => { |_| IntTy::Unsuffixed }
        )
    ));

    named!(boolean -> Lit, alt!(
        keyword!("true") => { |_| Lit::Bool(true) }
        |
        keyword!("false") => { |_| Lit::Bool(false) }
    ));

    fn float_string(input: &str) -> IResult<&str, String> {
        let mut chars = input.chars().peekable();
        match chars.next() {
            Some(ch) if ch >= '0' && ch <= '9' => {}
            _ => return IResult::Error,
        }

        let mut len = 1;
        let mut has_dot = false;
        let mut has_exp = false;
        while let Some(&ch) = chars.peek() {
            match ch {
                '0'...'9' | '_' => {
                    chars.next();
                    len += 1;
                }
                '.' => {
                    if has_dot {
                        break;
                    }
                    chars.next();
                    if chars.peek()
                        .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
                        .unwrap_or(false) {
                        return IResult::Error;
                    }
                    len += 1;
                    has_dot = true;
                }
                'e' | 'E' => {
                    chars.next();
                    len += 1;
                    has_exp = true;
                    break;
                }
                _ => break,
            }
        }

        let rest = &input[len..];
        if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
            return IResult::Error;
        }

        if has_exp {
            let mut has_exp_value = false;
            while let Some(&ch) = chars.peek() {
                match ch {
                    '+' | '-' => {
                        if has_exp_value {
                            break;
                        }
                        chars.next();
                        len += 1;
                    }
                    '0'...'9' => {
                        chars.next();
                        len += 1;
                        has_exp_value = true;
                    }
                    '_' => {
                        chars.next();
                        len += 1;
                    }
                    _ => break,
                }
            }
            if !has_exp_value {
                return IResult::Error;
            }
        }

        IResult::Done(&input[len..], input[..len].into())
    }

    pub fn digits(input: &str) -> IResult<&str, u64> {
        let mut value = 0u64;
        let mut len = 0;
        let mut empty = true;
        for b in input.bytes() {
            match b {
                b'0'...b'9' => {
                    value = match value.checked_mul(10) {
                        Some(value) => value,
                        None => return IResult::Error,
                    };
                    value = match value.checked_add((b - b'0') as u64) {
                        Some(value) => value,
                        None => return IResult::Error,
                    };
                    len += 1;
                    empty = false;
                }
                b'_' => {
                    if empty {
                        return IResult::Error;
                    }
                    len += 1;
                }
                _ => break,
            }
        }
        if empty {
            IResult::Error
        } else {
            IResult::Done(&input[len..], value)
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};
    use std::{ascii, iter};
    use std::fmt::{self, Display};
    use std::str;

    impl ToTokens for Lit {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
                Lit::Str(ref s, StrStyle::Raw(n)) => {
                    tokens.append(&format!("r{delim}\"{string}\"{delim}",
                        delim = iter::repeat("#").take(n).collect::<String>(),
                        string = s));
                }
                Lit::ByteStr(ref v, StrStyle::Cooked) => {
                    let mut escaped = "b\"".to_string();
                    for &ch in v.iter() {
                        escaped.extend(ascii::escape_default(ch).map(|c| c as char));
                    }
                    escaped.push('"');
                    tokens.append(&escaped);
                }
                Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
                    tokens.append(&format!("br{delim}\"{string}\"{delim}",
                        delim = iter::repeat("#").take(n).collect::<String>(),
                        string = str::from_utf8(vec).unwrap()));
                }
                Lit::Byte(b) => tokens.append(&format!("b{:?}", b as char)),
                Lit::Char(ch) => ch.to_tokens(tokens),
                Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
                Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
                Lit::Bool(true) => tokens.append("true"),
                Lit::Bool(false) => tokens.append("false"),
            }
        }
    }

    impl Display for IntTy {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
            match *self {
                IntTy::Isize => formatter.write_str("isize"),
                IntTy::I8 => formatter.write_str("i8"),
                IntTy::I16 => formatter.write_str("i16"),
                IntTy::I32 => formatter.write_str("i32"),
                IntTy::I64 => formatter.write_str("i64"),
                IntTy::Usize => formatter.write_str("usize"),
                IntTy::U8 => formatter.write_str("u8"),
                IntTy::U16 => formatter.write_str("u16"),
                IntTy::U32 => formatter.write_str("u32"),
                IntTy::U64 => formatter.write_str("u64"),
                IntTy::Unsuffixed => Ok(()),
            }
        }
    }

    impl Display for FloatTy {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
            match *self {
                FloatTy::F32 => formatter.write_str("f32"),
                FloatTy::F64 => formatter.write_str("f64"),
                FloatTy::Unsuffixed => Ok(()),
            }
        }
    }
}
<commit_msg>Hex, octal, binary integer literals<commit_after>/// Literal kind.
///
/// E.g. `"foo"`, `42`, `12.34` or `bool`
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Lit {
    /// A string literal (`"foo"`)
    Str(String, StrStyle),
    /// A byte string (`b"foo"`)
    ByteStr(Vec<u8>, StrStyle),
    /// A byte char (`b'f'`)
    Byte(u8),
    /// A character literal (`'a'`)
    Char(char),
    /// An integer literal (`1`)
    Int(u64, IntTy),
    /// A float literal (`1f64` or `1E10f64` or `1.0E10`)
    Float(String, FloatTy),
    /// A boolean literal
    Bool(bool),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum StrStyle {
    /// A regular string, like `"foo"`
    Cooked,
    /// A raw string, like `r##"foo"##`
    ///
    /// The uint is the number of `#` symbols used
    Raw(usize),
}

impl From<String> for Lit {
    fn from(input: String) -> Lit {
        Lit::Str(input, StrStyle::Cooked)
    }
}

impl<'a> From<&'a str> for Lit {
    fn from(input: &str) -> Lit {
        Lit::Str(input.into(), StrStyle::Cooked)
    }
}

impl From<Vec<u8>> for Lit {
    fn from(input: Vec<u8>) -> Lit {
        Lit::ByteStr(input, StrStyle::Cooked)
    }
}

impl<'a> From<&'a [u8]> for Lit {
    fn from(input: &[u8]) -> Lit {
        Lit::ByteStr(input.into(), StrStyle::Cooked)
    }
}

impl From<char> for Lit {
    fn from(input: char) -> Lit {
        Lit::Char(input)
    }
}

impl From<bool> for Lit {
    fn from(input: bool) -> Lit {
        Lit::Bool(input)
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IntTy {
    Isize,
    I8,
    I16,
    I32,
    I64,
    Usize,
    U8,
    U16,
    U32,
    U64,
    Unsuffixed,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum FloatTy {
    F32,
    F64,
    Unsuffixed,
}

macro_rules! impl_from_for_lit {
    (Int, [$($rust_type:ty => $syn_type:expr),+]) => {
        $(
            impl From<$rust_type> for Lit {
                fn from(input: $rust_type) -> Lit {
                    Lit::Int(input as u64, $syn_type)
                }
            }
        )+
    };
    (Float, [$($rust_type:ty => $syn_type:expr),+]) => {
        $(
            impl From<$rust_type> for Lit {
                fn from(input: $rust_type) -> Lit {
                    Lit::Float(format!("{}", input), $syn_type)
                }
            }
        )+
    };
}

impl_from_for_lit! {Int, [
    isize => IntTy::Isize,
    i8 => IntTy::I8,
    i16 => IntTy::I16,
    i32 => IntTy::I32,
    i64 => IntTy::I64,
    usize => IntTy::Usize,
    u8 => IntTy::U8,
    u16 => IntTy::U16,
    u32 => IntTy::U32,
    u64 => IntTy::U64
]}

impl_from_for_lit! {Float, [
    f32 => FloatTy::F32,
    f64 => FloatTy::F64
]}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use escape::{cooked_char, cooked_string, raw_string};
    use space::whitespace;
    use nom::IResult;
    use unicode_xid::UnicodeXID;

    named!(pub lit -> Lit, alt!(
        string
        |
        byte_string
        |
        byte
        |
        character
        |
        float // must be before int
        |
        int => { |(value, ty)| Lit::Int(value, ty) }
        |
        boolean
    ));

    named!(string -> Lit, alt!(
        quoted_string => { |s| Lit::Str(s, StrStyle::Cooked) }
        |
        preceded!(
            punct!("r"),
            raw_string
        ) => { |(s, n)| Lit::Str(s, StrStyle::Raw(n)) }
    ));

    named!(pub quoted_string -> String, delimited!(
        punct!("\""),
        cooked_string,
        tag!("\"")
    ));

    named!(byte_string -> Lit, alt!(
        delimited!(
            punct!("b\""),
            cooked_string,
            tag!("\"")
        ) => { |s: String| Lit::ByteStr(s.into_bytes(), StrStyle::Cooked) }
        |
        preceded!(
            punct!("br"),
            raw_string
        ) => { |(s, n): (String, _)| Lit::ByteStr(s.into_bytes(), StrStyle::Raw(n)) }
    ));

    named!(byte -> Lit, do_parse!(
        punct!("b") >>
        tag!("'") >>
        ch: cooked_char >>
        tag!("'") >>
        (Lit::Byte(ch as u8))
    ));

    named!(character -> Lit, do_parse!(
        punct!("'") >>
        ch: cooked_char >>
        tag!("'") >>
        (Lit::Char(ch))
    ));

    named!(float -> Lit, do_parse!(
        option!(whitespace) >>
        value: float_string >>
        suffix: alt!(
            tag!("f32") => { |_| FloatTy::F32 }
            |
            tag!("f64") => { |_| FloatTy::F64 }
            |
            epsilon!() => { |_| FloatTy::Unsuffixed }
        ) >>
        (Lit::Float(value, suffix))
    ));

    named!(pub int -> (u64, IntTy), tuple!(
        preceded!(
            option!(whitespace),
            digits
        ),
        alt!(
            tag!("isize") => { |_| IntTy::Isize }
            |
            tag!("i8") => { |_| IntTy::I8 }
            |
            tag!("i16") => { |_| IntTy::I16 }
            |
            tag!("i32") => { |_| IntTy::I32 }
            |
            tag!("i64") => { |_| IntTy::I64 }
            |
            tag!("usize") => { |_| IntTy::Usize }
            |
            tag!("u8") => { |_| IntTy::U8 }
            |
            tag!("u16") => { |_| IntTy::U16 }
            |
            tag!("u32") => { |_| IntTy::U32 }
            |
            tag!("u64") => { |_| IntTy::U64 }
            |
            epsilon!() => { |_| IntTy::Unsuffixed }
        )
    ));

    named!(boolean -> Lit, alt!(
        keyword!("true") => { |_| Lit::Bool(true) }
        |
        keyword!("false") => { |_| Lit::Bool(false) }
    ));

    fn float_string(input: &str) -> IResult<&str, String> {
        let mut chars = input.chars().peekable();
        match chars.next() {
            Some(ch) if ch >= '0' && ch <= '9' => {}
            _ => return IResult::Error,
        }

        let mut len = 1;
        let mut has_dot = false;
        let mut has_exp = false;
        while let Some(&ch) = chars.peek() {
            match ch {
                '0'...'9' | '_' => {
                    chars.next();
                    len += 1;
                }
                '.' => {
                    if has_dot {
                        break;
                    }
                    chars.next();
                    if chars.peek()
                        .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
                        .unwrap_or(false) {
                        return IResult::Error;
                    }
                    len += 1;
                    has_dot = true;
                }
                'e' | 'E' => {
                    chars.next();
                    len += 1;
                    has_exp = true;
                    break;
                }
                _ => break,
            }
        }

        let rest = &input[len..];
        if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
            return IResult::Error;
        }

        if has_exp {
            let mut has_exp_value = false;
            while let Some(&ch) = chars.peek() {
                match ch {
                    '+' | '-' => {
                        if has_exp_value {
                            break;
                        }
                        chars.next();
                        len += 1;
                    }
                    '0'...'9' => {
                        chars.next();
                        len += 1;
                        has_exp_value = true;
                    }
                    '_' => {
                        chars.next();
                        len += 1;
                    }
                    _ => break,
                }
            }
            if !has_exp_value {
                return IResult::Error;
            }
        }

        IResult::Done(&input[len..], input[..len].into())
    }

    pub fn digits(mut input: &str) -> IResult<&str, u64> {
        let base = if input.starts_with("0x") {
            input = &input[2..];
            16
        } else if input.starts_with("0o") {
            input = &input[2..];
            8
        } else if input.starts_with("0b") {
            input = &input[2..];
            2
        } else {
            10
        };

        let mut value = 0u64;
        let mut len = 0;
        let mut empty = true;
        for b in input.bytes() {
            let digit = match b {
                b'0'...b'9' => (b - b'0') as u64,
                b'a'...b'f' => 10 + (b - b'a') as u64,
                b'A'...b'F' => 10 + (b - b'A') as u64,
                b'_' => {
                    if empty {
                        return IResult::Error;
                    }
                    len += 1;
                    continue;
                }
                _ => break,
            };
            if digit >= base {
                return IResult::Error;
            }
            value = match value.checked_mul(base) {
                Some(value) => value,
                None => return IResult::Error,
            };
            value = match value.checked_add(digit) {
                Some(value) => value,
                None => return IResult::Error,
            };
            len += 1;
            empty = false;
        }
        if empty {
            IResult::Error
        } else {
            IResult::Done(&input[len..], value)
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};
    use std::{ascii, iter};
    use std::fmt::{self, Display};
    use std::str;

    impl ToTokens for Lit {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
                Lit::Str(ref s, StrStyle::Raw(n)) => {
                    tokens.append(&format!("r{delim}\"{string}\"{delim}",
                        delim = iter::repeat("#").take(n).collect::<String>(),
                        string = s));
                }
                Lit::ByteStr(ref v, StrStyle::Cooked) => {
                    let mut escaped = "b\"".to_string();
                    for &ch in v.iter() {
                        escaped.extend(ascii::escape_default(ch).map(|c| c as char));
                    }
                    escaped.push('"');
                    tokens.append(&escaped);
                }
                Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
                    tokens.append(&format!("br{delim}\"{string}\"{delim}",
                        delim = iter::repeat("#").take(n).collect::<String>(),
                        string = str::from_utf8(vec).unwrap()));
                }
                Lit::Byte(b) => tokens.append(&format!("b{:?}", b as char)),
                Lit::Char(ch) => ch.to_tokens(tokens),
                Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
                Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
                Lit::Bool(true) => tokens.append("true"),
                Lit::Bool(false) => tokens.append("false"),
            }
        }
    }

    impl Display for IntTy {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
            match *self {
                IntTy::Isize => formatter.write_str("isize"),
                IntTy::I8 => formatter.write_str("i8"),
                IntTy::I16 => formatter.write_str("i16"),
                IntTy::I32 => formatter.write_str("i32"),
                IntTy::I64 => formatter.write_str("i64"),
                IntTy::Usize => formatter.write_str("usize"),
                IntTy::U8 => formatter.write_str("u8"),
                IntTy::U16 => formatter.write_str("u16"),
                IntTy::U32 => formatter.write_str("u32"),
                IntTy::U64 => formatter.write_str("u64"),
                IntTy::Unsuffixed => Ok(()),
            }
        }
    }

    impl Display for FloatTy {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
            match *self {
                FloatTy::F32 => formatter.write_str("f32"),
                FloatTy::F64 => formatter.write_str("f64"),
                FloatTy::Unsuffixed => Ok(()),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{BufReader,BufWriter,Cursor};
use std::str;
use std::vec::Vec;
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt,Error};
static PAD_LEN:u32 = 4;

pub struct XdrReader {
	reader : Cursor<Vec<u8>>
}

pub struct XdrWriter {
	writer : Cursor<Vec<u8>>
}

impl XdrWriter {
	pub fn new() -> XdrWriter {
		let v : Vec<u8>= Vec::new();
		XdrWriter{ writer: Cursor::new(v)}
	}

	pub fn get_buffer(self) -> Vec<u8> {
		self.writer.into_inner()
	}

}
pub trait XdrPrimitive {
	fn read_from_xdr(x: &mut XdrReader) -> Result<Self, Error>;
	fn write_to_xdr(x: &mut XdrWriter, v: Self);
}

impl XdrPrimitive for u32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u32, Error>{
		match x.reader.read_u32::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u16, Error>{
		match x.reader.read_u32::<BigEndian>() {
			Ok(v) => Ok(v as u16),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for u8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u8, Error>{
		match x.reader.read_u32::<BigEndian>() {
			Ok(v) => Ok(v as u8),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for i8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i8, Error>{
		match x.reader.read_i32::<BigEndian>() {
			Ok(v) => Ok(v as i8),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i16, Error>{
		match x.reader.read_i32::<BigEndian>() {
			Ok(v) => Ok(v as i16),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i32, Error>{
		match x.reader.read_i32::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for i64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i64, Error>{
		match x.reader.read_i64::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i64::<BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u64, Error>{
		match x.reader.read_u64::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u64::<BigEndian>(v).unwrap();
	}

}

impl XdrPrimitive for f32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f32, Error>{
		match x.reader.read_f32::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f32::<BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for f64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f64, Error>{
		match x.reader.read_f64::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f64::<BigEndian>(v).unwrap();
	}
}
<commit_msg>'use' cleanup<commit_after>use std::io;
use std::fmt;
use std::error;
use std::vec::Vec;
use byteorder;
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt};

pub struct XdrReader {
	reader : io::Cursor<Vec<u8>>
}

pub struct XdrWriter {
	writer : io::Cursor<Vec<u8>>
}

impl XdrWriter {
	pub fn new() -> XdrWriter {
		let v : Vec<u8>= Vec::new();
		XdrWriter{ writer: io::Cursor::new(v)}
	}

	pub fn get_buffer(self) -> Vec<u8> {
		self.writer.into_inner()
	}

}
pub trait XdrPrimitive {
	fn read_from_xdr(x: &mut XdrReader) -> Result<Self, Error>;
	fn write_to_xdr(x: &mut XdrWriter, v: Self);
}

impl XdrPrimitive for u32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u32, Error>{
		match x.reader.read_u32::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u16, Error>{
		match x.reader.read_u32::<BigEndian>() {
			Ok(v) => Ok(v as u16),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for u8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u8, Error>{
		match x.reader.read_u32::<BigEndian>() {
			Ok(v) => Ok(v as u8),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for i8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i8, Error>{
		match x.reader.read_i32::<BigEndian>() {
			Ok(v) => Ok(v as i8),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i16, Error>{
		match x.reader.read_i32::<BigEndian>() {
			Ok(v) => Ok(v as i16),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i32, Error>{
		match x.reader.read_i32::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for i64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i64, Error>{
		match x.reader.read_i64::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i64::<BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u64, Error>{
		match x.reader.read_u64::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u64::<BigEndian>(v).unwrap();
	}

}

impl XdrPrimitive for f32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f32, Error>{
		match x.reader.read_f32::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f32::<BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for f64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f64, Error>{
		match x.reader.read_f64::<BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(v)
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f64::<BigEndian>(v).unwrap();
	}
}
<|endoftext|>


<commit_before>//! The AWS STS API.

#![allow(unused_imports)]

include!(concat!(env!("OUT_DIR"), "/sts.rs"));

pub use self::credential::{
    StsSessionCredentialsProvider,
    StsAssumeRoleSessionCredentialsProvider,
    StsWebIdentityFederationSessionCredentialsProvider,
    NewAwsCredsForStsCreds,
    };

mod credential {
    use std::error::Error;
    use std::fmt;

    use hyper::Client;
    use chrono::*;

    use ::{AwsCredentials, ProfileProvider, CredentialsError,
        ProvideAwsCredentials, DispatchSignedRequest};
    use super::{AssumeRoleRequest, AssumeRoleResponse, AssumeRoleError,
        AssumeRoleWithSAMLRequest, AssumeRoleWithSAMLResponse, AssumeRoleWithSAMLError,
        AssumeRoleWithWebIdentityRequest, AssumeRoleWithWebIdentityResponse, AssumeRoleWithWebIdentityError,
        DecodeAuthorizationMessageRequest, DecodeAuthorizationMessageResponse, DecodeAuthorizationMessageError,
        GetCallerIdentityRequest, GetCallerIdentityResponse, GetCallerIdentityError,
        GetFederationTokenRequest, GetFederationTokenResponse, GetFederationTokenError,
        GetSessionTokenRequest, GetSessionTokenResponse, GetSessionTokenError,
        StsClient};

    pub const DEFAULT_DURATION_SECONDS: i32 = 3600;
    pub const DEFAULT_ROLE_DURATION_SECONDS: i32 = 900;

    pub trait NewAwsCredsForStsCreds {
        fn new_for_credentials(sts_creds: ::sts::Credentials) -> Result<AwsCredentials, CredentialsError>;
    }

    impl NewAwsCredsForStsCreds for AwsCredentials {
        fn new_for_credentials(sts_creds: ::sts::Credentials) -> Result<AwsCredentials, CredentialsError> {
            let expires_at = try!(sts_creds.expiration.parse::<DateTime<UTC>>().map_err(CredentialsError::from));

            Ok(AwsCredentials::new(
                sts_creds.access_key_id,
                sts_creds.secret_access_key,
                Some(sts_creds.session_token),
                expires_at))
        }
    }

    pub trait StsSessionCredentialsClient {
        fn assume_role(&self, input: &AssumeRoleRequest) -> Result<AssumeRoleResponse, AssumeRoleError>;

        fn assume_role_with_saml(&self, input: &AssumeRoleWithSAMLRequest) -> Result<AssumeRoleWithSAMLResponse, AssumeRoleWithSAMLError>;

        fn assume_role_with_web_identity(&self, input: &AssumeRoleWithWebIdentityRequest) -> Result<AssumeRoleWithWebIdentityResponse, AssumeRoleWithWebIdentityError>;

        fn decode_authorization_message(&self, input: &DecodeAuthorizationMessageRequest) -> Result<DecodeAuthorizationMessageResponse, DecodeAuthorizationMessageError>;

        fn get_caller_identity(&self, input: &GetCallerIdentityRequest) -> Result<GetCallerIdentityResponse, GetCallerIdentityError> ;

        fn get_federation_token(&self, input: &GetFederationTokenRequest) -> Result<GetFederationTokenResponse, GetFederationTokenError>;

        fn get_session_token(&self, input: &GetSessionTokenRequest) -> Result<GetSessionTokenResponse, GetSessionTokenError>;
    }

    impl <P,D> StsSessionCredentialsClient for StsClient<P,D> where P: ProvideAwsCredentials, D: DispatchSignedRequest {
        fn assume_role(&self, input: &AssumeRoleRequest) -> Result<AssumeRoleResponse, AssumeRoleError> {
            StsClient::assume_role(self, input)
        }

        fn assume_role_with_saml(&self, input: &AssumeRoleWithSAMLRequest) -> Result<AssumeRoleWithSAMLResponse, AssumeRoleWithSAMLError> {
            StsClient::assume_role_with_saml(self, input)
        }

        fn assume_role_with_web_identity(&self, input: &AssumeRoleWithWebIdentityRequest) -> Result<AssumeRoleWithWebIdentityResponse, AssumeRoleWithWebIdentityError> {
            StsClient::assume_role_with_web_identity(self, input)
        }

        fn decode_authorization_message(&self, input: &DecodeAuthorizationMessageRequest) -> Result<DecodeAuthorizationMessageResponse, DecodeAuthorizationMessageError> {
            StsClient::decode_authorization_message(self, input)
        }

        fn get_caller_identity(&self, input: &GetCallerIdentityRequest) -> Result<GetCallerIdentityResponse, GetCallerIdentityError> {
            StsClient::get_caller_identity(self, input)
        }

        fn get_federation_token(&self, input: &GetFederationTokenRequest) -> Result<GetFederationTokenResponse, GetFederationTokenError> {
            StsClient::get_federation_token(self, input)
        }

        fn get_session_token(&self, input: &GetSessionTokenRequest) -> Result<GetSessionTokenResponse, GetSessionTokenError> {
            StsClient::get_session_token(self, input)
        }
    }

    pub struct StsSessionCredentialsProvider {
        sts_client: Box<StsSessionCredentialsClient>,
        session_duration: Duration,
        mfa_serial: Option<String>,
        mfa_code: Option<String>,
    }

    impl StsSessionCredentialsProvider {
        pub fn new<P,D>(sts_client: StsClient<P,D>,
                duration: Option<Duration>,
                mfa_serial: Option<String>,
                ) -> StsSessionCredentialsProvider
                where P: ProvideAwsCredentials + 'static, D: DispatchSignedRequest + 'static {
            StsSessionCredentialsProvider {
                sts_client: Box::new(sts_client),
                session_duration: duration.unwrap_or(Duration::seconds(DEFAULT_DURATION_SECONDS as i64)),
                mfa_serial: mfa_serial,
                mfa_code: None,
            }
        }

        pub fn set_mfa_code<S>(&mut self, code: S) where S: Into<String> {
            self.mfa_code = Some(code.into());
        }

        pub fn clear_mfa_code(&mut self) {
            self.mfa_code = None;
        }

        pub fn get_session_token(&self) -> Result<AwsCredentials, CredentialsError> {
            match self.sts_client.get_session_token(
                &GetSessionTokenRequest {
                    serial_number: self.mfa_serial.clone(),
                    token_code: self.mfa_code.clone(),
                    duration_seconds: Some(self.session_duration.num_seconds() as i32),
                    ..Default::default()
                }) {
                Ok(resp) => {
                    let creds = try!(resp.credentials.ok_or(CredentialsError::new("no credentials in response")));

                    AwsCredentials::new_for_credentials(creds)
                },
                err =>
                    Err(CredentialsError::new(format!("StsProvider get_session_token error: {:?}", err)))
            }
        }
    }

    impl ProvideAwsCredentials for StsSessionCredentialsProvider {
        fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
            self.get_session_token()
        }
    }

    pub struct StsAssumeRoleSessionCredentialsProvider {
        sts_client: Box<StsSessionCredentialsClient>,
        role_arn: String,
        session_name: String,
        external_id: Option<String>,
        session_duration: Duration,
        scope_down_policy: Option<String>,
    }

    impl StsAssumeRoleSessionCredentialsProvider {
        pub fn new<P,D>(sts_client: StsClient<P,D>,
                role_arn: String,
                session_name: String,
                external_id: Option<String>,
                session_duration: Option<Duration>,
                scope_down_policy: Option<String>,
                )
                -> StsAssumeRoleSessionCredentialsProvider
                where P: ProvideAwsCredentials + 'static, D: DispatchSignedRequest + 'static {
            StsAssumeRoleSessionCredentialsProvider {
                sts_client: Box::new(sts_client),
                role_arn: role_arn,
                session_name: session_name,
                external_id: external_id,
                session_duration: session_duration.unwrap_or(Duration::seconds(DEFAULT_ROLE_DURATION_SECONDS as i64)),
                scope_down_policy: scope_down_policy,
            }
        }

        pub fn assume_role(&self) -> Result<AwsCredentials, CredentialsError> {
            match self.sts_client.assume_role(&AssumeRoleRequest {
                role_arn: self.role_arn.clone(),
                role_session_name: self.session_name.clone(),
                duration_seconds: Some(self.session_duration.num_seconds() as i32),
                external_id: self.external_id.clone(),
                policy: self.scope_down_policy.clone(),
                ..Default::default()
            }) {
                Err(err) =>
                    Err(CredentialsError::new(format!("Sts AssumeRoleError: {:?}", err))),
                Ok(resp) => {
                    let creds = try!(resp.credentials.ok_or(CredentialsError::new("no credentials in response")));

                    AwsCredentials::new_for_credentials(creds)
                }
            }
        }
    }

    impl ProvideAwsCredentials for StsAssumeRoleSessionCredentialsProvider {
        fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
            self.assume_role()
        }
    }

    pub struct StsWebIdentityFederationSessionCredentialsProvider {
        sts_client: Box<StsSessionCredentialsClient>,
        wif_token: String,
        wif_provider: Option<String>,
        role_arn: String,
        session_name: String,
        session_duration: Duration,
        scope_down_policy: Option<String>,
    }

    impl StsWebIdentityFederationSessionCredentialsProvider {
        pub fn new<P,D>(sts_client: StsClient<P,D>,
                wif_token: String,
                wif_provider: Option<String>,
                role_arn: String,
                session_name: String,
                session_duration: Option<Duration>,
                policy: Option<String>,
                ) -> StsWebIdentityFederationSessionCredentialsProvider
                where P: ProvideAwsCredentials + 'static, D: DispatchSignedRequest + 'static {
            StsWebIdentityFederationSessionCredentialsProvider {
                sts_client: Box::new(sts_client),
                wif_token: wif_token,
                wif_provider: wif_provider,
                role_arn: role_arn,
                session_name: session_name,
                session_duration: session_duration.unwrap_or(Duration::seconds(DEFAULT_DURATION_SECONDS as i64)),
                scope_down_policy: policy,
            }
        }

        pub fn assume_role_with_web_identity(&self) -> Result<AwsCredentials, CredentialsError> {
            match self.sts_client.assume_role_with_web_identity(&AssumeRoleWithWebIdentityRequest {
                web_identity_token: self.wif_token.clone(),
                provider_id: self.wif_provider.clone(),
                role_arn: self.role_arn.clone(),
                role_session_name: self.session_name.clone(),
                duration_seconds: Some(self.session_duration.num_seconds() as i32),
                policy: self.scope_down_policy.clone(),
                ..Default::default()
            }) {
                Err(err) =>
                    Err(CredentialsError::new(format!("Sts AssumeRoleWithWebIdentityError: {:?}", err))),
                Ok(resp) => {
                    let creds = try!(resp.credentials.ok_or(CredentialsError::new("no credentials in response")));

                    let mut aws_creds = try!(AwsCredentials::new_for_credentials(creds));

                    if let Some(subject_from_wif) = resp.subject_from_web_identity_token {
                        aws_creds.claims_mut().insert(::claims::SUBJECT.to_owned(), subject_from_wif);
                    }

                    Ok(aws_creds)
                }
            }
        }
    }

    impl ProvideAwsCredentials for StsWebIdentityFederationSessionCredentialsProvider {
        fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
            self.assume_role_with_web_identity()
        }
    }
}<commit_msg>add link to client class indocs<commit_after>//! The AWS STS API.
//!
//! If you're using the service, you're probably looking for [StsClient](struct.StsClient.html).
#![allow(unused_imports)]

include!(concat!(env!("OUT_DIR"), "/sts.rs"));

pub use self::credential::{
    StsSessionCredentialsProvider,
    StsAssumeRoleSessionCredentialsProvider,
    StsWebIdentityFederationSessionCredentialsProvider,
    NewAwsCredsForStsCreds,
    };

mod credential {
    use std::error::Error;
    use std::fmt;

    use hyper::Client;
    use chrono::*;

    use ::{AwsCredentials, ProfileProvider, CredentialsError,
        ProvideAwsCredentials, DispatchSignedRequest};
    use super::{AssumeRoleRequest, AssumeRoleResponse, AssumeRoleError,
        AssumeRoleWithSAMLRequest, AssumeRoleWithSAMLResponse, AssumeRoleWithSAMLError,
        AssumeRoleWithWebIdentityRequest, AssumeRoleWithWebIdentityResponse, AssumeRoleWithWebIdentityError,
        DecodeAuthorizationMessageRequest, DecodeAuthorizationMessageResponse, DecodeAuthorizationMessageError,
        GetCallerIdentityRequest, GetCallerIdentityResponse, GetCallerIdentityError,
        GetFederationTokenRequest, GetFederationTokenResponse, GetFederationTokenError,
        GetSessionTokenRequest, GetSessionTokenResponse, GetSessionTokenError,
        StsClient};

    pub const DEFAULT_DURATION_SECONDS: i32 = 3600;
    pub const DEFAULT_ROLE_DURATION_SECONDS: i32 = 900;

    pub trait NewAwsCredsForStsCreds {
        fn new_for_credentials(sts_creds: ::sts::Credentials) -> Result<AwsCredentials, CredentialsError>;
    }

    impl NewAwsCredsForStsCreds for AwsCredentials {
        fn new_for_credentials(sts_creds: ::sts::Credentials) -> Result<AwsCredentials, CredentialsError> {
            let expires_at = try!(sts_creds.expiration.parse::<DateTime<UTC>>().map_err(CredentialsError::from));

            Ok(AwsCredentials::new(
                sts_creds.access_key_id,
                sts_creds.secret_access_key,
                Some(sts_creds.session_token),
                expires_at))
        }
    }

    pub trait StsSessionCredentialsClient {
        fn assume_role(&self, input: &AssumeRoleRequest) -> Result<AssumeRoleResponse, AssumeRoleError>;

        fn assume_role_with_saml(&self, input: &AssumeRoleWithSAMLRequest) -> Result<AssumeRoleWithSAMLResponse, AssumeRoleWithSAMLError>;

        fn assume_role_with_web_identity(&self, input: &AssumeRoleWithWebIdentityRequest) -> Result<AssumeRoleWithWebIdentityResponse, AssumeRoleWithWebIdentityError>;

        fn decode_authorization_message(&self, input: &DecodeAuthorizationMessageRequest) -> Result<DecodeAuthorizationMessageResponse, DecodeAuthorizationMessageError>;

        fn get_caller_identity(&self, input: &GetCallerIdentityRequest) -> Result<GetCallerIdentityResponse, GetCallerIdentityError> ;

        fn get_federation_token(&self, input: &GetFederationTokenRequest) -> Result<GetFederationTokenResponse, GetFederationTokenError>;

        fn get_session_token(&self, input: &GetSessionTokenRequest) -> Result<GetSessionTokenResponse, GetSessionTokenError>;
    }

    impl <P,D> StsSessionCredentialsClient for StsClient<P,D> where P: ProvideAwsCredentials, D: DispatchSignedRequest {
        fn assume_role(&self, input: &AssumeRoleRequest) -> Result<AssumeRoleResponse, AssumeRoleError> {
            StsClient::assume_role(self, input)
        }

        fn assume_role_with_saml(&self, input: &AssumeRoleWithSAMLRequest) -> Result<AssumeRoleWithSAMLResponse, AssumeRoleWithSAMLError> {
            StsClient::assume_role_with_saml(self, input)
        }

        fn assume_role_with_web_identity(&self, input: &AssumeRoleWithWebIdentityRequest) -> Result<AssumeRoleWithWebIdentityResponse, AssumeRoleWithWebIdentityError> {
            StsClient::assume_role_with_web_identity(self, input)
        }

        fn decode_authorization_message(&self, input: &DecodeAuthorizationMessageRequest) -> Result<DecodeAuthorizationMessageResponse, DecodeAuthorizationMessageError> {
            StsClient::decode_authorization_message(self, input)
        }

        fn get_caller_identity(&self, input: &GetCallerIdentityRequest) -> Result<GetCallerIdentityResponse, GetCallerIdentityError> {
            StsClient::get_caller_identity(self, input)
        }

        fn get_federation_token(&self, input: &GetFederationTokenRequest) -> Result<GetFederationTokenResponse, GetFederationTokenError> {
            StsClient::get_federation_token(self, input)
        }

        fn get_session_token(&self, input: &GetSessionTokenRequest) -> Result<GetSessionTokenResponse, GetSessionTokenError> {
            StsClient::get_session_token(self, input)
        }
    }

    pub struct StsSessionCredentialsProvider {
        sts_client: Box<StsSessionCredentialsClient>,
        session_duration: Duration,
        mfa_serial: Option<String>,
        mfa_code: Option<String>,
    }

    impl StsSessionCredentialsProvider {
        pub fn new<P,D>(sts_client: StsClient<P,D>,
                duration: Option<Duration>,
                mfa_serial: Option<String>,
                ) -> StsSessionCredentialsProvider
                where P: ProvideAwsCredentials + 'static, D: DispatchSignedRequest + 'static {
            StsSessionCredentialsProvider {
                sts_client: Box::new(sts_client),
                session_duration: duration.unwrap_or(Duration::seconds(DEFAULT_DURATION_SECONDS as i64)),
                mfa_serial: mfa_serial,
                mfa_code: None,
            }
        }

        pub fn set_mfa_code<S>(&mut self, code: S) where S: Into<String> {
            self.mfa_code = Some(code.into());
        }

        pub fn clear_mfa_code(&mut self) {
            self.mfa_code = None;
        }

        pub fn get_session_token(&self) -> Result<AwsCredentials, CredentialsError> {
            match self.sts_client.get_session_token(
                &GetSessionTokenRequest {
                    serial_number: self.mfa_serial.clone(),
                    token_code: self.mfa_code.clone(),
                    duration_seconds: Some(self.session_duration.num_seconds() as i32),
                    ..Default::default()
                }) {
                Ok(resp) => {
                    let creds = try!(resp.credentials.ok_or(CredentialsError::new("no credentials in response")));

                    AwsCredentials::new_for_credentials(creds)
                },
                err =>
                    Err(CredentialsError::new(format!("StsProvider get_session_token error: {:?}", err)))
            }
        }
    }

    impl ProvideAwsCredentials for StsSessionCredentialsProvider {
        fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
            self.get_session_token()
        }
    }

    pub struct StsAssumeRoleSessionCredentialsProvider {
        sts_client: Box<StsSessionCredentialsClient>,
        role_arn: String,
        session_name: String,
        external_id: Option<String>,
        session_duration: Duration,
        scope_down_policy: Option<String>,
    }

    impl StsAssumeRoleSessionCredentialsProvider {
        pub fn new<P,D>(sts_client: StsClient<P,D>,
                role_arn: String,
                session_name: String,
                external_id: Option<String>,
                session_duration: Option<Duration>,
                scope_down_policy: Option<String>,
                )
                -> StsAssumeRoleSessionCredentialsProvider
                where P: ProvideAwsCredentials + 'static, D: DispatchSignedRequest + 'static {
            StsAssumeRoleSessionCredentialsProvider {
                sts_client: Box::new(sts_client),
                role_arn: role_arn,
                session_name: session_name,
                external_id: external_id,
                session_duration: session_duration.unwrap_or(Duration::seconds(DEFAULT_ROLE_DURATION_SECONDS as i64)),
                scope_down_policy: scope_down_policy,
            }
        }

        pub fn assume_role(&self) -> Result<AwsCredentials, CredentialsError> {
            match self.sts_client.assume_role(&AssumeRoleRequest {
                role_arn: self.role_arn.clone(),
                role_session_name: self.session_name.clone(),
                duration_seconds: Some(self.session_duration.num_seconds() as i32),
                external_id: self.external_id.clone(),
                policy: self.scope_down_policy.clone(),
                ..Default::default()
            }) {
                Err(err) =>
                    Err(CredentialsError::new(format!("Sts AssumeRoleError: {:?}", err))),
                Ok(resp) => {
                    let creds = try!(resp.credentials.ok_or(CredentialsError::new("no credentials in response")));

                    AwsCredentials::new_for_credentials(creds)
                }
            }
        }
    }

    impl ProvideAwsCredentials for StsAssumeRoleSessionCredentialsProvider {
        fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
            self.assume_role()
        }
    }

    pub struct StsWebIdentityFederationSessionCredentialsProvider {
        sts_client: Box<StsSessionCredentialsClient>,
        wif_token: String,
        wif_provider: Option<String>,
        role_arn: String,
        session_name: String,
        session_duration: Duration,
        scope_down_policy: Option<String>,
    }

    impl StsWebIdentityFederationSessionCredentialsProvider {
        pub fn new<P,D>(sts_client: StsClient<P,D>,
                wif_token: String,
                wif_provider: Option<String>,
                role_arn: String,
                session_name: String,
                session_duration: Option<Duration>,
                policy: Option<String>,
                ) -> StsWebIdentityFederationSessionCredentialsProvider
                where P: ProvideAwsCredentials + 'static, D: DispatchSignedRequest + 'static {
            StsWebIdentityFederationSessionCredentialsProvider {
                sts_client: Box::new(sts_client),
                wif_token: wif_token,
                wif_provider: wif_provider,
                role_arn: role_arn,
                session_name: session_name,
                session_duration: session_duration.unwrap_or(Duration::seconds(DEFAULT_DURATION_SECONDS as i64)),
                scope_down_policy: policy,
            }
        }

        pub fn assume_role_with_web_identity(&self) -> Result<AwsCredentials, CredentialsError> {
            match self.sts_client.assume_role_with_web_identity(&AssumeRoleWithWebIdentityRequest {
                web_identity_token: self.wif_token.clone(),
                provider_id: self.wif_provider.clone(),
                role_arn: self.role_arn.clone(),
                role_session_name: self.session_name.clone(),
                duration_seconds: Some(self.session_duration.num_seconds() as i32),
                policy: self.scope_down_policy.clone(),
                ..Default::default()
            }) {
                Err(err) =>
                    Err(CredentialsError::new(format!("Sts AssumeRoleWithWebIdentityError: {:?}", err))),
                Ok(resp) => {
                    let creds = try!(resp.credentials.ok_or(CredentialsError::new("no credentials in response")));

                    let mut aws_creds = try!(AwsCredentials::new_for_credentials(creds));

                    if let Some(subject_from_wif) = resp.subject_from_web_identity_token {
                        aws_creds.claims_mut().insert(::claims::SUBJECT.to_owned(), subject_from_wif);
                    }

                    Ok(aws_creds)
                }
            }
        }
    }

    impl ProvideAwsCredentials for StsWebIdentityFederationSessionCredentialsProvider {
        fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
            self.assume_role_with_web_identity()
        }
    }
}<|endoftext|>


<commit_before>//! # Log module.
//!
//! The Config module provides the log facility.
use slog::*;
use slog_stream;
use slog_term;
use slog_json;
use slog_scope;
use std::fs::OpenOptions;
use std;

use config;

/// Bare logger that only write to console.
pub fn bootstrap() {
    slog_scope::set_global_logger(Logger::root(slog_term::streamer().full().build().ignore_err(),
                                               o![]));
}

/// Full featured logger.
/// Send log to console and log file, also handle log level.
pub fn log(parameters: &config::Parameters, verbose: u64) {
    // Stdout drain
    let drain_term = slog_term::streamer().full().build().ignore_err();

    // File drain
    let log_file = OpenOptions::new().create(true).append(true).open(&parameters.log_file);
    if log_file.is_err() {
        crit!("Fail to open log file at {:?}: {}",
              &parameters.log_file,
              log_file.err().unwrap());
        std::process::exit(-1);
    }
    let file_drain = slog_stream::async_stream(log_file.unwrap(), slog_json::default())
        .ignore_err();

    // increase console log level if needed. Cap to trave
    let console_level = parameters.log_level.as_usize() as u64 + verbose;
    let console_level = std::cmp::min(console_level, Level::Trace.as_usize() as u64);
    let console_level = Level::from_usize(console_level as usize).unwrap_or(Level::Trace);

    // Setup root logger
    let root_log = Logger::root(Duplicate::new(LevelFilter::new(drain_term, console_level),
                                               LevelFilter::new(file_drain, parameters.log_level))
                                    .ignore_err(),
                                o!());

    slog_scope::set_global_logger(root_log);
}
<commit_msg>Fixed ambiguous macro in Rust beta<commit_after>//! # Log module.
//!
//! The Config module provides the log facility.
use slog::Logger;
use slog::Level;
use slog::Duplicate;
use slog::LevelFilter;
use slog::DrainExt;
use slog_stream;
use slog_term;
use slog_json;
use slog_scope;
use std::fs::OpenOptions;
use std;

use config;

/// Bare logger that only write to console.
pub fn bootstrap() {
    slog_scope::set_global_logger(Logger::root(slog_term::streamer().full().build().ignore_err(),
                                               o![]));
}

/// Full featured logger.
/// Send log to console and log file, also handle log level.
pub fn log(parameters: &config::Parameters, verbose: u64) {
    // Stdout drain
    let drain_term = slog_term::streamer().full().build().ignore_err();

    // File drain
    let log_file = OpenOptions::new().create(true).append(true).open(&parameters.log_file);
    if log_file.is_err() {
        crit!("Fail to open log file at {:?}: {}",
              &parameters.log_file,
              log_file.err().unwrap());
        std::process::exit(-1);
    }
    let file_drain = slog_stream::async_stream(log_file.unwrap(), slog_json::default())
        .ignore_err();

    // increase console log level if needed. Cap to trave
    let console_level = parameters.log_level.as_usize() as u64 + verbose;
    let console_level = std::cmp::min(console_level, Level::Trace.as_usize() as u64);
    let console_level = Level::from_usize(console_level as usize).unwrap_or(Level::Trace);

    // Setup root logger
    let root_log = Logger::root(Duplicate::new(LevelFilter::new(drain_term, console_level),
                                               LevelFilter::new(file_drain, parameters.log_level))
                                    .ignore_err(),
                                o!());

    slog_scope::set_global_logger(root_log);
}
<|endoftext|>


<commit_before>//! This module provides an oct-tree of cubes. Each leaf cube describes a
//! spatial partition, its properties, and a deformable geometry.

extern crate nalgebra;
extern crate num;

use ::nalgebra::Origin;
use ::num::{One, Zero}; // TODO: `use ::std::num::{One, Zero};`.
use ::std::error;
use ::std::error::Error;
use ::std::fmt;
use ::std::mem;
use ::std::ops;

use math::{Clamp, Mask, DiscreteSpace};
use resource::ResourceId;

pub const MAX_WIDTH: RootWidth = 32;
pub const MIN_WIDTH: RootWidth = 4;

pub type Point3 = nalgebra::Point3<DiscreteSpace>;
pub type Vector3 = nalgebra::Vector3<DiscreteSpace>;
pub type RootWidth = u8; // TODO: https://github.com/rust-lang/rfcs/issues/671

impl Clamp<RootWidth> for RootWidth {
    fn clamp(&self, min: RootWidth, max: RootWidth) -> Self {
        nalgebra::clamp(*self, min, max)
    }
}

#[derive(Clone)]
pub struct Partition {
    origin: Point3,
    width: RootWidth,
}

impl Partition {
    fn at_point(point: &Point3, width: RootWidth) -> Self {
        Partition {
            origin: point.mask(!DiscreteSpace::zero() << width),
            width: width,
        }
    }

    fn at_index(&self, index: usize) -> Option<Self> {
        if self.width > MIN_WIDTH {
            let width = self.width - 1;
            Some(Partition {
                origin: self.origin + vector_at_index(index, width),
                width: width,
            })
        } else {
            None
        }
    }

    pub fn origin(&self) -> &Point3 {
        &self.origin
    }

    pub fn width(&self) -> RootWidth {
        self.width
    }

    pub fn midpoint(&self) -> Point3 {
        let m = exp(self.width - 1);
        Point3::new(m, m, m)
    }
}

pub trait ComputedCube: ops::Deref<Target = Cube> {
    fn partition(&self) -> &Partition;

    fn depth(&self) -> u8;
}

#[derive(Debug)]
pub enum JoinError {
    LeafJoined,
}

impl fmt::Display for JoinError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for JoinError {
    fn description(&self) -> &str {
        match *self {
            JoinError::LeafJoined => "attempted to join leaf",
        }
    }
}

#[derive(Debug)]
pub enum SubdivideError {
    LimitExceeded,
    BranchSubdivided,
}

impl fmt::Display for SubdivideError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for SubdivideError {
    fn description(&self) -> &str {
        match *self {
            SubdivideError::LimitExceeded => "minimum width limit exceeded",
            SubdivideError::BranchSubdivided => "attempted to subdivide branch",
        }
    }
}

pub trait ComputedCubeMut: ComputedCube + ops::DerefMut {
    fn join(&mut self) -> Result<&mut Self, JoinError> {
        try!(self.deref_mut().join().ok_or(JoinError::LeafJoined));
        Ok(self)
    }

    fn subdivide(&mut self) -> Result<&mut Self, SubdivideError> {
        if self.partition().width() > MIN_WIDTH {
            try!(self.deref_mut().subdivide().ok_or(SubdivideError::BranchSubdivided));
            Ok(self)
        } else {
            Err(SubdivideError::LimitExceeded)
        }
    }
}

#[derive(Clone)]
pub struct Traversal<'a> {
    cube: &'a Cube,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> Traversal<'a> {
    fn new(cube: &'a Cube, root: &'a Partition, partition: Partition) -> Self {
        Traversal {
            cube: cube,
            root: root,
            partition: partition,
        }
    }

    pub fn iter(&self) -> CubeIter {
        CubeIter::new(self.clone())
    }

    pub fn at_point(&self, point: &Point3, width: RootWidth) -> Self {
        let mut cube = self.cube;
        let mut depth = self.partition.width();

        // Clamp the inputs.
        let point = point.clamp(0, (exp(self.root.width())) - 1);
        let width = exp(width.clamp(MIN_WIDTH, depth));

        while (width >> depth) == 0 {
            match *cube {
                Cube::Branch(ref branch) => {
                    depth = depth - 1;
                    cube = &branch.cubes[index_at_point(&point, depth)]
                }
                _ => break,
            }
        }

        Traversal::new(cube, self.root, Partition::at_point(&point, depth))
    }
}

impl<'a> ComputedCube for Traversal<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

impl<'a> ops::Deref for Traversal<'a> {
    type Target = Cube;

    fn deref(&self) -> &Self::Target {
        self.cube
    }
}

pub struct CubeIter<'a> {
    traversals: Vec<Traversal<'a>>,
}

impl<'a> CubeIter<'a> {
    fn new(traversal: Traversal<'a>) -> Self {
        CubeIter { traversals: vec![traversal] }
    }
}

impl<'a> Iterator for CubeIter<'a> {
    type Item = Traversal<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(traversal) = self.traversals.pop() {
            match *traversal.cube {
                Cube::Branch(ref branch) => {
                    for (index, cube) in branch.iter().enumerate() {
                        self.traversals.push(Traversal::new(cube,
                                                            traversal.root,
                                                            traversal.partition()
                                                                .at_index(index)
                                                                .unwrap()));
                    }
                }
                _ => {}
            }
            Some(traversal)
        } else {
            None
        }
    }
}

pub struct TraversalMut<'a> {
    cube: &'a mut Cube,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> TraversalMut<'a> {
    fn new(cube: &'a mut Cube, root: &'a Partition, partition: Partition) -> Self {
        TraversalMut {
            cube: cube,
            root: root,
            partition: partition,
        }
    }

    pub fn at_point(&'a mut self, point: &Point3, width: RootWidth) -> Self {
        let mut cube: Option<&mut Cube> = Some(self.cube);
        let mut depth = self.partition.width();

        let point = point.clamp(0, (exp(self.root.width())) - 1);
        let width = exp(width.clamp(MIN_WIDTH, depth));

        while (width >> depth) == 0 {
            let inner = cube.take().unwrap();
            match *inner {
                Cube::Branch(ref mut branch) => {
                    depth = depth - 1;
                    cube = Some(&mut branch.cubes[index_at_point(&point, depth)]);
                }
                _ => {
                    cube = Some(inner);
                    break;
                }
            }
        }

        TraversalMut::new(cube.take().unwrap(),
                          self.root,
                          Partition::at_point(&point, depth))
    }
}

impl<'a> ComputedCube for TraversalMut<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

impl<'a> ComputedCubeMut for TraversalMut<'a> {}

impl<'a> ops::Deref for TraversalMut<'a> {
    type Target = Cube;

    fn deref(&self) -> &Self::Target {
        self.cube
    }
}

impl<'a> ops::DerefMut for TraversalMut<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.cube
    }
}

pub struct Tree {
    cube: Cube,
    partition: Partition,
}

impl Tree {
    pub fn new(width: RootWidth) -> Self {
        Tree {
            cube: Cube::new(),
            partition: Partition::at_point(&Point3::origin(), width.clamp(MIN_WIDTH, MAX_WIDTH)),
        }
    }

    pub fn iter(&self) -> CubeIter {
        CubeIter::new(self.traverse())
    }

    pub fn traverse(&self) -> Traversal {
        Traversal::new(&self.cube, &self.partition, self.partition.clone())
    }

    pub fn traverse_mut(&mut self) -> TraversalMut {
        TraversalMut::new(&mut self.cube, &self.partition, self.partition.clone())
    }
}

impl ComputedCube for Tree {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        0
    }
}

impl ComputedCubeMut for Tree {}

impl ops::Deref for Tree {
    type Target = Cube;

    fn deref(&self) -> &Self::Target {
        &self.cube
    }
}

impl ops::DerefMut for Tree {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.cube
    }
}

#[derive(Clone)]
pub enum Cube {
    Leaf(LeafNode),
    Branch(BranchNode),
}

impl Cube {
    fn new() -> Self {
        Cube::Leaf(LeafNode::new())
    }

    fn join(&mut self) -> Option<&mut Self> {
        let cube = mem::replace(self, Cube::default());
        match cube {
            Cube::Branch(branch) => {
                *self = branch.join().into();
                Some(self)
            }
            _ => {
                *self = cube;
                None
            }
        }
    }

    fn subdivide(&mut self) -> Option<&mut Self> {
        let cube = mem::replace(self, Cube::default());
        match cube {
            Cube::Leaf(leaf) => {
                *self = leaf.subdivide().into();
                Some(self)
            }
            _ => {
                *self = cube;
                None
            }
        }
    }

    pub fn is_leaf(&self) -> bool {
        match *self {
            Cube::Leaf(_) => true,
            _ => false,
        }
    }
}

impl Default for Cube {
    fn default() -> Self {
        Cube::new()
    }
}

impl From<LeafNode> for Cube {
    fn from(leaf: LeafNode) -> Self {
        Cube::Leaf(leaf)
    }
}

impl From<BranchNode> for Cube {
    fn from(branch: BranchNode) -> Self {
        Cube::Branch(branch)
    }
}

#[derive(Clone, Copy)]
pub struct LeafNode {
    pub geometry: Geometry,
    pub material: ResourceId,
}

impl LeafNode {
    fn new() -> Self {
        LeafNode {
            geometry: Geometry::full(),
            material: 0,
        }
    }

    fn subdivide(self) -> BranchNode {
        // TODO: Transform the geometry of the parent into the children.
        let cube: Cube = self.into();
        BranchNode {
            cubes: Box::new([cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube]),
        }
    }
}

pub struct BranchNode {
    cubes: Box<[Cube; 8]>,
}

impl BranchNode {
    fn join(self) -> LeafNode {
        // TODO: Copy data from one of the original leaves.
        LeafNode::new()
    }
}

impl Clone for BranchNode {
    fn clone(&self) -> Self {
        BranchNode {
            cubes: Box::new([self.cubes[0].clone(),
                             self.cubes[1].clone(),
                             self.cubes[2].clone(),
                             self.cubes[3].clone(),
                             self.cubes[4].clone(),
                             self.cubes[5].clone(),
                             self.cubes[6].clone(),
                             self.cubes[7].clone()]),
        }
    }
}

impl ops::Deref for BranchNode {
    type Target = [Cube];

    fn deref(&self) -> &Self::Target {
        &*self.cubes
    }
}

#[derive(Copy, Clone)]
pub struct Geometry([[Edge; 4]; 3]);

impl Geometry {
    fn full() -> Self {
        Geometry([[Edge::full(); 4]; 3])
    }

    fn empty() -> Self {
        Geometry([[Edge::converged(0); 4]; 3])
    }

    pub fn as_edges_x(&self) -> &[Edge; 4] {
        &self.0[0]
    }
    pub fn as_edges_y(&self) -> &[Edge; 4] {
        &self.0[1]
    }
    pub fn as_edges_z(&self) -> &[Edge; 4] {
        &self.0[2]
    }

    pub fn as_edges_x_mut(&mut self) -> &mut [Edge; 4] {
        &mut self.0[0]
    }
    pub fn as_edges_y_mut(&mut self) -> &mut [Edge; 4] {
        &mut self.0[1]
    }
    pub fn as_edges_z_mut(&mut self) -> &mut [Edge; 4] {
        &mut self.0[2]
    }
}

#[derive(Copy, Clone, PartialEq, PartialOrd)]
pub struct Edge(u8);

const MIN_EDGE: u8 = 0;
const MAX_EDGE: u8 = 0x0F;

impl Edge {
    fn full() -> Self {
        Edge(MAX_EDGE)
    }

    fn converged(value: u8) -> Self {
        let value = nalgebra::clamp(value, MIN_EDGE, MAX_EDGE);
        Edge((value << 4) | value)
    }

    pub fn set_front(&mut self, value: u8) {
        let value = nalgebra::clamp(value, MIN_EDGE, self.back());
        self.0 = (value << 4) | self.back();
    }

    pub fn set_back(&mut self, value: u8) {
        let value = nalgebra::clamp(value, self.front(), MAX_EDGE);
        self.0 = (self.front() << 4) | value;
    }

    pub fn front(&self) -> u8 {
        (self.0 & 0xF0) >> 4
    }

    pub fn back(&self) -> u8 {
        self.0 & 0x0F
    }

    pub fn front_transform(&self) -> f32 {
        ((self.front() - MIN_EDGE) as f32) / ((MAX_EDGE - MIN_EDGE) as f32)
    }

    pub fn back_transform(&self) -> f32 {
        let range = MAX_EDGE - MIN_EDGE;
        -((range - (self.back() - MIN_EDGE)) as f32) / (range as f32)
    }
}

trait Subdivision {}

impl Subdivision for [Cube; 8] {}

trait Storage {}

impl Storage for Box<[Cube; 8]> {}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn index_at_point(point: &Point3, width: RootWidth) -> usize {
    ((((point.x >> width) & DiscreteSpace::one()) << 0) |
     (((point.y >> width) & DiscreteSpace::one()) << 1) |
     (((point.z >> width) & DiscreteSpace::one()) << 2)) as usize
}

fn vector_at_index(index: usize, width: RootWidth) -> Vector3 {
    assert!(index < 8);
    let index = index as DiscreteSpace;
    let width = exp(width);
    Vector3::new(((index >> 0) & DiscreteSpace::one()) * width,
                 ((index >> 1) & DiscreteSpace::one()) * width,
                 ((index >> 2) & DiscreteSpace::one()) * width)
}

pub fn exp(width: RootWidth) -> DiscreteSpace {
    if width > 0 {
        DiscreteSpace::one() << (width - 1)
    } else {
        0
    }
}

#[cfg(test)]
mod tests {
    use super::*;
}
<commit_msg>Define axes, direction, and orientation over cubes and edges.<commit_after>//! This module provides an oct-tree of cubes. Each leaf cube describes a
//! spatial partition, its properties, and a deformable geometry.

extern crate nalgebra;
extern crate num;

use ::nalgebra::Origin;
use ::num::{One, Zero}; // TODO: `use ::std::num::{One, Zero};`.
use ::std::error;
use ::std::error::Error;
use ::std::fmt;
use ::std::iter;
use ::std::mem;
use ::std::ops;

use math::{Clamp, Mask, DiscreteSpace};
use resource::ResourceId;

pub const MAX_WIDTH: RootWidth = 32;
pub const MIN_WIDTH: RootWidth = 4;

pub type Point3 = nalgebra::Point3<DiscreteSpace>;
pub type Vector3 = nalgebra::Vector3<DiscreteSpace>;
pub type RootWidth = u8; // TODO: https://github.com/rust-lang/rfcs/issues/671

impl Clamp<RootWidth> for RootWidth {
    fn clamp(&self, min: RootWidth, max: RootWidth) -> Self {
        nalgebra::clamp(*self, min, max)
    }
}

pub enum Axis {
    X = 0,
    Y = 1,
    Z = 2,
}

pub enum Direction {
    Positive,
    Negative,
}

pub enum Orientation {
    Left,
    Right,
    Top,
    Bottom,
    Front,
    Back,
}

impl Orientation {
    pub fn axis(&self) -> Axis {
        match *self {
            Orientation::Left | Orientation::Right => Axis::X,
            Orientation::Top | Orientation::Bottom => Axis::Y,
            Orientation::Front | Orientation::Back => Axis::Z,
        }
    }

    pub fn direction(&self) -> Direction {
        match *self {
            Orientation::Left | Orientation::Top | Orientation::Front => Direction::Positive,
            Orientation::Right | Orientation::Bottom | Orientation::Back => Direction::Negative,
        }
    }
}

#[derive(Clone)]
pub struct Partition {
    origin: Point3,
    width: RootWidth,
}

impl Partition {
    fn at_point(point: &Point3, width: RootWidth) -> Self {
        Partition {
            origin: point.mask(!DiscreteSpace::zero() << width),
            width: width,
        }
    }

    fn at_index(&self, index: usize) -> Option<Self> {
        if self.width > MIN_WIDTH {
            let width = self.width - 1;
            Some(Partition {
                origin: self.origin + vector_at_index(index, width),
                width: width,
            })
        } else {
            None
        }
    }

    pub fn origin(&self) -> &Point3 {
        &self.origin
    }

    pub fn width(&self) -> RootWidth {
        self.width
    }

    pub fn midpoint(&self) -> Point3 {
        let m = exp(self.width - 1);
        Point3::new(m, m, m)
    }
}

pub trait ComputedCube: ops::Deref<Target = Cube> {
    fn partition(&self) -> &Partition;

    fn depth(&self) -> u8;
}

#[derive(Debug)]
pub enum JoinError {
    LeafJoined,
}

impl fmt::Display for JoinError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for JoinError {
    fn description(&self) -> &str {
        match *self {
            JoinError::LeafJoined => "attempted to join leaf",
        }
    }
}

#[derive(Debug)]
pub enum SubdivideError {
    LimitExceeded,
    BranchSubdivided,
}

impl fmt::Display for SubdivideError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for SubdivideError {
    fn description(&self) -> &str {
        match *self {
            SubdivideError::LimitExceeded => "minimum width limit exceeded",
            SubdivideError::BranchSubdivided => "attempted to subdivide branch",
        }
    }
}

pub trait ComputedCubeMut: ComputedCube + ops::DerefMut {
    fn join(&mut self) -> Result<&mut Self, JoinError> {
        try!(self.deref_mut().join().ok_or(JoinError::LeafJoined));
        Ok(self)
    }

    fn subdivide(&mut self) -> Result<&mut Self, SubdivideError> {
        if self.partition().width() > MIN_WIDTH {
            try!(self.deref_mut().subdivide().ok_or(SubdivideError::BranchSubdivided));
            Ok(self)
        } else {
            Err(SubdivideError::LimitExceeded)
        }
    }
}

#[derive(Clone)]
pub struct Traversal<'a> {
    cube: &'a Cube,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> Traversal<'a> {
    fn new(cube: &'a Cube, root: &'a Partition, partition: Partition) -> Self {
        Traversal {
            cube: cube,
            root: root,
            partition: partition,
        }
    }

    pub fn iter(&self) -> CubeIter {
        CubeIter::new(self.clone())
    }

    pub fn at_point(&self, point: &Point3, width: RootWidth) -> Self {
        let mut cube = self.cube;
        let mut depth = self.partition.width();

        // Clamp the inputs.
        let point = point.clamp(0, (exp(self.root.width())) - 1);
        let width = exp(width.clamp(MIN_WIDTH, depth));

        while (width >> depth) == 0 {
            match *cube {
                Cube::Branch(ref branch) => {
                    depth = depth - 1;
                    cube = &branch.cubes[index_at_point(&point, depth)]
                }
                _ => break,
            }
        }

        Traversal::new(cube, self.root, Partition::at_point(&point, depth))
    }
}

impl<'a> ComputedCube for Traversal<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

impl<'a> ops::Deref for Traversal<'a> {
    type Target = Cube;

    fn deref(&self) -> &Self::Target {
        self.cube
    }
}

pub struct CubeIter<'a> {
    traversals: Vec<Traversal<'a>>,
}

impl<'a> CubeIter<'a> {
    fn new(traversal: Traversal<'a>) -> Self {
        CubeIter { traversals: vec![traversal] }
    }
}

impl<'a> Iterator for CubeIter<'a> {
    type Item = Traversal<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(traversal) = self.traversals.pop() {
            match *traversal.cube {
                Cube::Branch(ref branch) => {
                    for (index, cube) in branch.iter().enumerate() {
                        self.traversals.push(Traversal::new(cube,
                                                            traversal.root,
                                                            traversal.partition()
                                                                .at_index(index)
                                                                .unwrap()));
                    }
                }
                _ => {}
            }
            Some(traversal)
        } else {
            None
        }
    }
}

pub struct TraversalMut<'a> {
    cube: &'a mut Cube,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> TraversalMut<'a> {
    fn new(cube: &'a mut Cube, root: &'a Partition, partition: Partition) -> Self {
        TraversalMut {
            cube: cube,
            root: root,
            partition: partition,
        }
    }

    pub fn at_point(&'a mut self, point: &Point3, width: RootWidth) -> Self {
        let mut cube: Option<&mut Cube> = Some(self.cube);
        let mut depth = self.partition.width();

        let point = point.clamp(0, (exp(self.root.width())) - 1);
        let width = exp(width.clamp(MIN_WIDTH, depth));

        while (width >> depth) == 0 {
            let inner = cube.take().unwrap();
            match *inner {
                Cube::Branch(ref mut branch) => {
                    depth = depth - 1;
                    cube = Some(&mut branch.cubes[index_at_point(&point, depth)]);
                }
                _ => {
                    cube = Some(inner);
                    break;
                }
            }
        }

        TraversalMut::new(cube.take().unwrap(),
                          self.root,
                          Partition::at_point(&point, depth))
    }
}

impl<'a> ComputedCube for TraversalMut<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

impl<'a> ComputedCubeMut for TraversalMut<'a> {}

impl<'a> ops::Deref for TraversalMut<'a> {
    type Target = Cube;

    fn deref(&self) -> &Self::Target {
        self.cube
    }
}

impl<'a> ops::DerefMut for TraversalMut<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.cube
    }
}

pub struct Tree {
    cube: Cube,
    partition: Partition,
}

impl Tree {
    pub fn new(width: RootWidth) -> Self {
        Tree {
            cube: Cube::new(),
            partition: Partition::at_point(&Point3::origin(), width.clamp(MIN_WIDTH, MAX_WIDTH)),
        }
    }

    pub fn iter(&self) -> CubeIter {
        CubeIter::new(self.traverse())
    }

    pub fn traverse(&self) -> Traversal {
        Traversal::new(&self.cube, &self.partition, self.partition.clone())
    }

    pub fn traverse_mut(&mut self) -> TraversalMut {
        TraversalMut::new(&mut self.cube, &self.partition, self.partition.clone())
    }
}

impl ComputedCube for Tree {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        0
    }
}

impl ComputedCubeMut for Tree {}

impl ops::Deref for Tree {
    type Target = Cube;

    fn deref(&self) -> &Self::Target {
        &self.cube
    }
}

impl ops::DerefMut for Tree {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.cube
    }
}

#[derive(Clone)]
pub enum Cube {
    Leaf(LeafNode),
    Branch(BranchNode),
}

impl Cube {
    fn new() -> Self {
        Cube::Leaf(LeafNode::new())
    }

    fn join(&mut self) -> Option<&mut Self> {
        let cube = mem::replace(self, Cube::default());
        match cube {
            Cube::Branch(branch) => {
                *self = branch.join().into();
                Some(self)
            }
            _ => {
                *self = cube;
                None
            }
        }
    }

    fn subdivide(&mut self) -> Option<&mut Self> {
        let cube = mem::replace(self, Cube::default());
        match cube {
            Cube::Leaf(leaf) => {
                *self = leaf.subdivide().into();
                Some(self)
            }
            _ => {
                *self = cube;
                None
            }
        }
    }

    pub fn is_leaf(&self) -> bool {
        match *self {
            Cube::Leaf(_) => true,
            _ => false,
        }
    }
}

impl Default for Cube {
    fn default() -> Self {
        Cube::new()
    }
}

impl From<LeafNode> for Cube {
    fn from(leaf: LeafNode) -> Self {
        Cube::Leaf(leaf)
    }
}

impl From<BranchNode> for Cube {
    fn from(branch: BranchNode) -> Self {
        Cube::Branch(branch)
    }
}

#[derive(Clone, Copy)]
pub struct LeafNode {
    pub geometry: Geometry,
    pub material: ResourceId,
}

impl LeafNode {
    fn new() -> Self {
        LeafNode {
            geometry: Geometry::full(),
            material: 0,
        }
    }

    fn subdivide(self) -> BranchNode {
        // TODO: Transform the geometry of the parent into the children.
        let cube: Cube = self.into();
        BranchNode {
            cubes: Box::new([cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube.clone(),
                             cube]),
        }
    }
}

pub struct BranchNode {
    cubes: Box<[Cube; 8]>,
}

impl BranchNode {
    fn join(self) -> LeafNode {
        // TODO: Copy data from one of the original leaves.
        LeafNode::new()
    }
}

impl Clone for BranchNode {
    fn clone(&self) -> Self {
        BranchNode {
            cubes: Box::new([self.cubes[0].clone(),
                             self.cubes[1].clone(),
                             self.cubes[2].clone(),
                             self.cubes[3].clone(),
                             self.cubes[4].clone(),
                             self.cubes[5].clone(),
                             self.cubes[6].clone(),
                             self.cubes[7].clone()]),
        }
    }
}

impl ops::Deref for BranchNode {
    type Target = [Cube];

    fn deref(&self) -> &Self::Target {
        &*self.cubes
    }
}

#[derive(Copy, Clone)]
pub struct Geometry([[Edge; 4]; 3]);

impl Geometry {
    fn full() -> Self {
        Geometry([[Edge::full(); 4]; 3])
    }

    fn empty() -> Self {
        Geometry([[Edge::converged(0); 4]; 3])
    }

    pub fn axis_edges(&self, axis: Axis) -> &[Edge; 4] {
        &self.0[axis as usize]
    }

    pub fn axis_edges_mut(&mut self, axis: Axis) -> &mut [Edge; 4] {
        &mut self.0[axis as usize]
    }
}

#[derive(Copy, Clone, PartialEq, PartialOrd)]
pub struct Edge(u8);

pub const MIN_EDGE: u8 = 0;
pub const MAX_EDGE: u8 = 0x0F;

impl Edge {
    fn full() -> Self {
        Edge(MAX_EDGE)
    }

    fn converged(value: u8) -> Self {
        let value = nalgebra::clamp(value, MIN_EDGE, MAX_EDGE);
        Edge((value << 4) | value)
    }

    pub fn set_front(&mut self, value: u8) {
        let value = nalgebra::clamp(value, MIN_EDGE, self.back());
        self.0 = (value << 4) | self.back();
    }

    pub fn set_back(&mut self, value: u8) {
        let value = nalgebra::clamp(value, self.front(), MAX_EDGE);
        self.0 = (self.front() << 4) | value;
    }

    pub fn front(&self) -> u8 {
        (self.0 & 0xF0) >> 4
    }

    pub fn back(&self) -> u8 {
        self.0 & 0x0F
    }

    pub fn front_transform(&self) -> f32 {
        ((self.front() - MIN_EDGE) as f32) / ((MAX_EDGE - MIN_EDGE) as f32)
    }

    pub fn back_transform(&self) -> f32 {
        let range = MAX_EDGE - MIN_EDGE;
        -((range - (self.back() - MIN_EDGE)) as f32) / (range as f32)
    }
}

trait Subdivision {}

impl Subdivision for [Cube; 8] {}

trait Storage {}

impl Storage for Box<[Cube; 8]> {}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn index_at_point(point: &Point3, width: RootWidth) -> usize {
    ((((point.x >> width) & DiscreteSpace::one()) << 0) |
     (((point.y >> width) & DiscreteSpace::one()) << 1) |
     (((point.z >> width) & DiscreteSpace::one()) << 2)) as usize
}

fn vector_at_index(index: usize, width: RootWidth) -> Vector3 {
    assert!(index < 8);
    let index = index as DiscreteSpace;
    let width = exp(width);
    Vector3::new(((index >> 0) & DiscreteSpace::one()) * width,
                 ((index >> 1) & DiscreteSpace::one()) * width,
                 ((index >> 2) & DiscreteSpace::one()) * width)
}

pub fn exp(width: RootWidth) -> DiscreteSpace {
    if width > 0 {
        DiscreteSpace::one() << (width - 1)
    } else {
        0
    }
}

#[cfg(test)]
mod tests {
    use super::*;
}
<|endoftext|>