<commit_before>//! # Russet
//!
//! __Russet__ is a simple string tokenising library for Rust.  It supports
//! POSIX shell-style separation of a line of _words_ into a vector of
//! strings.
#![experimental]

#![feature(phase)]
#[phase(plugin)]
extern crate quickcheck_macros;
extern crate quickcheck;

use std::char::is_whitespace;
use std::collections::hashmap::HashMap;

/// A tokeniser object.
///
/// A Tokeniser can be fed characters from an iterator, string, or individually.
/// It is an _immutable_ object: actions on a Tokeniser consume the Tokeniser,
/// and produce a fresh copy of the Tokeniser.
///
/// At any stage, a Tokeniser can be consumed to produce the vector of words
/// it has read, using the `into_strings` method.  This method may fail if the
/// Tokeniser ended in a bad state (in the middle of a quoted string, or in
/// the middle of an escape sequence).
#[deriving(Clone)]
pub struct Tokeniser<Q, E> {
    /// The current vector of parsed words.
    vec: Vec<String>,

    /// Whether or not we are currently in a word.
    in_word: bool,

    /// The current closing quote character, if any.
    quote: Option<char>,

    /// Whether the tokeniser is currently processing an escape character.
    escaping: bool,

    /// Maps from quote openers to quote closers.
    quote_pairs: Q,

    /// Map from escape characters to their replacements.
    escape_pairs: E,

    /// The character preceding escape characters.
    escape_leader: Option<char>
}

/// A tokeniser error.
///
/// A Tokeniser's `into_strings` method can fail with one of the following
/// errors if called while the Tokeniser is in an unfinished state.
#[deriving(Eq, PartialEq, Show)]
pub enum Error {
    /// A quotation was opened, but not closed.
    UnmatchedQuote,

    /// An escape sequence was started, but not finished.
    UnfinishedEscape
}

impl<Q: Map<char, char>+Clone, E: Map<char, char>+Clone> Tokeniser<Q, E> {
    /// Creates a new, blank Tokeniser.
    ///
    /// # Arguments
    ///
    /// * `quote_pairs`   - A map, mapping characters that serve as opening
    ///                     quotes to their closing quotes.
    /// * `escape_pairs`  - A map, mapping escape characters to the characters
    ///                     they represent.
    /// * `escape_leader` - The character, if any, that starts an escape
    ///                     sequence.
    ///
    /// # Return value
    ///
    /// A new Tokeniser, with an empty state.  Attempting to take the
    /// string vector of the Tokeniser yields the empty vector.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::collections::hashmap::HashMap;
    /// use russet::Tokeniser;
    ///
    /// let quote_pairs: HashMap<char, char> =
    ///     vec![ ( '\"', '\"' ), ( '\'', '\'' ) ].move_iter().collect();
    /// let escape_pairs: HashMap<char, char> =
    ///     vec![ ( 'n', '\n' ) ].move_iter().collect();
    /// let tok = Tokeniser::new(quote_pairs, escape_pairs, Some('\\'));
    /// assert_eq!(tok.into_strings(), Ok(vec![]));
    /// ```
    pub fn new(quote_pairs: Q, escape_pairs: E, escape_leader: Option<char>)
               -> Tokeniser<Q, E> {
        Tokeniser {
            vec: vec![ String::new() ],
            in_word: false,
            quote: None,
            escaping: false,
            quote_pairs: quote_pairs,
            escape_pairs: escape_pairs,
            escape_leader: escape_leader
        }
    }

    /// Feeds a single character `chr` to a Tokeniser.
    ///
    /// # Return value
    ///
    /// A new Tokeniser, representing the state of the Tokeniser after
    /// consuming `chr`.
    ///
    /// # Example
    ///
    /// ```rust
    /// use russet::Tokeniser;
    /// use std::collections::hashmap::HashMap;
    ///
    /// let quote_pairs: HashMap<char, char> =
    ///     vec![ ( '\"', '\"' ), ( '\'', '\'' ) ].move_iter().collect();
    /// let escape_pairs: HashMap<char, char> =
    ///     vec![ ( 'n', '\n' ) ].move_iter().collect();
    /// let tok = Tokeniser::new(quote_pairs, escape_pairs, Some('\\'));
    /// let tok2 = tok.add_char('a').add_char('b').add_char('c');
    /// assert_eq!(tok2.into_strings(), Ok(vec![ "abc".into_string() ]));
    /// ```
    pub fn add_char(self, chr: char) -> Tokeniser<Q, E> {
        let mut new = self.clone();

        match (chr, self) {
            // Escape character while not escaped
            // -> Begin escape (and word if not in one already)
            ( '\\', Tokeniser { escaping: false, .. } ) => {
                new.escaping = true;
                new.in_word = true;
            },
            // Unescaped quote opening character, not currently in quoted word
            // -> Start quoting
            ( q, Tokeniser {
                escaping: false,
                quote: None,
                quote_pairs: ref qs,
                ..
            } ) if qs.contains_key(&q) => {
                new.quote = Some(qs.find(&q).unwrap().clone());
                new.in_word = true;
            },
            // Unescaped quote closing character, in quoted word, quotes ok
            // -> Stop quoting
            ( c, Tokeniser { escaping: false, quote: Some(cc), .. } )
                if c == cc => {
                new.quote = None;
                new.in_word = true;
            },
            // Unescaped whitespace, while not in a word
            // -> Ignore
            ( a, Tokeniser { escaping: false, in_word: false, .. } )
                if is_whitespace(a) => (),
            // Unescaped whitespace, while in a non-quoted word
            // -> End word
            ( a, Tokeniser { escaping: false, in_word: true, quote: None, .. } )
                if is_whitespace(a) => {
                new.in_word = false;
                new.vec.push(String::new());
            },
            // Known escaped character
            // -> Escape character
            ( e, Tokeniser { escaping: true, escape_pairs: ref es, .. } )
                if es.contains_key(&e) => {
                let x = es.find(&e).unwrap();

                new.in_word = true;
                new.escaping = false;
                new.vec.mut_last().mutate(|s| { s.push_char(x.clone()); s });
            },
            // Anything else
            // -> Echo
            ( a, _ ) => {
                new.in_word = true;
                new.escaping = false;
                new.vec.mut_last().mutate(|s| { s.push_char(a); s });
            }
        }

        new
    }

    /// Feeds a line into the Tokeniser.
    ///
    /// # Return value
    ///
    /// A new Tokeniser, representing the state of the Tokeniser after
    /// consuming `line`.
    pub fn add_line(self, line: &str) -> Tokeniser<Q, E> {
        line.trim().chars().fold(self, |s, chr| s.add_char(chr))
    }

    /// Destroys the tokeniser, extracting the string vector.
    ///
    /// # Return value
    ///
    /// A Result, containing the tokenised string vector if the Tokeniser
    /// was in a valid ending state, and an Error otherwise.
    pub fn into_strings(mut self) -> Result<Vec<String>, Error> {
        if self.in_word && self.quote.is_some() {
            Err(UnmatchedQuote)
        } else if self.escaping {
            Err(UnfinishedEscape)
        } else {
            if self.vec.last().map(|s| s.len() == 0).unwrap_or(false) {
                self.vec.pop();
            }

            Ok(self.vec)
        }
    }
}

/// A type for tokenisers returned by Russet.
pub type StockTokeniser = Tokeniser<HashMap<char, char>, HashMap<char, char>>;

/// Creates a Tokeniser that doesn't support quoting or escaping.
///
/// This is effectively equivalent to the Words iterator on string slices.
///
/// # Return value
///
/// A Tokeniser with no quoting or escaping.
///
/// # Example
///
/// ```rust
/// use russet::whitespace_split_tokeniser;
///
/// let tok = whitespace_split_tokeniser();
/// let tok2 = tok.add_line("this \"ignores quotes\"  and\n  \\slashes");
/// assert_eq!(tok2.into_strings(), Ok(vec!("this".into_string(),
///                                         "\"ignores".into_string(),
///                                         "quotes\"".into_string(),
///                                         "and".into_string(),
///                                         "slashes".into_string())));
/// ```
#[experimental]
pub fn whitespace_split_tokeniser() -> StockTokeniser {
    let quote_pairs: HashMap<char, char> = HashMap::new();
    let escape_pairs: HashMap<char, char> = HashMap::new();
    Tokeniser::new(quote_pairs, escape_pairs, None)
}

/// Unpacks a line into its constituent words.
#[experimental]
pub fn unpack(line: &str) -> Result<Vec<String>, Error> {
    let quote_pairs: HashMap<char, char> =
        vec![ ( '\"', '\"' ), ( '\'', '\'' ) ].move_iter().collect();
    let escape_pairs: HashMap<char, char> =
        vec![ ( 'n', '\n' ) ].move_iter().collect();

    line.trim().chars().fold(
        Tokeniser::new(quote_pairs, escape_pairs, Some('\\')),
        |s, chr| s.add_char(chr)
    ).into_strings()
}

#[cfg(test)]
mod test {
    use super::{
        unpack,
        whitespace_split_tokeniser,
        Error,
        UnmatchedQuote,
        UnfinishedEscape
    };

    #[test]
    fn unpack_unmatched_quote() {
        assert_eq!(unpack("\"abcde"), Err(UnmatchedQuote));
    }

    #[test]
    fn unpack_unfinished_escape() {
        assert_eq!(unpack("zxcvbn m\\"), Err(UnfinishedEscape));
    }

    #[test]
    fn unpack_empty_string() {
        assert_eq!(unpack(""), Ok(vec![]));
    }

    #[test]
    fn unpack_leading_whitespace() {
        let rhs = vec![ "abc".into_string(), "def".into_string() ];
        assert_eq!(unpack("     abc def"), Ok(rhs));
    }

    #[test]
    fn unpack_trailing_whitespace() {
        let rhs = vec![ "ghi".into_string(), "jkl".into_string() ];
        assert_eq!(unpack("ghi jkl     \n"), Ok(rhs));
    }

    #[test]
    fn unpack_enqueue_command() {
        let lhs =
            "enqueue file \"C:\\\\Users\\\\Test\\\\Artist - Title.mp3\" 1";
        let rhs = vec![ "enqueue".into_string(),
                        "file".into_string(),
                        "C:\\Users\\Test\\Artist - Title.mp3".into_string(),
                        "1".into_string() ];
        assert_eq!(unpack(lhs), Ok(rhs));
    }

    #[test]
    fn unpack_escaped_newline() {
        assert_eq!(unpack("abc\\nde"),     Ok(vec![ "abc\nde".into_string() ]));
        assert_eq!(unpack("\"abc\\nde\""), Ok(vec![ "abc\nde".into_string() ]));
    }

    /// The whitespace_split_tokeniser should provide the same strings as
    /// the Words iterator for an arbitrary string.
    #[quickcheck]
    fn whitespace_split_tokeniser_words_equivalence(line : String) -> bool {
        let line_slice = line.as_slice();

        let lhs: Result<Vec<String>, Error> =
            whitespace_split_tokeniser().add_line(line_slice).into_strings();
        let rhs: Result<Vec<String>, Error> =
            Ok(line_slice.words().map(|x| x.into_string()).collect());

        lhs == rhs
    }
}
<commit_msg>Implement shell-style escaping.<commit_after>//! # Russet
//!
//! __Russet__ is a simple string tokenising library for Rust.  It supports
//! POSIX shell-style separation of a line of _words_ into a vector of
//! strings.
#![experimental]

#![feature(phase)]
#[phase(plugin)]
extern crate quickcheck_macros;
extern crate quickcheck;

use std::char::is_whitespace;
use std::collections::hashmap::HashMap;

/// A tokeniser object.
///
/// A Tokeniser can be fed characters from an iterator, string, or individually.
/// It is an _immutable_ object: actions on a Tokeniser consume the Tokeniser,
/// and produce a fresh copy of the Tokeniser.
///
/// At any stage, a Tokeniser can be consumed to produce the vector of words
/// it has read, using the `into_strings` method.  This method may fail if the
/// Tokeniser ended in a bad state (in the middle of a quoted string, or in
/// the middle of an escape sequence).
#[deriving(Clone)]
pub struct Tokeniser<Q, E> {
    /// The current vector of parsed words.
    vec: Vec<String>,

    /// Whether or not we are currently in a word.
    in_word: bool,

    /// The current closing quote character and quote mode, if any.
    quote: Option<( char, QuoteMode )>,

    /// Whether the tokeniser is currently processing an escape character.
    escaping: bool,

    /// Maps from quote openers to quote closers.
    quote_pairs: Q,

    /// Map from escape characters to their replacements.
    escape_pairs: E,

    /// The character preceding escape characters.
    escape_leader: Option<char>
}

/// A quote mode.
#[deriving(Clone)]
pub enum QuoteMode {
    /// All characters except the closing character have their literal value.
    /// This is equivalent to single-quoting in POSIX shell.
    IgnoreEscapes,

    /// All characters except the closing character and escape sequences
    /// have their literal value.  This is roughly equivalent to
    /// double-quoting in POSIX shell.
    ParseEscapes
}

/// A tokeniser error.
///
/// A Tokeniser's `into_strings` method can fail with one of the following
/// errors if called while the Tokeniser is in an unfinished state.
#[deriving(Eq, PartialEq, Show)]
pub enum Error {
    /// A quotation was opened, but not closed.
    UnmatchedQuote,

    /// An escape sequence was started, but not finished.
    UnfinishedEscape
}

impl<Q: Map<char, ( char, QuoteMode )>+Collection+Clone,
     E: Map<char, char>+Clone> Tokeniser<Q, E> {
    /// Creates a new, blank Tokeniser.
    ///
    /// # Arguments
    ///
    /// * `quote_pairs`   - A map, mapping characters that serve as opening
    ///                     quotes to their closing quotes and quote modes.
    /// * `escape_pairs`  - A map, mapping escape characters to the characters
    ///                     they represent.  An empty map is treated as a
    ///                     _shell-style escape_: the
    /// * `escape_leader` - The character, if any, that starts an escape
    ///                     sequence.
    ///
    /// # Return value
    ///
    /// A new Tokeniser, with an empty state.  Attempting to take the
    /// string vector of the Tokeniser yields the empty vector.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::collections::hashmap::HashMap;
    /// use russet::{ Tokeniser, ParseEscapes, QuoteMode };
    ///
    /// let quote_pairs: HashMap<char, ( char, QuoteMode )> =
    ///     vec![ ( '\"', ( '\"', ParseEscapes ) ) ].move_iter().collect();
    /// let escape_pairs: HashMap<char, char> =
    ///     vec![ ( 'n', '\n' ) ].move_iter().collect();
    /// let tok = Tokeniser::new(quote_pairs, escape_pairs, Some('\\'));
    /// assert_eq!(tok.into_strings(), Ok(vec![]));
    /// ```
    pub fn new(quote_pairs: Q, escape_pairs: E, escape_leader: Option<char>)
               -> Tokeniser<Q, E> {
        Tokeniser {
            vec: vec![ String::new() ],
            in_word: false,
            quote: None,
            escaping: false,
            quote_pairs: quote_pairs,
            escape_pairs: escape_pairs,
            escape_leader: escape_leader
        }
    }

    /// Feeds a single character `chr` to a Tokeniser.
    ///
    /// # Return value
    ///
    /// A new Tokeniser, representing the state of the Tokeniser after
    /// consuming `chr`.
    ///
    /// # Example
    ///
    /// ```rust
    /// use russet::whitespace_split_tokeniser;
    ///
    /// let tok = whitespace_split_tokeniser();
    /// let tok2 = tok.add_char('a').add_char('b').add_char('c');
    /// assert_eq!(tok2.into_strings(), Ok(vec![ "abc".into_string() ]));
    /// ```
    pub fn add_char(self, chr: char) -> Tokeniser<Q, E> {
        let mut new = self.clone();

        match (chr, self) {
            // ESCAPE SEQUENCES
            //   Shell-style escaping (no escapes defined)
            //   -> Echo character
            ( c, Tokeniser { escaping: true, escape_pairs: ref es, .. } )
                if es.is_empty() => {
                new.in_word = true;
                new.escaping = false;
                new.vec.mut_last().mutate(|s| { s.push_char(c); s });
            },
            // Known escaped character, otherwise
            // -> Escape character
            ( e, Tokeniser { escaping: true, escape_pairs: ref es, .. } )
                if es.contains_key(&e) => {
                let x = es.find(&e).unwrap();

                new.in_word = true;
                new.escaping = false;
                new.vec.mut_last().mutate(|s| { s.push_char(x.clone()); s });
            },

            // ESCAPE LEADER
            //   Escape leader, not in quotes
            //   -> Begin escape (and word if not in one already)
            ( c, Tokeniser {
                escaping: false,
                quote: None,
                escape_leader: Some(e),
                ..
            } ) if e == c => {
                new.escaping = true;
                new.in_word = true;
            },
            //   Escape leader, in escape-permitting quotes
            //   -> Begin escape (and word if not in one already)
            ( c, Tokeniser {
                escaping: false,
                quote: Some(( _, ParseEscapes )),
                escape_leader: Some(e),
                ..
            } ) if e == c => {
                new.escaping = true;
                new.in_word = true;
            },

            // QUOTE OPENING
            //   Quote opening character, not currently in quoted word
            //   -> Start quoting
            ( q, Tokeniser {
                escaping: false,
                quote: None,
                quote_pairs: ref qs,
                ..
            } ) if qs.contains_key(&q) => {
                new.quote = Some(qs.find(&q).unwrap().clone());
                new.in_word = true;
            },

            // QUOTE CLOSING
            //   Quote closing character, in quoted word, quotes ok
            //   -> Stop quoting
            ( c, Tokeniser { escaping: false, quote: Some(( cc, _ )), .. } )
                if c == cc => {
                new.quote = None;
                new.in_word = true;
            },

            // UNESCAPED WHITESPACE
            //   Unescaped whitespace, while not in a word
            //   -> Ignore
            ( a, Tokeniser { escaping: false, in_word: false, .. } )
                if is_whitespace(a) => (),
            //   Unescaped whitespace, while in a non-quoted word
            //   -> End word
            ( a, Tokeniser { escaping: false, in_word: true, quote: None, .. } )
                if is_whitespace(a) => {
                new.in_word = false;
                new.vec.push(String::new());
            },

            // DEFAULT
            //   Anything else
            //   -> Echo
            ( a, _ ) => {
                new.in_word = true;
                new.escaping = false;
                new.vec.mut_last().mutate(|s| { s.push_char(a); s });
            }
        }

        new
    }

    /// Feeds a line into the Tokeniser.
    ///
    /// # Return value
    ///
    /// A new Tokeniser, representing the state of the Tokeniser after
    /// consuming `line`.
    pub fn add_line(self, line: &str) -> Tokeniser<Q, E> {
        line.trim().chars().fold(self, |s, chr| s.add_char(chr))
    }

    /// Destroys the tokeniser, extracting the string vector.
    ///
    /// # Return value
    ///
    /// A Result, containing the tokenised string vector if the Tokeniser
    /// was in a valid ending state, and an Error otherwise.
    pub fn into_strings(mut self) -> Result<Vec<String>, Error> {
        if self.in_word && self.quote.is_some() {
            Err(UnmatchedQuote)
        } else if self.escaping {
            Err(UnfinishedEscape)
        } else {
            if self.vec.last().map(|s| s.len() == 0).unwrap_or(false) {
                self.vec.pop();
            }

            Ok(self.vec)
        }
    }
}

/// A type for tokenisers returned by Russet.
pub type StockTokeniser = Tokeniser<HashMap<char, ( char, QuoteMode )>,
                                    HashMap<char, char>>;

/// Creates a Tokeniser that doesn't support quoting or escaping.
///
/// This is effectively equivalent to the Words iterator on string slices.
///
/// # Return value
///
/// A Tokeniser with no quoting or escaping.
///
/// # Example
///
/// ```rust
/// use russet::whitespace_split_tokeniser;
///
/// let tok = whitespace_split_tokeniser();
/// let tok2 = tok.add_line("this \"ignores quotes\"  and\n  \\slashes");
/// assert_eq!(tok2.into_strings(), Ok(vec!("this".into_string(),
///                                         "\"ignores".into_string(),
///                                         "quotes\"".into_string(),
///                                         "and".into_string(),
///                                         "\\slashes".into_string())));
/// ```
#[experimental]
pub fn whitespace_split_tokeniser() -> StockTokeniser {
    let quote_pairs: HashMap<char, ( char, QuoteMode )> = HashMap::new();
    let escape_pairs: HashMap<char, char> = HashMap::new();
    Tokeniser::new(quote_pairs, escape_pairs, None)
}

/// Creates a Tokeniser that provides shell-style quoting.
///
/// This recognises pairs of " and ' as delineating words, and parses
/// anything following a \ as its literal value.  Anything in single quotes
/// is returned verbatim.
///
/// # Return value
///
/// A Tokeniser with shell-style quoting.
///
/// # Example
///
/// ```rust
/// use russet::shell_style_tokeniser;
///
/// let tok = shell_style_tokeniser();
/// let tok2 = tok.add_line("word1 word\\ 2 \"word\\ 3\" 'word\\ \"4\"'");
/// assert_eq!(tok2.into_strings(), Ok(vec!("word1".into_string(),
///                                         "word 2".into_string(),
///                                         "word 3".into_string(),
///                                         "word\\ \"4\"".into_string())));
/// ```
#[experimental]
pub fn shell_style_tokeniser() -> StockTokeniser {
    let quote_pairs: HashMap<char, ( char, QuoteMode )> =
        vec![ ( '\"', ( '\"', ParseEscapes ) ),
              ( '\'', ( '\'', IgnoreEscapes ) ) ].move_iter().collect();
    let escape_pairs: HashMap<char, char> = HashMap::new();
    Tokeniser::new(quote_pairs, escape_pairs, Some('\\'))
}

/// Unpacks a line into its constituent words.
#[experimental]
pub fn unpack(line: &str) -> Result<Vec<String>, Error> {
    let quote_pairs: HashMap<char, ( char, QuoteMode )> =
        vec![ ( '\"', ( '\"', ParseEscapes ) ),
              ( '\'', ( '\'', ParseEscapes ) ) ].move_iter().collect();
    let escape_pairs: HashMap<char, char> =
        vec![ ( 'n', '\n' ) ].move_iter().collect();

    line.trim().chars().fold(
        Tokeniser::new(quote_pairs, escape_pairs, Some('\\')),
        |s, chr| s.add_char(chr)
    ).into_strings()
}

#[cfg(test)]
mod test {
    use super::{
        unpack,
        whitespace_split_tokeniser,
        Error,
        UnmatchedQuote,
        UnfinishedEscape
    };

    #[test]
    fn unpack_unmatched_quote() {
        assert_eq!(unpack("\"abcde"), Err(UnmatchedQuote));
    }

    #[test]
    fn unpack_unfinished_escape() {
        assert_eq!(unpack("zxcvbn m\\"), Err(UnfinishedEscape));
    }

    #[test]
    fn unpack_empty_string() {
        assert_eq!(unpack(""), Ok(vec![]));
    }

    #[test]
    fn unpack_leading_whitespace() {
        let rhs = vec![ "abc".into_string(), "def".into_string() ];
        assert_eq!(unpack("     abc def"), Ok(rhs));
    }

    #[test]
    fn unpack_trailing_whitespace() {
        let rhs = vec![ "ghi".into_string(), "jkl".into_string() ];
        assert_eq!(unpack("ghi jkl     \n"), Ok(rhs));
    }

    #[test]
    fn unpack_enqueue_command() {
        let lhs =
            "enqueue file \"C:\\\\Users\\\\Test\\\\Artist - Title.mp3\" 1";
        let rhs = vec![ "enqueue".into_string(),
                        "file".into_string(),
                        "C:\\Users\\Test\\Artist - Title.mp3".into_string(),
                        "1".into_string() ];
        assert_eq!(unpack(lhs), Ok(rhs));
    }

    #[test]
    fn unpack_escaped_newline() {
        assert_eq!(unpack("abc\\nde"),     Ok(vec![ "abc\nde".into_string() ]));
        assert_eq!(unpack("\"abc\\nde\""), Ok(vec![ "abc\nde".into_string() ]));
    }

    /// The whitespace_split_tokeniser should provide the same strings as
    /// the Words iterator for an arbitrary string.
    #[quickcheck]
    fn whitespace_split_tokeniser_words_equivalence(line : String) -> bool {
        let line_slice = line.as_slice();

        let lhs: Result<Vec<String>, Error> =
            whitespace_split_tokeniser().add_line(line_slice).into_strings();
        let rhs: Result<Vec<String>, Error> =
            Ok(line_slice.words().map(|x| x.into_string()).collect());

        lhs == rhs
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(convert)]

extern crate libc;

pub mod apr;
pub mod ap_exports;

pub mod util_filter;
pub mod httpd;

pub mod ap_mmn;
pub mod http_config;

pub mod http_protocol;

pub mod wrapper;

use libc::{c_void, c_char, c_int};

use std::ptr;
use std::ffi::CString;

use apr::raw::{apr_pool_t, APR_HOOK_MIDDLE};

use httpd::raw::{OK, request_rec};
use ap_exports::raw::{ap_hook_handler};
use http_config::raw::{command_rec};
use http_protocol::raw::{ap_rwrite};

macro_rules! module_def {
   ($module:ident, $handler:ident, $cname:expr) => {
      const CNAME: &'static [u8] = $cname;
      const CNAME_PTR: *const &'static [u8] = &CNAME;
      const CNAME_CHAR_PTR: *const c_char = CNAME_PTR as *const c_char;

      #[no_mangle]
      pub static mut $module: http_config::raw::module = http_config::raw::module {
         version: ap_mmn::raw::MODULE_MAGIC_NUMBER_MAJOR,
         minor_version: ap_mmn::raw::MODULE_MAGIC_NUMBER_MINOR,
         module_index: -1,
         name: CNAME_CHAR_PTR,
         dynamic_load_handle: 0 as *mut c_void,
         next: 0 as *mut http_config::raw::module,
         magic: ap_mmn::raw::MODULE_MAGIC_COOKIE,
         rewrite_args: None,
         create_dir_config: None,
         merge_dir_config: None,
         create_server_config: None,
         merge_server_config: None,
         cmds: 0 as *const command_rec,
         register_hooks: Some(module_hooks),
      };

      extern "C" fn module_hooks(_: *mut apr_pool_t) {
         unsafe {
            ap_hook_handler(
               Some($handler), ptr::null(), ptr::null(), APR_HOOK_MIDDLE
            );
         }
      }

   }
}

module_def!(aprust_module, aprust_handler, b"mod_aprust\0");

fn rwrite<T: Into<Vec<u8>>>(t: T, r: *mut request_rec) {
   let s = CString::new(t).unwrap();
   let len = s.to_bytes().len();

   unsafe {
      ap_rwrite(s.as_ptr() as *mut c_void, len as i32, r);
   }
}

fn dump_str<T: Into<Vec<u8>>>(r: *mut request_rec, name: T, optional: Option<&str>) {
   rwrite("
", r);
   rwrite(name, r);
   rwrite(": ", r);

   match optional {
      None => {
         rwrite("NULL", r);
      },
      Some(slice) => {
         let html = format!("{:?}", slice);
         rwrite(html, r);
      }
   };

   rwrite("
", r);
}

#[no_mangle]
pub extern "C" fn aprust_handler(r: *mut request_rec) -> c_int {
   let req = httpd::Request::from_raw_ptr(r).unwrap();

   let mut headers_out = req.headers_out().unwrap();
   headers_out.set("Test-Key", "Hello");

   let headers_in = req.headers_in().unwrap();
   rwrite("<meta charset=\"utf-8\">", r);

   dump_str(r, "Cookie", headers_in.get("Cookie"));

   dump_str(r, "the_request", req.the_request());
   dump_str(r, "protocol", req.protocol());
   dump_str(r, "hostname", req.hostname());
   dump_str(r, "status_line", req.status_line());
   dump_str(r, "method", req.method());
   dump_str(r, "range", req.range());
   dump_str(r, "content_type", req.content_type());
   dump_str(r, "handler", req.handler());
   dump_str(r, "content_encoding", req.content_encoding());
   dump_str(r, "vlist_validator", req.vlist_validator());
   dump_str(r, "user", req.user());
   dump_str(r, "ap_auth_type", req.ap_auth_type());
   dump_str(r, "unparsed_uri", req.unparsed_uri());
   dump_str(r, "uri", req.uri());
   dump_str(r, "filename", req.filename());
   dump_str(r, "canonical_filename", req.canonical_filename());
   dump_str(r, "path_info", req.path_info());
   dump_str(r, "args", req.args());
   dump_str(r, "log_id", req.log_id());
   dump_str(r, "useragent_ip", req.useragent_ip());

   rwrite("", r);

   OK
}
<commit_msg>Macro naming changes -> cname to c_name.<commit_after>#![feature(libc)]
#![feature(convert)]

extern crate libc;

pub mod apr;
pub mod ap_exports;

pub mod util_filter;
pub mod httpd;

pub mod ap_mmn;
pub mod http_config;

pub mod http_protocol;

pub mod wrapper;

use libc::{c_void, c_char, c_int};

use std::ptr;
use std::ffi::CString;

use apr::raw::{apr_pool_t, APR_HOOK_MIDDLE};

use httpd::raw::{OK, request_rec};
use ap_exports::raw::{ap_hook_handler};
use http_config::raw::{command_rec};
use http_protocol::raw::{ap_rwrite};

macro_rules! module_def {
   ($module:ident, $handler:ident, $c_name:expr) => {
      const C_NAME: &'static [u8] = $c_name;
      const C_NAME_PTR: *const &'static [u8] = &C_NAME;
      const C_NAME_CHAR_PTR: *const c_char = C_NAME_PTR as *const c_char;

      #[no_mangle]
      pub static mut $module: http_config::raw::module = http_config::raw::module {
         version: ap_mmn::raw::MODULE_MAGIC_NUMBER_MAJOR,
         minor_version: ap_mmn::raw::MODULE_MAGIC_NUMBER_MINOR,
         module_index: -1,
         name: C_NAME_CHAR_PTR,
         dynamic_load_handle: 0 as *mut c_void,
         next: 0 as *mut http_config::raw::module,
         magic: ap_mmn::raw::MODULE_MAGIC_COOKIE,
         rewrite_args: None,
         create_dir_config: None,
         merge_dir_config: None,
         create_server_config: None,
         merge_server_config: None,
         cmds: 0 as *const command_rec,
         register_hooks: Some(module_hooks),
      };

      extern "C" fn module_hooks(_: *mut apr_pool_t) {
         unsafe {
            ap_hook_handler(
               Some($handler), ptr::null(), ptr::null(), APR_HOOK_MIDDLE
            );
         }
      }

   }
}

module_def!(aprust_module, aprust_handler, b"mod_aprust\0");

fn rwrite<T: Into<Vec<u8>>>(t: T, r: *mut request_rec) {
   let s = CString::new(t).unwrap();
   let len = s.to_bytes().len();

   unsafe {
      ap_rwrite(s.as_ptr() as *mut c_void, len as i32, r);
   }
}

fn dump_str<T: Into<Vec<u8>>>(r: *mut request_rec, name: T, optional: Option<&str>) {
   rwrite("
", r);
   rwrite(name, r);
   rwrite(": ", r);

   match optional {
      None => {
         rwrite("NULL", r);
      },
      Some(slice) => {
         let html = format!("{:?}", slice);
         rwrite(html, r);
      }
   };

   rwrite("
", r);
}

#[no_mangle]
pub extern "C" fn aprust_handler(r: *mut request_rec) -> c_int {
   let req = httpd::Request::from_raw_ptr(r).unwrap();

   let mut headers_out = req.headers_out().unwrap();
   headers_out.set("Test-Key", "Hello");

   let headers_in = req.headers_in().unwrap();
   rwrite("<meta charset=\"utf-8\">", r);

   dump_str(r, "Cookie", headers_in.get("Cookie"));

   dump_str(r, "the_request", req.the_request());
   dump_str(r, "protocol", req.protocol());
   dump_str(r, "hostname", req.hostname());
   dump_str(r, "status_line", req.status_line());
   dump_str(r, "method", req.method());
   dump_str(r, "range", req.range());
   dump_str(r, "content_type", req.content_type());
   dump_str(r, "handler", req.handler());
   dump_str(r, "content_encoding", req.content_encoding());
   dump_str(r, "vlist_validator", req.vlist_validator());
   dump_str(r, "user", req.user());
   dump_str(r, "ap_auth_type", req.ap_auth_type());
   dump_str(r, "unparsed_uri", req.unparsed_uri());
   dump_str(r, "uri", req.uri());
   dump_str(r, "filename", req.filename());
   dump_str(r, "canonical_filename", req.canonical_filename());
   dump_str(r, "path_info", req.path_info());
   dump_str(r, "args", req.args());
   dump_str(r, "log_id", req.log_id());
   dump_str(r, "useragent_ip", req.useragent_ip());

   rwrite("", r);

   OK
}
<|endoftext|>


<commit_before>extern crate rayon;

use rayon::prelude::*;
use rayon::par_iter::collect;

mod types;
pub use types::TestResult;

pub trait Runnable {
    fn run(&self) -> TestResult;
}

mod reporters;
use reporters::{Reporter, CompositeReporter, ProgressReporter, StatisticsReporter};

pub struct TestRunner {
    parallelism: bool,
}

impl TestRunner {
    pub fn new(parallelism: bool) -> TestRunner {
        TestRunner { parallelism: parallelism }
    }

    pub fn run(&self, tests: &Vec<Box<Runnable + Sync>>) {
        let reporters: Vec<Box<Reporter>> = vec![Box::new(ProgressReporter::new()),
                                                 Box::new(StatisticsReporter::new())];
        let mut reporter = CompositeReporter::new(reporters);
        reporter.start();

        if self.parallelism {
            let mut results = Vec::with_capacity(tests.len());
            collect::collect_into(tests.into_par_iter()
                                      .map(move |test| test.run()),
                                  &mut results);

            for result in results {
                reporter.record(&result);
            }
        } else {
            for result in tests.into_iter().map(|test| test.run()) {
                reporter.record(&result);
            }
        }

        reporter.report();
    }
}
<commit_msg>Add a missing lifetime to the run function.<commit_after>extern crate rayon;

use rayon::prelude::*;
use rayon::par_iter::collect;

mod types;
pub use types::TestResult;

pub trait Runnable {
    fn run(&self) -> TestResult;
}

mod reporters;
use reporters::{Reporter, CompositeReporter, ProgressReporter, StatisticsReporter};

pub struct TestRunner {
    parallelism: bool,
}

impl TestRunner {
    pub fn new(parallelism: bool) -> TestRunner {
        TestRunner { parallelism: parallelism }
    }

    pub fn run<'run>(&self, tests: &Vec<Box<Runnable + Sync + 'run>>) {
        let reporters: Vec<Box<Reporter>> = vec![Box::new(ProgressReporter::new()),
                                                 Box::new(StatisticsReporter::new())];
        let mut reporter = CompositeReporter::new(reporters);
        reporter.start();

        if self.parallelism {
            let mut results = Vec::with_capacity(tests.len());
            collect::collect_into(tests.into_par_iter()
                                      .map(move |test| test.run()),
                                  &mut results);

            for result in results {
                reporter.record(&result);
            }
        } else {
            for result in tests.into_iter().map(|test| test.run()) {
                reporter.record(&result);
            }
        }

        reporter.report();
    }
}
<|endoftext|>


<commit_before>#![deny(/*missing_docs,*/unsafe_code,
    unstable_features,
    unused_import_braces, unused_qualifications)]

extern crate nom;

#[macro_use]
extern crate log;

extern crate itertools;

extern crate md5;

extern crate dns_parser;
extern crate der_parser;
extern crate ipsec_parser;
extern crate kerberos_parser;
extern crate ntp_parser;
extern crate openvpn_parser;
extern crate radius_parser;
extern crate snmp_parser;
extern crate ssh_parser;
extern crate tls_parser;
extern crate x509_parser;

pub use rparser::*;
#[macro_use]
pub mod rparser;

mod variant;
pub use variant::*;

mod dhcp;
pub use dhcp::*;

mod dns_tcp;
pub use dns_tcp::{DnsTCPBuilder, DnsTCPParser, dns_probe_tcp};
mod dns_udp;
pub use dns_udp::{DnsUDPBuilder, DnsUDPParser, dns_probe_udp};

mod kerberos_tcp;
pub use kerberos_tcp::{KerberosTCPBuilder,KerberosParserTCP,kerberos_probe_tcp};
mod kerberos_udp;
pub use kerberos_udp::{KerberosUDPBuilder,KerberosParserUDP,kerberos_probe_udp};

mod ipsec;
mod ipsec_natt;
pub use ipsec::*;
pub use ipsec_natt::*;

pub use ntp::*;
pub mod ntp;

mod openvpn;
pub use openvpn::{OpenVPNTCPBuilder,OpenVPNTCPParser,openvpn_tcp_probe};
mod openvpn_udp;
pub use openvpn_udp::{OpenVPNUDPBuilder,OpenVPNUDPParser,openvpn_udp_probe};

mod radius;
pub use radius::{RadiusBuilder,RadiusParser};

mod snmp;
pub use snmp::{SNMPv1Builder,SNMPv2cBuilder,SNMPParser,snmp_probe,snmpv1_probe,snmpv2c_probe};
mod snmpv3;
pub use snmpv3::{SNMPv3Builder,SNMPv3Parser,snmpv3_probe};

mod ssh;
pub use ssh::{SSHBuilder,SSHParser,ssh_probe};

pub use tls::*;
pub mod tls;<commit_msg>Remove crates declaration, not required since edition 2018<commit_after>#![deny(/*missing_docs,*/unsafe_code,
    unstable_features,
    unused_import_braces, unused_qualifications)]

#[macro_use]
extern crate log;

pub use rparser::*;
#[macro_use]
pub mod rparser;

mod variant;
pub use variant::*;

mod dhcp;
pub use dhcp::*;

mod dns_tcp;
pub use dns_tcp::{DnsTCPBuilder, DnsTCPParser, dns_probe_tcp};
mod dns_udp;
pub use dns_udp::{DnsUDPBuilder, DnsUDPParser, dns_probe_udp};

mod kerberos_tcp;
pub use kerberos_tcp::{KerberosTCPBuilder,KerberosParserTCP,kerberos_probe_tcp};
mod kerberos_udp;
pub use kerberos_udp::{KerberosUDPBuilder,KerberosParserUDP,kerberos_probe_udp};

mod ipsec;
mod ipsec_natt;
pub use ipsec::*;
pub use ipsec_natt::*;

pub use ntp::*;
pub mod ntp;

mod openvpn;
pub use openvpn::{OpenVPNTCPBuilder,OpenVPNTCPParser,openvpn_tcp_probe};
mod openvpn_udp;
pub use openvpn_udp::{OpenVPNUDPBuilder,OpenVPNUDPParser,openvpn_udp_probe};

mod radius;
pub use radius::{RadiusBuilder,RadiusParser};

mod snmp;
pub use snmp::{SNMPv1Builder,SNMPv2cBuilder,SNMPParser,snmp_probe,snmpv1_probe,snmpv2c_probe};
mod snmpv3;
pub use snmpv3::{SNMPv3Builder,SNMPv3Parser,snmpv3_probe};

mod ssh;
pub use ssh::{SSHBuilder,SSHParser,ssh_probe};

pub use tls::*;
pub mod tls;<|endoftext|>


<commit_before>// Copyright (c) 2015 William Light <wrl@illest.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

extern crate byteorder;

mod message;
mod argument;

pub use message::Message;
pub use argument::Argument;

#[macro_export]
macro_rules! osc_args {
    [] => {{
        vec![]
    }};

    [$($x:expr),*] => {{
        let mut v = vec![];
        $(v.push(Argument::from($x));)*
        v
    }};
}

mod test;
<commit_msg>using $crate properly would also help<commit_after>// Copyright (c) 2015 William Light <wrl@illest.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

extern crate byteorder;

mod message;
mod argument;

pub use message::Message;
pub use argument::Argument;

#[macro_export]
macro_rules! osc_args {
    [] => {{
        vec![]
    }};

    [$($x:expr),*] => {{
        let mut v = vec![];
        $(v.push($crate::Argument::from($x));)*
        v
    }};
}

mod test;
<|endoftext|>


<commit_before>pub(crate) mod base;
pub mod mutators;
pub mod nav;
pub mod search;
pub mod view;

use std::cell::UnsafeCell;
use std::error::Error;
use std::fmt;
use std::hash::Hash;
use std::ops::Deref;

use base::{EdgeId, RawEdge, RawVertex, VertexId};
use mutators::{MutEdge, MutNode};
use nav::{Edge, Node};
use symbol_map::indexing::{Indexing, Insertion};
use symbol_map::SymbolId;

/// A search graph.
///
/// Supports incremental rollout of game state topology and vertex
/// de-duplication with transposition tables. Limited support is provided for
/// deletion of components and compaction in memory after deletion.
///
/// - `T`: The type of game states. It is required to derive `Hash` and `Eq` to
///   so that it may be stored in a hashtable, where game states are looked up to
///   support de-duplication of game states. It is required to derive `Clone` to
///   accommodate a limitation of the `HashMap` interface.
/// - `S`: The type of graph vertex data.
/// - `A`: The type of graph edge data.
///
/// Vertices are addressed by content. To examine graph contents, obtain a node
/// handle with `find_node`. To modify graph contents, add new root vertices with
/// `add_node` and retrieve extant vertices with `find_node_mut`.
pub struct Graph<T: Hash + Eq + Clone, S, A> {
  /// Lookup table that maps from game states to `VertexId`.
  state_ids: symbol_map::indexing::HashIndexing<T, VertexId>,
  vertices: Vec<RawVertex<S>>, // Indexed by VertexId.
  arcs: Vec<RawEdge<A>>,       // Indexed by EdgeId.
}

impl<T, S, A> Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Creates an empty `Graph` with no vertices or edges.
  pub fn new() -> Self {
    Graph {
      state_ids: Default::default(),
      vertices: Vec::new(),
      arcs: Vec::new(),
    }
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex(&self, state: VertexId) -> &RawVertex<S> {
    &self.vertices[state.as_usize()]
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex_mut(&mut self, state: VertexId) -> &mut RawVertex<S> {
    &mut self.vertices[state.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc(&self, arc: EdgeId) -> &RawEdge<A> {
    &self.arcs[arc.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc_mut(&mut self, arc: EdgeId) -> &mut RawEdge<A> {
    &mut self.arcs[arc.as_usize()]
  }

  /// Returns the game state associated with `id`.
  fn get_state(&self, id: VertexId) -> Option<&T> {
    self.state_ids.get_symbol(&id).as_ref().map(|x| x.data())
  }

  /// Adds a new vertex with the given data, returning a mutable reference to it.
  ///
  /// This method does not add incoming or outgoing edges (expanded or
  /// not). That must be done by calling `add_arc` with the new vertex
  /// `VertexId`.
  fn add_raw_vertex(&mut self, data: S) -> &mut RawVertex<S> {
    self.vertices.push(RawVertex {
      data: data,
      parents: Vec::new(),
      children: Vec::new(),
    });
    self.vertices.last_mut().unwrap()
  }

  /// Adds a new edge with the given data, source, and target. Returns the
  /// internal ID for the new edge.
  fn add_raw_edge(&mut self, data: A, source: VertexId, target: VertexId) -> EdgeId {
    let arc_id = EdgeId(self.arcs.len());
    self.get_vertex_mut(source).children.push(arc_id);
    self.get_vertex_mut(target).parents.push(arc_id);
    self.arcs.push(RawEdge {
      data: data,
      source: source,
      target: target,
    });
    arc_id
  }

  /// Gets a node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn find_node<'s>(&'s self, state: &T) -> Option<Node<'s, T, S, A>> {
    match self.state_ids.get(state) {
      Some(symbol) => Some(Node::new(self, *symbol.id())),
      None => None,
    }
  }

  /// Gets a mutable node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn find_node_mut<'s>(&'s mut self, state: &T) -> Option<MutNode<'s, T, S, A>> {
    match self.state_ids.get(state).map(|s| s.id().clone()) {
      Some(id) => Some(MutNode::new(self, id)),
      None => None,
    }
  }

  /// Adds a vertex (with no parents or children) for the given game state and
  /// data and returns a mutable handle for it.
  ///
  /// If `state` is already known, returns a mutable handle to that state,
  /// ignoring the `data` parameter. As a result, this method is guaranteed to
  /// return a handle for a root vertex only when `state` is a novel game
  /// state.
  pub fn add_node<'s>(&'s mut self, state: T, data: S) -> MutNode<'s, T, S, A> {
    let node_id = match self.state_ids.get_or_insert(state).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        self.add_raw_vertex(data);
        id
      }
    };
    MutNode::new(self, node_id)
  }

  /// Adds an edge from the vertex with state data `source` to the vertex with
  /// state data `dest`. If vertices are not found for `source` or `dest`,
  /// they are added, with the data provided by `source_data` and `dest_data`
  /// callbacks.
  ///
  /// The edge that is created will have the data `edge_data`. Returns a
  /// mutable edge handle for that edge.
  pub fn add_edge<'s, F, G>(
    &'s mut self,
    source: T,
    source_data: F,
    dest: T,
    dest_data: G,
    edge_data: A,
  ) -> MutEdge<'s, T, S, A>
  where
    F: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
    G: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
  {
    let source_id = match self.state_ids.get_or_insert(source).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = source_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let dest_id = match self.state_ids.get_or_insert(dest).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = dest_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let edge_id = self.add_raw_edge(edge_data, source_id, dest_id);
    MutEdge::new(self, edge_id)
  }

  /// Returns the number of vertices in the graph.
  pub fn vertex_count(&self) -> usize {
    // TODO: This is actually the number of vertices we have allocated.
    self.vertices.len()
  }

  /// Returns the number of edges in the graph.
  pub fn edge_count(&self) -> usize {
    // TODO: This is actually the number of edges we have allocated.
    self.arcs.len()
  }
}

/// Allows both read-only references into a `Graph` and operations that modify
/// the graph but do not invalidate family of types defined in the `nav`
/// module.
///
/// All methods on `Graph` that take a `&self` parameter may also be called on
/// an `AppendOnlyGraph`. The `add_node` and `add_edge` methods may also be
/// called, because they do not invalidate `Node`, `Edge`, or other such smart
/// pointers into the underlying graph. Unlike the analogous methods on `Graph`,
/// these methods return a read-only view of the graph topology, instead of
/// granting read-write access.
///
/// For example:
///
/// ```rust
/// # use search_graph::{AppendOnlyGraph, Graph};
/// # use search_graph::nav::{Node, Edge};
/// # fn main() {
/// let appendable: AppendOnlyGraph<u32, String, f32> = Graph::new().into();
/// let root1 = appendable.append_node(0, "data1".to_string());
/// // If appendable were a Graph, we could not call append_node while root1 is alive.
/// let root2 = appendable.append_node(1, "data2".to_string());
/// assert_eq!("data1", appendable.find_node(&0).unwrap().get_data());
/// assert!(root1.is_leaf());
/// let edge = appendable.append_edge(root1.clone(), root2.clone(), 3.3).unwrap();
/// assert_eq!(*edge.get_source().get_label(), 0);
/// assert_eq!(*edge.get_target().get_label(), 1);
/// assert!(!root1.is_leaf());
/// # }
/// ```
pub struct AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  graph: UnsafeCell<Graph<T, S, A>>,
}

#[derive(Debug)]
pub enum AppendEdgeError {
  GraphMismatch,
}

impl fmt::Display for AppendEdgeError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}", self)
  }
}

impl Error for AppendEdgeError {
  fn description(&self) -> &'static str {
    match *self {
      AppendEdgeError::GraphMismatch => {
        "Underlying graph mismatch (cannot create an edge between vertices in two different graphs)"
      }
    }
  }
}

impl<T, S, A> AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  pub fn append_node<'s>(&'s self, state: T, data: S) -> Node<'s, T, S, A> {
    let graph: &mut Graph<T, S, A> = unsafe { &mut *self.graph.get() };
    graph.add_node(state, data).to_node()
  }

  pub fn append_edge<'s, 'a>(
    &'s self,
    source: Node<'a, T, S, A>,
    target: Node<'a, T, S, A>,
    edge_data: A,
  ) -> Result<Edge<'s, T, S, A>, AppendEdgeError> {
    if std::ptr::eq(source.graph, target.graph) {
      let graph: &mut Graph<T, S, A> = unsafe { &mut *self.graph.get() };
      let id = graph.add_raw_edge(edge_data, source.id, target.id);
      Ok(Edge { graph, id })
    } else {
      Err(AppendEdgeError::GraphMismatch)
    }
  }
}

impl<T, S, A> Deref for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  type Target = Graph<T, S, A>;

  fn deref(&self) -> &Graph<T, S, A> {
    unsafe { &*self.graph.get() }
  }
}

impl<T, S, A> From<AppendOnlyGraph<T, S, A>> for Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: AppendOnlyGraph<T, S, A>) -> Self {
    graph.graph.into_inner()
  }
}

impl<T, S, A> From<Graph<T, S, A>> for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: Graph<T, S, A>) -> Self {
    AppendOnlyGraph {
      graph: UnsafeCell::new(graph),
    }
  }
}

#[cfg(test)]
mod test {
  use crossbeam_utils::thread;
  use std::sync::Arc;

  type Graph = crate::Graph<&'static str, &'static str, &'static str>;

  #[test]
  fn send_to_thread_safe_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let graph = Arc::new(g);
    thread::scope(move |s| {
      let g = graph.clone();
      let t1 = s.spawn(move |_| g.find_node(&"root").map(|n| n.get_id()));
      let g = graph.clone();
      let t2 = s.spawn(move |_| g.find_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }

  #[test]
  fn sync_to_thread_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let g = &g;
    thread::scope(|s| {
      let t1 = s.spawn(move |_| g.find_node(&"root").map(|n| n.get_id()));
      let t2 = s.spawn(move |_| g.find_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }
}
<commit_msg>Ditch AppendOnlyGraph, which was broken and unfixable.<commit_after>pub(crate) mod base;
pub mod mutators;
pub mod nav;
pub mod search;
pub mod view;

use std::hash::Hash;

use base::{EdgeId, RawEdge, RawVertex, VertexId};
use symbol_map::indexing::{Indexing, Insertion};
use symbol_map::SymbolId;

/// A search graph.
///
/// Supports incremental rollout of game state topology and vertex
/// de-duplication with transposition tables. Limited support is provided for
/// deletion of components and compaction in memory after deletion.
///
/// - `T`: The type of game states. It is required to derive `Hash` and `Eq` to
///   so that it may be stored in a hashtable, where game states are looked up to
///   support de-duplication of game states. It is required to derive `Clone` to
///   accommodate a limitation of the `HashMap` interface.
/// - `S`: The type of graph vertex data.
/// - `A`: The type of graph edge data.
///
/// Vertices are addressed by content. To examine graph contents, obtain a node
/// handle with `find_node`. To modify graph contents, add new root vertices with
/// `add_node` and retrieve extant vertices with `find_node_mut`.
pub struct Graph<T: Hash + Eq + Clone, S, A> {
  /// Lookup table that maps from game states to `VertexId`.
  state_ids: symbol_map::indexing::HashIndexing<T, VertexId>,
  vertices: Vec<RawVertex<S>>, // Indexed by VertexId.
  arcs: Vec<RawEdge<A>>,       // Indexed by EdgeId.
}

impl<T, S, A> Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Creates an empty `Graph` with no vertices or edges.
  pub fn new() -> Self {
    Graph {
      state_ids: Default::default(),
      vertices: Vec::new(),
      arcs: Vec::new(),
    }
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex(&self, state: VertexId) -> &RawVertex<S> {
    &self.vertices[state.as_usize()]
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex_mut(&mut self, state: VertexId) -> &mut RawVertex<S> {
    &mut self.vertices[state.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc(&self, arc: EdgeId) -> &RawEdge<A> {
    &self.arcs[arc.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc_mut(&mut self, arc: EdgeId) -> &mut RawEdge<A> {
    &mut self.arcs[arc.as_usize()]
  }

  /// Returns the game state associated with `id`.
  fn get_state(&self, id: VertexId) -> Option<&T> {
    self.state_ids.get_symbol(&id).as_ref().map(|x| x.data())
  }

  /// Adds a new vertex with the given data, returning a mutable reference to it.
  ///
  /// This method does not add incoming or outgoing edges (expanded or
  /// not). That must be done by calling `add_arc` with the new vertex
  /// `VertexId`.
  fn add_raw_vertex(&mut self, data: S) -> &mut RawVertex<S> {
    self.vertices.push(RawVertex {
      data: data,
      parents: Vec::new(),
      children: Vec::new(),
    });
    self.vertices.last_mut().unwrap()
  }

  /// Adds a new edge with the given data, source, and target. Returns the
  /// internal ID for the new edge.
  fn add_raw_edge(&mut self, data: A, source: VertexId, target: VertexId) -> EdgeId {
    let arc_id = EdgeId(self.arcs.len());
    self.get_vertex_mut(source).children.push(arc_id);
    self.get_vertex_mut(target).parents.push(arc_id);
    self.arcs.push(RawEdge {
      data: data,
      source: source,
      target: target,
    });
    arc_id
  }

  /// Gets a node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn find_node<'s>(&'s self, state: &T) -> Option<nav::Node<'s, T, S, A>> {
    match self.state_ids.get(state) {
      Some(symbol) => Some(nav::Node::new(self, *symbol.id())),
      None => None,
    }
  }

  /// Gets a mutable node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn find_node_mut<'s>(&'s mut self, state: &T) -> Option<mutators::MutNode<'s, T, S, A>> {
    match self.state_ids.get(state).map(|s| s.id().clone()) {
      Some(id) => Some(mutators::MutNode::new(self, id)),
      None => None,
    }
  }

  /// Adds a vertex (with no parents or children) for the given game state and
  /// data and returns a mutable handle for it.
  ///
  /// If `state` is already known, returns a mutable handle to that state,
  /// ignoring the `data` parameter. As a result, this method is guaranteed to
  /// return a handle for a root vertex only when `state` is a novel game
  /// state.
  pub fn add_node<'s>(&'s mut self, state: T, data: S) -> mutators::MutNode<'s, T, S, A> {
    let node_id = match self.state_ids.get_or_insert(state).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        self.add_raw_vertex(data);
        id
      }
    };
    mutators::MutNode::new(self, node_id)
  }

  /// Adds an edge from the vertex with state data `source` to the vertex with
  /// state data `dest`. If vertices are not found for `source` or `dest`,
  /// they are added, with the data provided by `source_data` and `dest_data`
  /// callbacks.
  ///
  /// The edge that is created will have the data `edge_data`. Returns a
  /// mutable edge handle for that edge.
  pub fn add_edge<'s, F, G>(
    &'s mut self,
    source: T,
    source_data: F,
    dest: T,
    dest_data: G,
    edge_data: A,
  ) -> mutators::MutEdge<'s, T, S, A>
  where
    F: for<'b> FnOnce(nav::Node<'b, T, S, A>) -> S,
    G: for<'b> FnOnce(nav::Node<'b, T, S, A>) -> S,
  {
    let source_id = match self.state_ids.get_or_insert(source).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = source_data(nav::Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let dest_id = match self.state_ids.get_or_insert(dest).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = dest_data(nav::Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let edge_id = self.add_raw_edge(edge_data, source_id, dest_id);
    mutators::MutEdge::new(self, edge_id)
  }

  /// Returns the number of vertices in the graph.
  pub fn vertex_count(&self) -> usize {
    // TODO: This is actually the number of vertices we have allocated.
    self.vertices.len()
  }

  /// Returns the number of edges in the graph.
  pub fn edge_count(&self) -> usize {
    // TODO: This is actually the number of edges we have allocated.
    self.arcs.len()
  }
}

#[cfg(test)]
mod test {
  use crossbeam_utils::thread;
  use std::sync::Arc;

  type Graph = crate::Graph<&'static str, &'static str, &'static str>;

  #[test]
  fn send_to_thread_safe_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let graph = Arc::new(g);
    thread::scope(move |s| {
      let g = graph.clone();
      let t1 = s.spawn(move |_| g.find_node(&"root").map(|n| n.get_id()));
      let g = graph.clone();
      let t2 = s.spawn(move |_| g.find_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }

  #[test]
  fn sync_to_thread_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let g = &g;
    thread::scope(|s| {
      let t1 = s.spawn(move |_| g.find_node(&"root").map(|n| n.get_id()));
      let t2 = s.spawn(move |_| g.find_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }
}
<|endoftext|>


<commit_before>#![feature(vec_push_all, box_raw, heap_api)]

#[cfg(linux)] extern crate libc;
#[cfg(linux)] extern crate alsa_sys;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate winmm as winmm_sys;

// TODO: use Cow<str> instead of String?
// TODO: get rid of unused error types
#[derive(Debug)]
pub enum Error {
    Warning(&'static str),        // A non-critical error.
    DebugWarning,                 // A non-critical error which might be useful for debugging.
    Unspecified,                  // The default, unspecified error type.
    NoDevicesFound(&'static str), // No devices found on system.
    InvalidDevice,                // An invalid device ID was specified.
    MemoryError,                  // An error occured during memory allocation.
    InvalidParameter(String),     // An invalid parameter was specified to a function.
    InvalidUse,                   // The function was called incorrectly.
    DriverError(&'static str),    // A system driver error occured.
    SystemError,                  // A system error occured.
    ThreadError(&'static str)     // A thread error occured.
}

pub type Result<T> = std::result::Result<T, Error>;

pub trait MidiApi {
    fn get_port_count(&self) -> u32;
    fn get_port_name(&self, port_number: u32 /*= 0*/) -> Result<String>;
    fn open_port(&mut self, port_number: u32 /*= 0*/, port_name: &str /*= "RtMidi"*/) -> Result<()>;
    //fn open_virtual_port(port_name: &str/*= "RtMidi"*/);
    fn close_port(&mut self);
    fn is_port_open(&self) -> bool;
}

// TODO: create helper function that creates an instance (trait object)
//       of the correct system API

pub trait MidiInApi : MidiApi {
    fn new(client_name: &str /*= "RtMidi Input Client"*/, queue_size_limit: usize /*= 100*/) -> Result<Self>;
    fn set_callback<F>(&mut self, callback: F) -> Result<()> where F: FnMut(f64, &Vec<u8>)+Send;
    fn cancel_callback(&mut self) -> Result<()>;
    fn ignore_types(&mut self, sysex: bool /*= true*/, time: bool /*= true*/, active_sense: bool /*= true*/);

    /// Fill the user-provided vector with the data bytes for the next available
    /// MIDI message in  the input queue and return the event delta-time in seconds.
    ///
    /// This function returns immediately whether a new message is
    /// available or not.  A valid message is indicated by a non-zero
    /// vector size.  An exception is thrown if an error occurs during
    /// message retrieval or an input connection was not previously
    /// established.
    fn get_message(&mut self, message: &mut Vec<u8>) -> f64;
}

/*pub struct MidiIn<Impl> where Impl: MidiInApi {
    inputData: MidiInData
}*/

// A MIDI structure used internally by the class to store incoming
// messages.  Each message represents one and only one MIDI message.
#[derive(Debug, Clone)]
struct MidiMessage {
    bytes: Vec<u8>,
    timestamp: f64
}

impl MidiMessage {
    // TODO: probably not needed
    pub fn new() -> MidiMessage {
        MidiMessage {
            bytes: vec![],
            timestamp: 0.0
        }
    }
}

#[derive(Debug)]
struct MidiQueue {
    front: usize,
    back: usize,
    size: usize,
    ring: Box<[MidiMessage]>
}

impl MidiQueue {
    pub fn new(ring_size: usize) -> MidiQueue {
        MidiQueue {
            front: 0,
            back: 0,
            size: 0,
            ring: unsafe {
                let mut vec = Vec::with_capacity(ring_size);
                vec.set_len(ring_size);
                vec.into_boxed_slice()
            }
        }
    }
}

pub trait MidiOutApi : MidiApi {
    fn new(client_name: &str /*= "RtMidi Output Client"*/) -> Result<Self>;
    fn send_message(&mut self, message: &[u8]) -> Result<()>;
}

// TODO: allow feature selection (ALSA and/or Jack)
#[cfg(linux)]
pub mod alsa;

#[cfg(windows)]
pub mod winmm;<commit_msg>Fixed compilation on Linux<commit_after>#![feature(vec_push_all, box_raw, heap_api)]

#[cfg(target_os="linux")] extern crate libc;
#[cfg(target_os="linux")] extern crate alsa_sys;
#[cfg(target_os="windows")] extern crate winapi;
#[cfg(target_os="windows")] extern crate winmm as winmm_sys;

// TODO: use Cow<str> instead of String?
// TODO: get rid of unused error types
#[derive(Debug)]
pub enum Error {
    Warning(&'static str),        // A non-critical error.
    DebugWarning,                 // A non-critical error which might be useful for debugging.
    Unspecified,                  // The default, unspecified error type.
    NoDevicesFound(&'static str), // No devices found on system.
    InvalidDevice,                // An invalid device ID was specified.
    MemoryError,                  // An error occured during memory allocation.
    InvalidParameter(String),     // An invalid parameter was specified to a function.
    InvalidUse,                   // The function was called incorrectly.
    DriverError(&'static str),    // A system driver error occured.
    SystemError,                  // A system error occured.
    ThreadError(&'static str)     // A thread error occured.
}

pub type Result<T> = std::result::Result<T, Error>;

pub trait MidiApi {
    fn get_port_count(&self) -> u32;
    fn get_port_name(&self, port_number: u32 /*= 0*/) -> Result<String>;
    fn open_port(&mut self, port_number: u32 /*= 0*/, port_name: &str /*= "RtMidi"*/) -> Result<()>;
    //fn open_virtual_port(port_name: &str/*= "RtMidi"*/);
    fn close_port(&mut self);
    fn is_port_open(&self) -> bool;
}

// TODO: create helper function that creates an instance (trait object)
//       of the correct system API

pub trait MidiInApi : MidiApi {
    fn new(client_name: &str /*= "RtMidi Input Client"*/, queue_size_limit: usize /*= 100*/) -> Result<Self>;
    fn set_callback<F>(&mut self, callback: F) -> Result<()> where F: FnMut(f64, &Vec<u8>)+Send;
    fn cancel_callback(&mut self) -> Result<()>;
    fn ignore_types(&mut self, sysex: bool /*= true*/, time: bool /*= true*/, active_sense: bool /*= true*/);

    /// Fill the user-provided vector with the data bytes for the next available
    /// MIDI message in  the input queue and return the event delta-time in seconds.
    ///
    /// This function returns immediately whether a new message is
    /// available or not.  A valid message is indicated by a non-zero
    /// vector size.  An exception is thrown if an error occurs during
    /// message retrieval or an input connection was not previously
    /// established.
    fn get_message(&mut self, message: &mut Vec<u8>) -> f64;
}

/*pub struct MidiIn<Impl> where Impl: MidiInApi {
    inputData: MidiInData
}*/

// A MIDI structure used internally by the class to store incoming
// messages.  Each message represents one and only one MIDI message.
#[derive(Debug, Clone)]
struct MidiMessage {
    bytes: Vec<u8>,
    timestamp: f64
}

impl MidiMessage {
    // TODO: probably not needed
    pub fn new() -> MidiMessage {
        MidiMessage {
            bytes: vec![],
            timestamp: 0.0
        }
    }
}

#[derive(Debug)]
struct MidiQueue {
    front: usize,
    back: usize,
    size: usize,
    ring: Box<[MidiMessage]>
}

impl MidiQueue {
    pub fn new(ring_size: usize) -> MidiQueue {
        MidiQueue {
            front: 0,
            back: 0,
            size: 0,
            ring: unsafe {
                let mut vec = Vec::with_capacity(ring_size);
                vec.set_len(ring_size);
                vec.into_boxed_slice()
            }
        }
    }
}

pub trait MidiOutApi : MidiApi {
    fn new(client_name: &str /*= "RtMidi Output Client"*/) -> Result<Self>;
    fn send_message(&mut self, message: &[u8]) -> Result<()>;
}

// TODO: allow feature selection (ALSA and/or Jack)
#[cfg(target_os="linux")]
pub mod alsa;

#[cfg(target_os="windows")]
pub mod winmm;<|endoftext|>


<commit_before>extern crate base64;
extern crate crypto_mac;
extern crate digest;
extern crate hmac;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate sha2;

use serde::de::DeserializeOwned;
use serde::Serialize;

use digest::generic_array::ArrayLength;
use digest::*;
use hmac::{Hmac, Mac};

pub use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
pub use crate::claims::Claims;
pub use crate::claims::RegisteredClaims;
pub use crate::error::Error;
pub use crate::header::Header;

pub mod algorithm;
pub mod claims;
pub mod error;
pub mod header;
pub mod token;

const SEPARATOR: &'static str = ".";

pub trait Component: Sized {
    fn from_base64<Input: ?Sized + AsRef<[u8]>>(raw: &Input) -> Result<Self, Error>;
    fn to_base64(&self) -> Result<String, Error>;
}

impl<T> Component for T
where
    T: Serialize + DeserializeOwned + Sized,
{
    /// Parse from a string.
    fn from_base64<Input: ?Sized + AsRef<[u8]>>(raw: &Input) -> Result<T, Error> {
        let json_bytes = base64::decode_config(raw, base64::URL_SAFE_NO_PAD)?;
        Ok(serde_json::from_slice(&json_bytes)?)
    }

    /// Encode to a string.
    fn to_base64(&self) -> Result<String, Error> {
        let json_bytes = serde_json::to_vec(&self)?;
        let encoded_json_bytes = base64::encode_config(&json_bytes, base64::URL_SAFE_NO_PAD);
        Ok(encoded_json_bytes)
    }
}

fn split_components(token: &str) -> Result<[&str; 3], Error> {
    let mut components = token.split(SEPARATOR);
    let header = components.next().ok_or(Error::Format)?;
    let claims = components.next().ok_or(Error::Format)?;
    let signature = components.next().ok_or(Error::Format)?;

    Ok([header, claims, signature])
}
<commit_msg>Add new token type<commit_after>extern crate base64;
extern crate crypto_mac;
extern crate digest;
extern crate hmac;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate sha2;

use serde::de::DeserializeOwned;
use serde::Serialize;

use digest::generic_array::ArrayLength;
use digest::*;
use hmac::{Hmac, Mac};

pub use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
pub use crate::claims::Claims;
pub use crate::claims::RegisteredClaims;
pub use crate::error::Error;
pub use crate::header::Header;

pub mod algorithm;
pub mod claims;
pub mod error;
pub mod header;
pub mod token;

const SEPARATOR: &'static str = ".";

pub struct Token<H, C, S> {
    header: H,
    claims: C,
    signature: S,
}

pub trait Component: Sized {
    fn from_base64<Input: ?Sized + AsRef<[u8]>>(raw: &Input) -> Result<Self, Error>;
    fn to_base64(&self) -> Result<String, Error>;
}

impl<T> Component for T
where
    T: Serialize + DeserializeOwned + Sized,
{
    /// Parse from a string.
    fn from_base64<Input: ?Sized + AsRef<[u8]>>(raw: &Input) -> Result<T, Error> {
        let json_bytes = base64::decode_config(raw, base64::URL_SAFE_NO_PAD)?;
        Ok(serde_json::from_slice(&json_bytes)?)
    }

    /// Encode to a string.
    fn to_base64(&self) -> Result<String, Error> {
        let json_bytes = serde_json::to_vec(&self)?;
        let encoded_json_bytes = base64::encode_config(&json_bytes, base64::URL_SAFE_NO_PAD);
        Ok(encoded_json_bytes)
    }
}

fn split_components(token: &str) -> Result<[&str; 3], Error> {
    let mut components = token.split(SEPARATOR);
    let header = components.next().ok_or(Error::Format)?;
    let claims = components.next().ok_or(Error::Format)?;
    let signature = components.next().ok_or(Error::Format)?;

    Ok([header, claims, signature])
}
<|endoftext|>


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

#![cfg_attr(feature = "unstable", feature(fn_must_use))]
#![cfg_attr(not(test), no_std)]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all Typed* structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = TypedTransform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!
//! Components are accessed in their scalar form by default for convenience, and most
//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
//! For example:
//!
//! ```rust
//! # use euclid::*;
//! # pub struct WorldSpace;
//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! let p = WorldPoint::new(0.0, 1.0, 1.0);
//! // p.x is an f32.
//! println!("p.x = {:?} ", p.x);
//! // p.x is a Length<f32, WorldSpace>.
//! println!("p.x_typed() = {:?} ", p.x_typed());
//! // Length::get returns the scalar value (f32).
//! assert_eq!(p.x, p.x_typed().get());
//! ```

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

#[cfg(feature = "mint")]
pub extern crate mint;
#[macro_use]
extern crate euclid_macros;
extern crate num_traits;
#[cfg(test)]
extern crate rand;
#[cfg(test)]
use std as core;

pub use length::Length;
pub use scale::TypedScale;
pub use transform2d::{Transform2D, TypedTransform2D};
pub use transform3d::{Transform3D, TypedTransform3D};
pub use point::{Point2D, Point3D, TypedPoint2D, TypedPoint3D, point2, point3};
pub use vector::{TypedVector2D, TypedVector3D, Vector2D, Vector3D, vec2, vec3};
pub use vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
pub use homogen::HomogeneousVector;

pub use rect::{rect, Rect, TypedRect};
pub use translation::{TypedTranslation2D, TypedTranslation3D};
pub use rotation::{Angle, Rotation2D, Rotation3D, TypedRotation2D, TypedRotation3D};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
pub use size::{Size2D, TypedSize2D, size2};
pub use trig::Trig;

#[macro_use]
mod macros;

pub mod approxeq;
mod homogen;
pub mod num;
mod length;
mod point;
mod rect;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod transform2d;
mod transform3d;
mod translation;
mod trig;
mod vector;

/// The default unit.
#[derive(Clone, Copy)]
pub struct UnknownUnit;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix2D<T> = Transform2D<T>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix2D<T, Src, Dst> = TypedTransform2D<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix4D<T> = Transform3D<T>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix4D<T, Src, Dst> = TypedTransform3D<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type ScaleFactor<T, Src, Dst> = TypedScale<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub use Angle as Radians;
<commit_msg>Auto merge of #318 - servo:fitzgen-patch-1, r=nical<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(feature = "unstable", feature(fn_must_use))]
#![cfg_attr(not(test), no_std)]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all Typed* structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = TypedTransform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!
//! Components are accessed in their scalar form by default for convenience, and most
//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
//! For example:
//!
//! ```rust
//! # use euclid::*;
//! # pub struct WorldSpace;
//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! let p = WorldPoint::new(0.0, 1.0, 1.0);
//! // p.x is an f32.
//! println!("p.x = {:?} ", p.x);
//! // p.x is a Length<f32, WorldSpace>.
//! println!("p.x_typed() = {:?} ", p.x_typed());
//! // Length::get returns the scalar value (f32).
//! assert_eq!(p.x, p.x_typed().get());
//! ```

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

#[cfg(feature = "mint")]
pub extern crate mint;
#[macro_use]
extern crate euclid_macros;
extern crate num_traits;
#[cfg(test)]
extern crate rand;
#[cfg(test)]
use std as core;

pub use length::Length;
pub use scale::TypedScale;
pub use transform2d::{Transform2D, TypedTransform2D};
pub use transform3d::{Transform3D, TypedTransform3D};
pub use point::{Point2D, Point3D, TypedPoint2D, TypedPoint3D, point2, point3};
pub use vector::{TypedVector2D, TypedVector3D, Vector2D, Vector3D, vec2, vec3};
pub use vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
pub use homogen::HomogeneousVector;

pub use rect::{rect, Rect, TypedRect};
pub use translation::{TypedTranslation2D, TypedTranslation3D};
pub use rotation::{Angle, Rotation2D, Rotation3D, TypedRotation2D, TypedRotation3D};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
pub use size::{Size2D, TypedSize2D, size2};
pub use trig::Trig;

#[macro_use]
mod macros;

pub mod approxeq;
mod homogen;
pub mod num;
mod length;
mod point;
mod rect;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod transform2d;
mod transform3d;
mod translation;
mod trig;
mod vector;

/// The default unit.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnknownUnit;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix2D<T> = Transform2D<T>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix2D<T, Src, Dst> = TypedTransform2D<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix4D<T> = Transform3D<T>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix4D<T, Src, Dst> = TypedTransform3D<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type ScaleFactor<T, Src, Dst> = TypedScale<T, Src, Dst>;

/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub use Angle as Radians;
<|endoftext|>


<commit_before>
mod error;
mod pair;
mod parser;
mod value;
mod token;
mod scanner;

pub use error::*;
pub use pair::*;
pub use parser::*;
pub use value::*;
pub use token::*;
pub use scanner::*;

<commit_msg>start parse_file<commit_after>
mod error;
mod pair;
mod parser;
mod value;
mod token;
mod scanner;

pub use error::*;
pub use pair::*;
pub use parser::*;
pub use value::*;
pub use token::*;
pub use scanner::*;

use std::path::Path;
use std::fs::File;
use std::io::Read;

pub fn parse_file(filename: &str) -> Result<Vec<Token>, NcclError> {
    if let Ok(mut file) = File::open(Path::new(filename)) {
        let mut data = String::new();
        file.read_to_string(&mut data).unwrap();
        Scanner::new(data).scan_tokens()
    } else {
        Err(NcclError::new(ErrorKind::FileError, "Could not find file.", 0))
    }
}

<|endoftext|>


<commit_before>// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
// Licensed under the MIT license
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
// notice may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(feature = "docsrs", feature(doc_auto_cfg))]
#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
#![cfg_attr(feature = "derive", doc = include_str!("../README.md"))]
//! <https://github.com/clap-rs/clap>
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    unused_allocation,
    trivial_numeric_casts
)]
#![forbid(unsafe_code)]
// TODO: https://github.com/rust-lang/rust-clippy/issues/7290
#![allow(clippy::single_component_path_imports)]
#![allow(clippy::branches_sharing_code)]

#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");

#[cfg(feature = "color")]
pub use crate::util::color::ColorChoice;
pub use crate::{
    build::{
        App, AppFlags, AppSettings, Arg, ArgFlags, ArgGroup, ArgSettings, PossibleValue, ValueHint,
    },
    parse::errors::{Error, ErrorKind, Result},
    parse::{ArgMatches, Indices, OsValues, Values},
};

pub use crate::derive::{ArgEnum, Args, FromArgMatches, IntoApp, Parser, Subcommand};

#[cfg(feature = "yaml")]
#[doc(hidden)]
#[deprecated(
    since = "3.0.0",
    note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
)]
pub use yaml_rust::YamlLoader;

#[cfg(feature = "derive")]
#[doc(hidden)]
pub use clap_derive::{self, *};

/// Deprecated, replaced with [`Parser`]
#[deprecated(since = "3.0.0", note = "Replaced with `Parser`")]
pub use Parser as StructOpt;

#[cfg(any(feature = "derive", feature = "cargo"))]
#[doc(hidden)]
pub use lazy_static;

#[macro_use]
#[allow(missing_docs)]
mod macros;

mod derive;

#[cfg(feature = "regex")]
pub use crate::build::arg::RegexRef;

mod build;
mod mkeymap;
mod output;
mod parse;
mod util;

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";

/// Deprecated, replaced with [`App`]
#[deprecated(since = "3.0.0", note = "Replaced with `App`")]
#[derive(Debug, Copy, Clone)]
pub struct SubCommand {}

#[allow(deprecated)]
impl SubCommand {
    /// Deprecated, replaced with [`App::new`]
    #[deprecated(since = "3.0.0", note = "Replaced with `App::new`")]
    pub fn with_name<'help>(name: &str) -> App<'help> {
        App::new(name)
    }

    /// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case?
    #[cfg(feature = "yaml")]
    #[deprecated(
        since = "3.0.0",
        note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
    )]
    pub fn from_yaml(yaml: &yaml_rust::Yaml) -> App {
        #![allow(deprecated)]
        App::from_yaml(yaml)
    }
}
<commit_msg>docs: Clarify deprecation message for `SubCommand`<commit_after>// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
// Licensed under the MIT license
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
// notice may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(feature = "docsrs", feature(doc_auto_cfg))]
#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
#![cfg_attr(feature = "derive", doc = include_str!("../README.md"))]
//! <https://github.com/clap-rs/clap>
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    unused_allocation,
    trivial_numeric_casts
)]
#![forbid(unsafe_code)]
// TODO: https://github.com/rust-lang/rust-clippy/issues/7290
#![allow(clippy::single_component_path_imports)]
#![allow(clippy::branches_sharing_code)]

#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");

#[cfg(feature = "color")]
pub use crate::util::color::ColorChoice;
pub use crate::{
    build::{
        App, AppFlags, AppSettings, Arg, ArgFlags, ArgGroup, ArgSettings, PossibleValue, ValueHint,
    },
    parse::errors::{Error, ErrorKind, Result},
    parse::{ArgMatches, Indices, OsValues, Values},
};

pub use crate::derive::{ArgEnum, Args, FromArgMatches, IntoApp, Parser, Subcommand};

#[cfg(feature = "yaml")]
#[doc(hidden)]
#[deprecated(
    since = "3.0.0",
    note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
)]
pub use yaml_rust::YamlLoader;

#[cfg(feature = "derive")]
#[doc(hidden)]
pub use clap_derive::{self, *};

/// Deprecated, replaced with [`Parser`]
#[deprecated(since = "3.0.0", note = "Replaced with `Parser`")]
pub use Parser as StructOpt;

#[cfg(any(feature = "derive", feature = "cargo"))]
#[doc(hidden)]
pub use lazy_static;

#[macro_use]
#[allow(missing_docs)]
mod macros;

mod derive;

#[cfg(feature = "regex")]
pub use crate::build::arg::RegexRef;

mod build;
mod mkeymap;
mod output;
mod parse;
mod util;

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";

/// Deprecated, replaced with [`App::new`], unless you were looking for [Subcommand]
#[deprecated(
    since = "3.0.0",
    note = "Replaced with `App::new` unless you intended the `Subcommand` trait"
)]
#[derive(Debug, Copy, Clone)]
pub struct SubCommand {}

#[allow(deprecated)]
impl SubCommand {
    /// Deprecated, replaced with [`App::new`].
    /// Did you mean Subcommand (lower-case c)?
    #[deprecated(since = "3.0.0", note = "Replaced with `App::new`")]
    pub fn with_name<'help>(name: &str) -> App<'help> {
        App::new(name)
    }

    /// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case?
    #[cfg(feature = "yaml")]
    #[deprecated(
        since = "3.0.0",
        note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
    )]
    pub fn from_yaml(yaml: &yaml_rust::Yaml) -> App {
        #![allow(deprecated)]
        App::from_yaml(yaml)
    }
}
<|endoftext|>