<commit_before>// Copyright 2016 Vincent Vigneron. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under 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.

extern crate itertools;

use std::collections::{HashSet,HashMap};
use std::fmt;                          // Formatter, format!, Display, Debug, write!
use std::error;
use std::result;

/// The `DFAError` type.
#[derive(Debug)]
pub enum DFAError {
    /// The transition from state `usize` with symbol `char` is defined twice.
    DuplicatedTransition(char,usize),
    /// No final state is specified.
    MissingFinalStates,
    /// No starting state is specified.
    MissingStartingState,
}

impl fmt::Display for DFAError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DFAError::DuplicatedTransition(symb,state) => write!(f, "Duplicated transition ('{}',{}).", symb, state),
            DFAError::MissingFinalStates => write!(f, "Missing final states."),
            DFAError::MissingStartingState => write!(f, "Missing starting state."),
        }
    }
}

impl error::Error for DFAError {
    fn description(&self) -> &str {
        match *self {
            DFAError::DuplicatedTransition(_,_) => "Duplicated transition.",
            DFAError::MissingFinalStates => "Missing final states.",
            DFAError::MissingStartingState => "Missing starting state.",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

/// The type `DFA` represents a Deterministic Finite Automaton. The transitions
/// of the automatan are stored in a hashtable.
#[derive(Debug)]
pub struct DFA {
    transitions : HashMap<(char,usize),usize>,
    start       : usize,
    finals      : HashSet<usize>,
}
/// a
struct SrcState( u64 );
/// a
struct DstState( u64 );
/// a
struct Symbol( char );

/// The `DFABuilder` follows the builder pattern and allows to create a Deterministic
/// Finite Automaton. The builder is moved at each call so it is necessary to bind
/// to a new variable the return value for each function of the builder.
///
/// # Errors
///
/// Return an error if the starting state is not specified.
///
/// Return an error if the final states are not specified.
///
/// # Examples
///
/// ```
/// extern crate automata;
///
/// use automata::dfa::core::*;
/// use std::error::Error;
///
/// fn main() {
///     // (abc)*
///     let dfa = DFABuilder::new()
///         .add_start(0)
///         .add_final(0)
///         .add_transition('a', 0, 1)
///         .add_transition('b', 1, 2)
///         .add_transition('c', 2, 0)
///         .finalize();
/// }
/// ```
///
/// ```
/// extern crate automata;
///
/// use automata::dfa::core::*;
/// use std::error::Error;
///
/// fn main() {
///     let dfa = DFABuilder::new()
///         .add_start(4)
///         .add_transition('t', 0, 1)
///         .finalize();
///     match dfa {
///         Err(DFAError::MissingFinalStates) => assert!(true),
///         _ => assert!(false),
///     }
/// }
/// ```
///
/// ```
/// extern crate automata;
///
/// use automata::dfa::core::*;
/// use std::error::Error;
///
/// fn main() {
///     let dfa = DFABuilder::new()
///         .add_start(4)
///         .add_transition('t', 0, 1)
///         .add_transition('t', 0, 2)
///         .finalize();
///     match dfa {
///         Err(DFAError::DuplicatedTransition(symb,src)) => assert!((symb,src)==('t',0)),
///         _ => assert!(false),
///     }
/// }
/// ```
///
/// ```
/// extern crate automata;
///
/// use automata::dfa::core::*;
/// use std::error::Error;
///
/// fn main() {
///     let dfa = DFABuilder::new()
///         .add_final(4)
///         .add_transition('t', 0, 1)
///         .finalize();
///     match dfa {
///         Err(DFAError::MissingStartingState) => assert!(true),
///         _ => assert!(false),
///     }
/// }
/// ```
///
#[derive(Debug)]
pub struct DFABuilder {
    transitions : HashMap<(char,usize),usize>,
    start       : Option<usize>,
    finals      : HashSet<usize>,
}

/// Alias for result::Result<T,DFAError>.
pub type Result<T> = result::Result<T,DFAError>;

/// DFABuilding is the trait assiociated to the DFABuilder type. Each DFABuilder
/// should implement DFABuilding trait.
///
/// DFABuilder can generate some errors during the building stage. For instance,
/// one could try to insert a transition with two different destination states.
///
/// #Errors
///
/// If self contains a DFAerror then each function should transfer this error.
pub trait DFABuilding {
    /// Add a starting state to the DFA.
    ///
    /// # Errors
    ///
    /// In the futur will return a DFAError::DuplicatedStartingState if
    /// two starting states are added.
    fn add_start(self, state: usize) -> Result<DFABuilder>;

    /// Add a final state to the DFA.
    fn add_final(self, state: usize) -> Result<DFABuilder>;

    /// Add a transition to the DFA.
    ///
    /// # Errors
    ///
    /// Return a DFAError::DuplicatedTransition(symb,src) if a transtion
    /// with the same symb and src has already been inserted, even if
    /// the destination state is the same.
    fn add_transition(self, symb: char, src: usize, dest: usize) -> Result<DFABuilder>;

    /// Finalize the building of the DFA.
    ///
    /// # Errors
    ///
    /// Return a DFAError::MissingStartingState if no starting state is specified.
    ///
    /// Return a DFAError::MissingFinalStates if no final state is specified.
    fn finalize(self) -> Result<DFA>;
}

impl DFABuilder {
    /// Creates a new DFABuilder.
    pub fn new() -> Result<DFABuilder> {
        Ok(DFABuilder{transitions: HashMap::new(), start: None, finals: HashSet::new()})
    }
}

impl DFABuilding for DFABuilder {
    fn add_start(self, state: usize) -> Result<DFABuilder> {
        Ok(self).add_start(state)
    }

    fn add_final(self, state: usize) -> Result<DFABuilder> {
        Ok(self).add_final(state)
    }

    fn add_transition(self, symb: char, src: usize, dest: usize) -> Result<DFABuilder> {
        Ok(self).add_transition(symb,src,dest)
    }

    fn finalize(self) -> Result<DFA> {
        Ok(self).finalize()
    }
}

/// Implementing DFABuilding trait for Result<DFABuilder> allows
/// to chain the return value of the DFABuilder instead of unwrapping them
/// at each stage of the building process.
impl DFABuilding for Result<DFABuilder> {
    fn add_start(self, state: usize) -> Result<DFABuilder> {
        self.map(|mut dfa| {
            dfa.start = Some(state);
            dfa
        })
    }

    fn add_final(self, state: usize) -> Result<DFABuilder> {
        self.map(|mut dfa| {
            dfa.finals.insert(state);
            dfa
        })
    }

    fn add_transition(self, symb: char, src: usize, dest: usize) -> Result<DFABuilder> {
        self.and_then(|mut dfa| {
            if dfa.transitions.insert((symb,src), dest).is_some() {
                return Err(DFAError::DuplicatedTransition(symb,src));
            }
            Ok(dfa)
        })
    }

    fn finalize(self) -> Result<DFA> {
        self.and_then(|dfa| {
            if dfa.start.is_none() {
                Err(DFAError::MissingStartingState)
            } else if dfa.finals.is_empty() {
                Err(DFAError::MissingFinalStates)
            } else {
                Ok(DFA{transitions: dfa.transitions, start: dfa.start.unwrap(), finals: dfa.finals})
            }
        })
    }
}

impl DFA {
    /// Test if an input string is a word of the language defined by the DFA.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate automata;
    ///
    /// use automata::dfa::core::*;
    /// use std::error::Error;
    ///
    /// fn main() {
    ///     // (abc)*
    ///     let dfa = DFABuilder::new()
    ///         .add_start(0)
    ///         .add_final(0)
    ///         .add_transition('a', 0, 1)
    ///         .add_transition('b', 1, 2)
    ///         .add_transition('c', 2, 0)
    ///         .finalize();
    ///     match dfa {
    ///         Ok(dfa) => {
    ///            assert!(dfa.test("abc"));
    ///            assert!(dfa.test(""));
    ///            assert!(!dfa.test("a"));
    ///            assert!(!dfa.test("ab"));
    ///            assert!(!dfa.test("abca"));
    ///            assert!(!dfa.test("abcab"));
    ///            assert!(dfa.test("abcabcabc"));
    ///         },
    ///         Err(e) => println!("{}", e),
    ///     }
    /// }
    /// ```
    pub fn test(&self, input: &str) -> bool {
        let f = input
            .chars()
            .fold(Some(self.start), |state,c| {
                match state {
                    Some(n) => self.transitions.get(&(c,n)).map(|v| *v),
                    None => None,
                }
            });
        match f {
            Some(n) => self.finals.contains(&n),
            None => false
        }
    }
}

impl fmt::Display for DFA {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "START: {}", self.start));
        try!(writeln!(f, "FINALS:"));
        for fi in self.finals.iter() {
            try!(writeln!(f,"  {}", fi));
        }
        try!(writeln!(f, "TRANSITIONS:"));
        for (tr,d) in self.transitions.iter() {
            let (c,s) = *tr;
            try!(writeln!(f, "  ({},{}) => {}", c, s, d));
        }
        write!(f, "")
    }
}

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

    #[test]
    fn test_dfa() {
        let dfa = DFABuilder::new()
            .add_start(0)
            .add_final(3)
            .add_transition('a', 0, 1)
            .add_transition('c', 0, 3)
            .add_transition('b', 1, 2)
            .add_transition('a', 2, 1)
            .add_transition('c', 2, 3)
            .finalize()
            .unwrap();
        let samples =
            vec![("ababac", false),
                 ("ababc", true),
                 ("", false),
                 ("abc", true),
                 ("c", true),
                 ("ac", false),
                 ("ababababababababababababababababababababc", true),];

        for (input,expected_result) in samples {
            assert!(dfa.test(input) == expected_result, "input false for: \"{}\"", input);
        }
    }

    #[test]
    fn test_dfa_builder() {
        let _dfa = DFABuilder::new()
            .add_start(0)
            .add_final(3)
            .add_transition('a', 0, 1)
            .add_transition('c', 0, 3)
            .add_transition('b', 1, 2)
            .add_transition('a', 2, 1)
            .add_transition('c', 2, 3)
            .finalize()
            .unwrap();
    }

    #[test]
    fn test_dfa_builder_duplicated_transition() {
        let dfa = DFABuilder::new()
            .add_start(0)
            .add_final(3)
            .add_transition('a', 0, 1)
            .add_transition('c', 0, 3)
            .add_transition('b', 1, 2)
            .add_transition('a', 2, 1)
            .add_transition('c', 2, 3)
            .add_transition('a', 0, 2)
            .finalize();
        match dfa {
            Err(DFAError::DuplicatedTransition(sy,sr)) => assert!((sy,sr) == ('a',0)),
            _ => assert!(false, "DuplicatedTransition expected."),
        }
    }

    #[test]
    fn test_dfa_builder_missing_start() {
        let dfa = DFABuilder::new()
            .add_final(3)
            .add_transition('a', 0, 1)
            .finalize();
        match dfa {
            Err(DFAError::MissingStartingState) => assert!(true),
            _ => assert!(false, "MissingStartingState expected."),
        }
    }

    #[test]
    fn test_dfa_builder_missing_finals() {
        let dfa = DFABuilder::new()
            .add_start(0)
            .add_transition('a', 0, 1)
            .finalize();
        match dfa {
            Err(DFAError::MissingFinalStates) => assert!(true),
            _ => assert!(false, "MissingFinalStates expected."),
        }
    }
}
<commit_msg>delete new structs<commit_after>// Copyright 2016 Vincent Vigneron. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under 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.

extern crate itertools;

use std::collections::{HashSet,HashMap};
use std::fmt;                          // Formatter, format!, Display, Debug, write!
use std::error;
use std::result;

/// The `DFAError` type.
#[derive(Debug)]
pub enum DFAError {
    /// The transition from state `usize` with symbol `char` is defined twice.
    DuplicatedTransition(char,usize),
    /// No final state is specified.
    MissingFinalStates,
    /// No starting state is specified.
    MissingStartingState,
}

impl fmt::Display for DFAError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DFAError::DuplicatedTransition(symb,state) => write!(f, "Duplicated transition ('{}',{}).", symb, state),
            DFAError::MissingFinalStates => write!(f, "Missing final states."),
            DFAError::MissingStartingState => write!(f, "Missing starting state."),
        }
    }
}

impl error::Error for DFAError {
    fn description(&self) -> &str {
        match *self {
            DFAError::DuplicatedTransition(_,_) => "Duplicated transition.",
            DFAError::MissingFinalStates => "Missing final states.",
            DFAError::MissingStartingState => "Missing starting state.",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

/// The type `DFA` represents a Deterministic Finite Automaton. The transitions
/// of the automatan are stored in a hashtable.
#[derive(Debug)]
pub struct DFA {
    transitions : HashMap<(char,usize),usize>,
    start       : usize,
    finals      : HashSet<usize>,
}
/*
/// a
struct SrcState( u64 );
/// a
struct DstState( u64 );
/// a
struct Symbol( char );
*/

/// The `DFABuilder` follows the builder pattern and allows to create a Deterministic
/// Finite Automaton. The builder is moved at each call so it is necessary to bind
/// to a new variable the return value for each function of the builder.
///
/// # Errors
///
/// Return an error if the starting state is not specified.
///
/// Return an error if the final states are not specified.
///
/// # Examples
///
/// ```
/// extern crate automata;
///
/// use automata::dfa::core::*;
/// use std::error::Error;
///
/// fn main() {
///     // (abc)*
///     let dfa = DFABuilder::new()
///         .add_start(0)
///         .add_final(0)
///         .add_transition('a', 0, 1)
///         .add_transition('b', 1, 2)
///         .add_transition('c', 2, 0)
///         .finalize();
/// }
/// ```
///
/// ```
/// extern crate automata;
///
/// use automata::dfa::core::*;
/// use std::error::Error;
///
/// fn main() {
///     let dfa = DFABuilder::new()
///         .add_start(4)
///         .add_transition('t', 0, 1)
///         .finalize();
///     match dfa {
///         Err(DFAError::MissingFinalStates) => assert!(true),
///         _ => assert!(false),
///     }
/// }
/// ```
///
/// ```
/// extern crate automata;
///
/// use automata::dfa::core::*;
/// use std::error::Error;
///
/// fn main() {
///     let dfa = DFABuilder::new()
///         .add_start(4)
///         .add_transition('t', 0, 1)
///         .add_transition('t', 0, 2)
///         .finalize();
///     match dfa {
///         Err(DFAError::DuplicatedTransition(symb,src)) => assert!((symb,src)==('t',0)),
///         _ => assert!(false),
///     }
/// }
/// ```
///
/// ```
/// extern crate automata;
///
/// use automata::dfa::core::*;
/// use std::error::Error;
///
/// fn main() {
///     let dfa = DFABuilder::new()
///         .add_final(4)
///         .add_transition('t', 0, 1)
///         .finalize();
///     match dfa {
///         Err(DFAError::MissingStartingState) => assert!(true),
///         _ => assert!(false),
///     }
/// }
/// ```
///
#[derive(Debug)]
pub struct DFABuilder {
    transitions : HashMap<(char,usize),usize>,
    start       : Option<usize>,
    finals      : HashSet<usize>,
}

/// Alias for result::Result<T,DFAError>.
pub type Result<T> = result::Result<T,DFAError>;

/// DFABuilding is the trait assiociated to the DFABuilder type. Each DFABuilder
/// should implement DFABuilding trait.
///
/// DFABuilder can generate some errors during the building stage. For instance,
/// one could try to insert a transition with two different destination states.
///
/// #Errors
///
/// If self contains a DFAerror then each function should transfer this error.
pub trait DFABuilding {
    /// Add a starting state to the DFA.
    ///
    /// # Errors
    ///
    /// In the futur will return a DFAError::DuplicatedStartingState if
    /// two starting states are added.
    fn add_start(self, state: usize) -> Result<DFABuilder>;

    /// Add a final state to the DFA.
    fn add_final(self, state: usize) -> Result<DFABuilder>;

    /// Add a transition to the DFA.
    ///
    /// # Errors
    ///
    /// Return a DFAError::DuplicatedTransition(symb,src) if a transtion
    /// with the same symb and src has already been inserted, even if
    /// the destination state is the same.
    fn add_transition(self, symb: char, src: usize, dest: usize) -> Result<DFABuilder>;

    /// Finalize the building of the DFA.
    ///
    /// # Errors
    ///
    /// Return a DFAError::MissingStartingState if no starting state is specified.
    ///
    /// Return a DFAError::MissingFinalStates if no final state is specified.
    fn finalize(self) -> Result<DFA>;
}

impl DFABuilder {
    /// Creates a new DFABuilder.
    pub fn new() -> Result<DFABuilder> {
        Ok(DFABuilder{transitions: HashMap::new(), start: None, finals: HashSet::new()})
    }
}

impl DFABuilding for DFABuilder {
    fn add_start(self, state: usize) -> Result<DFABuilder> {
        Ok(self).add_start(state)
    }

    fn add_final(self, state: usize) -> Result<DFABuilder> {
        Ok(self).add_final(state)
    }

    fn add_transition(self, symb: char, src: usize, dest: usize) -> Result<DFABuilder> {
        Ok(self).add_transition(symb,src,dest)
    }

    fn finalize(self) -> Result<DFA> {
        Ok(self).finalize()
    }
}

/// Implementing DFABuilding trait for Result<DFABuilder> allows
/// to chain the return value of the DFABuilder instead of unwrapping them
/// at each stage of the building process.
impl DFABuilding for Result<DFABuilder> {
    fn add_start(self, state: usize) -> Result<DFABuilder> {
        self.map(|mut dfa| {
            dfa.start = Some(state);
            dfa
        })
    }

    fn add_final(self, state: usize) -> Result<DFABuilder> {
        self.map(|mut dfa| {
            dfa.finals.insert(state);
            dfa
        })
    }

    fn add_transition(self, symb: char, src: usize, dest: usize) -> Result<DFABuilder> {
        self.and_then(|mut dfa| {
            if dfa.transitions.insert((symb,src), dest).is_some() {
                return Err(DFAError::DuplicatedTransition(symb,src));
            }
            Ok(dfa)
        })
    }

    fn finalize(self) -> Result<DFA> {
        self.and_then(|dfa| {
            if dfa.start.is_none() {
                Err(DFAError::MissingStartingState)
            } else if dfa.finals.is_empty() {
                Err(DFAError::MissingFinalStates)
            } else {
                Ok(DFA{transitions: dfa.transitions, start: dfa.start.unwrap(), finals: dfa.finals})
            }
        })
    }
}

impl DFA {
    /// Test if an input string is a word of the language defined by the DFA.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate automata;
    ///
    /// use automata::dfa::core::*;
    /// use std::error::Error;
    ///
    /// fn main() {
    ///     // (abc)*
    ///     let dfa = DFABuilder::new()
    ///         .add_start(0)
    ///         .add_final(0)
    ///         .add_transition('a', 0, 1)
    ///         .add_transition('b', 1, 2)
    ///         .add_transition('c', 2, 0)
    ///         .finalize();
    ///     match dfa {
    ///         Ok(dfa) => {
    ///            assert!(dfa.test("abc"));
    ///            assert!(dfa.test(""));
    ///            assert!(!dfa.test("a"));
    ///            assert!(!dfa.test("ab"));
    ///            assert!(!dfa.test("abca"));
    ///            assert!(!dfa.test("abcab"));
    ///            assert!(dfa.test("abcabcabc"));
    ///         },
    ///         Err(e) => println!("{}", e),
    ///     }
    /// }
    /// ```
    pub fn test(&self, input: &str) -> bool {
        let f = input
            .chars()
            .fold(Some(self.start), |state,c| {
                match state {
                    Some(n) => self.transitions.get(&(c,n)).map(|v| *v),
                    None => None,
                }
            });
        match f {
            Some(n) => self.finals.contains(&n),
            None => false
        }
    }
}

impl fmt::Display for DFA {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "START: {}", self.start));
        try!(writeln!(f, "FINALS:"));
        for fi in self.finals.iter() {
            try!(writeln!(f,"  {}", fi));
        }
        try!(writeln!(f, "TRANSITIONS:"));
        for (tr,d) in self.transitions.iter() {
            let (c,s) = *tr;
            try!(writeln!(f, "  ({},{}) => {}", c, s, d));
        }
        write!(f, "")
    }
}

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

    #[test]
    fn test_dfa() {
        let dfa = DFABuilder::new()
            .add_start(0)
            .add_final(3)
            .add_transition('a', 0, 1)
            .add_transition('c', 0, 3)
            .add_transition('b', 1, 2)
            .add_transition('a', 2, 1)
            .add_transition('c', 2, 3)
            .finalize()
            .unwrap();
        let samples =
            vec![("ababac", false),
                 ("ababc", true),
                 ("", false),
                 ("abc", true),
                 ("c", true),
                 ("ac", false),
                 ("ababababababababababababababababababababc", true),];

        for (input,expected_result) in samples {
            assert!(dfa.test(input) == expected_result, "input false for: \"{}\"", input);
        }
    }

    #[test]
    fn test_dfa_builder() {
        let _dfa = DFABuilder::new()
            .add_start(0)
            .add_final(3)
            .add_transition('a', 0, 1)
            .add_transition('c', 0, 3)
            .add_transition('b', 1, 2)
            .add_transition('a', 2, 1)
            .add_transition('c', 2, 3)
            .finalize()
            .unwrap();
    }

    #[test]
    fn test_dfa_builder_duplicated_transition() {
        let dfa = DFABuilder::new()
            .add_start(0)
            .add_final(3)
            .add_transition('a', 0, 1)
            .add_transition('c', 0, 3)
            .add_transition('b', 1, 2)
            .add_transition('a', 2, 1)
            .add_transition('c', 2, 3)
            .add_transition('a', 0, 2)
            .finalize();
        match dfa {
            Err(DFAError::DuplicatedTransition(sy,sr)) => assert!((sy,sr) == ('a',0)),
            _ => assert!(false, "DuplicatedTransition expected."),
        }
    }

    #[test]
    fn test_dfa_builder_missing_start() {
        let dfa = DFABuilder::new()
            .add_final(3)
            .add_transition('a', 0, 1)
            .finalize();
        match dfa {
            Err(DFAError::MissingStartingState) => assert!(true),
            _ => assert!(false, "MissingStartingState expected."),
        }
    }

    #[test]
    fn test_dfa_builder_missing_finals() {
        let dfa = DFABuilder::new()
            .add_start(0)
            .add_transition('a', 0, 1)
            .finalize();
        match dfa {
            Err(DFAError::MissingFinalStates) => assert!(true),
            _ => assert!(false, "MissingFinalStates expected."),
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// 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.

/*!
# ears

__ears__ is a simple library for play Audio in Rust.

__ears__ is build on the top of OpenAL and libsndfile.

* Provide an acces to the OpenAL spatialization functionnality in a simple way.
* Accept a lot of audio format thanks to libsndfile.

# A simple example

```Rust
extern mod ears;
use ears::Sound;

fn main() -> {
	// Create a new Sound.
	let snd = Sound::new(~"path/to/my/sound.ogg").unwrap();

	// Play the Sound
	snd.play();

	// Wait until the end of the sound
	while snd.is_playing() {}
}
```

# Functionnality

__ears__ provide two way for play audio files.

* The Sound class, which represent light sounds who can share a buffer of samples with another Sound.
* The Music class, which is a bigger sound and who can't share sample buffer.

# Use ears

As said before, __ears__ require OpenAL and libsndfile, you need to install these two libraries in your system.

__ears__ compile against the last Rust compiler, so if it doesn't work on your computer you may need to update your compiler.

__ears__ work fully with `rustpkg`, so just install __ears__ in your project workspace like this :

```Shell
> rustpkg install github.com/JeremyLetang/ears
```

then import stuff from __ears__ in your project, you can import all the stuff :

```Rust
extern mod ears;

use ears::*;
```

or a specific :

```Rust
extern mod ears;

use ears::Music;
```

# Compile examples

Like __ears__ you can build the examples with `rustpkg`, just do :

```Shell
> rustpkg install examples/an_example
```
*/

#[feature(globs, macro_rules)];

#[link(name = "ears",
       vers = "0.1",
       package_id = "github.com/JeremyLetang/ears",
       author = "letang.jeremy@gmail.com",
       uuid = "D0271EC6-5F27-4C72-BBEA-1341DC665F34",
       url = "https://github.com/JeremyLetang/ears")];

#[desc = "Easy Api in Rust for Sounds"];
#[license = "MIT"];
#[crate_type = "lib"];

extern mod extra;

// Reexport public API
pub use init::ears_init;
pub use music::Music;
pub use sound::Sound;
pub use states::{State, Initial, Playing, Paused, Stopped};
pub use sound_data::SoundData;
pub use audio_controller::AudioController;
pub use audio_tags::{AudioTags, Tags};

// Hidden internal bindings
#[doc(hidden)]
pub mod internal;
#[doc(hidden)]
mod openal;
#[doc(hidden)]
mod sndfile;

// The public ears API
pub mod init;
pub mod listener;
pub mod sound;
pub mod music;
pub mod sound_data;
pub mod states;
pub mod audio_controller;
pub mod audio_tags;
pub mod recorder;
<commit_msg>add managed_boxes attributes before replacing it by std::rc;<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// 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.

/*!
# ears

__ears__ is a simple library for play Audio in Rust.

__ears__ is build on the top of OpenAL and libsndfile.

* Provide an acces to the OpenAL spatialization functionnality in a simple way.
* Accept a lot of audio format thanks to libsndfile.

# A simple example

```Rust
extern mod ears;
use ears::Sound;

fn main() -> {
	// Create a new Sound.
	let snd = Sound::new(~"path/to/my/sound.ogg").unwrap();

	// Play the Sound
	snd.play();

	// Wait until the end of the sound
	while snd.is_playing() {}
}
```

# Functionnality

__ears__ provide two way for play audio files.

* The Sound class, which represent light sounds who can share a buffer of samples with another Sound.
* The Music class, which is a bigger sound and who can't share sample buffer.

# Use ears

As said before, __ears__ require OpenAL and libsndfile, you need to install these two libraries in your system.

__ears__ compile against the last Rust compiler, so if it doesn't work on your computer you may need to update your compiler.

__ears__ work fully with `rustpkg`, so just install __ears__ in your project workspace like this :

```Shell
> rustpkg install github.com/JeremyLetang/ears
```

then import stuff from __ears__ in your project, you can import all the stuff :

```Rust
extern mod ears;

use ears::*;
```

or a specific :

```Rust
extern mod ears;

use ears::Music;
```

# Compile examples

Like __ears__ you can build the examples with `rustpkg`, just do :

```Shell
> rustpkg install examples/an_example
```
*/

#[feature(globs, macro_rules, managed_boxes)];

#[link(name = "ears",
       vers = "0.1",
       package_id = "github.com/JeremyLetang/ears",
       author = "letang.jeremy@gmail.com",
       uuid = "D0271EC6-5F27-4C72-BBEA-1341DC665F34",
       url = "https://github.com/JeremyLetang/ears")];

#[desc = "Easy Api in Rust for Sounds"];
#[license = "MIT"];
#[crate_type = "lib"];

extern mod extra;

// Reexport public API
pub use init::ears_init;
pub use music::Music;
pub use sound::Sound;
pub use states::{State, Initial, Playing, Paused, Stopped};
pub use sound_data::SoundData;
pub use audio_controller::AudioController;
pub use audio_tags::{AudioTags, Tags};

// Hidden internal bindings
#[doc(hidden)]
pub mod internal;
#[doc(hidden)]
mod openal;
#[doc(hidden)]
mod sndfile;

// The public ears API
pub mod init;
pub mod listener;
pub mod sound;
pub mod music;
pub mod sound_data;
pub mod states;
pub mod audio_controller;
pub mod audio_tags;
pub mod recorder;
<|endoftext|>


<commit_before>// Copyright 2013-2014 Simon Sapin.
//
// 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.

//! Abstraction that conditionally compiles either to rust-encoding,
//! or to only support UTF-8.

#[cfg(feature = "query_encoding")] extern crate encoding;

use std::borrow::Cow;

#[cfg(feature = "query_encoding")] use self::encoding::types::{DecoderTrap, EncoderTrap};
#[cfg(feature = "query_encoding")] use self::encoding::label::encoding_from_whatwg_label;
#[cfg(feature = "query_encoding")] pub use self::encoding::types::EncodingRef;

#[cfg(feature = "query_encoding")]
#[derive(Copy)]
pub struct EncodingOverride {
    /// `None` means UTF-8.
    encoding: Option<EncodingRef>
}

#[cfg(feature = "query_encoding")]
impl EncodingOverride {
    pub fn from_opt_encoding(encoding: Option<EncodingRef>) -> EncodingOverride {
        encoding.map(EncodingOverride::from_encoding).unwrap_or_else(EncodingOverride::utf8)
    }

    pub fn from_encoding(encoding: EncodingRef) -> EncodingOverride {
        EncodingOverride {
            encoding: if encoding.name() == "utf-8" { None } else { Some(encoding) }
        }
    }

    pub fn utf8() -> EncodingOverride {
        EncodingOverride { encoding: None }
    }

    pub fn lookup(label: &[u8]) -> Option<EncodingOverride> {
        ::std::str::from_utf8(label)
        .ok()
        .and_then(encoding_from_whatwg_label)
        .map(EncodingOverride::from_encoding)
    }

    pub fn is_utf8(&self) -> bool {
        self.encoding.is_none()
    }

    pub fn decode(&self, input: &[u8]) -> String {
        match self.encoding {
            Some(encoding) => encoding.decode(input, DecoderTrap::Replace).unwrap(),
            None => String::from_utf8_lossy(input).to_string(),
        }
    }

    pub fn encode<'a>(&self, input: &'a str) -> Cow<'a, [u8]> {
        match self.encoding {
            Some(encoding) => Cow::Owned(
                encoding.encode(input, EncoderTrap::NcrEscape).unwrap()),
            None => Cow::Borrowed(input.as_bytes()),  // UTF-8
        }
    }
}

#[cfg(not(feature = "query_encoding"))]
#[derive(Copy, Clone)]
pub struct EncodingOverride;

#[cfg(not(feature = "query_encoding"))]
impl EncodingOverride {
    pub fn utf8() -> EncodingOverride {
        EncodingOverride
    }

    pub fn lookup(_label: &[u8]) -> Option<EncodingOverride> {
        None
    }

    pub fn is_utf8(&self) -> bool {
        true
    }

    pub fn decode(&self, input: &[u8]) -> String {
        String::from_utf8_lossy(input).into_owned()
    }

    pub fn encode<'a>(&self, input: &'a str) -> Cow<'a, [u8]> {
        Cow::Borrowed(input.as_bytes())
    }
}
<commit_msg>Upgrade to rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)<commit_after>// Copyright 2013-2014 Simon Sapin.
//
// 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.

//! Abstraction that conditionally compiles either to rust-encoding,
//! or to only support UTF-8.

#[cfg(feature = "query_encoding")] extern crate encoding;

use std::borrow::Cow;

#[cfg(feature = "query_encoding")] use self::encoding::types::{DecoderTrap, EncoderTrap};
#[cfg(feature = "query_encoding")] use self::encoding::label::encoding_from_whatwg_label;
#[cfg(feature = "query_encoding")] pub use self::encoding::types::EncodingRef;

#[cfg(feature = "query_encoding")]
#[derive(Copy, Clone)]
pub struct EncodingOverride {
    /// `None` means UTF-8.
    encoding: Option<EncodingRef>
}

#[cfg(feature = "query_encoding")]
impl EncodingOverride {
    pub fn from_opt_encoding(encoding: Option<EncodingRef>) -> EncodingOverride {
        encoding.map(EncodingOverride::from_encoding).unwrap_or_else(EncodingOverride::utf8)
    }

    pub fn from_encoding(encoding: EncodingRef) -> EncodingOverride {
        EncodingOverride {
            encoding: if encoding.name() == "utf-8" { None } else { Some(encoding) }
        }
    }

    pub fn utf8() -> EncodingOverride {
        EncodingOverride { encoding: None }
    }

    pub fn lookup(label: &[u8]) -> Option<EncodingOverride> {
        ::std::str::from_utf8(label)
        .ok()
        .and_then(encoding_from_whatwg_label)
        .map(EncodingOverride::from_encoding)
    }

    pub fn is_utf8(&self) -> bool {
        self.encoding.is_none()
    }

    pub fn decode(&self, input: &[u8]) -> String {
        match self.encoding {
            Some(encoding) => encoding.decode(input, DecoderTrap::Replace).unwrap(),
            None => String::from_utf8_lossy(input).to_string(),
        }
    }

    pub fn encode<'a>(&self, input: &'a str) -> Cow<'a, [u8]> {
        match self.encoding {
            Some(encoding) => Cow::Owned(
                encoding.encode(input, EncoderTrap::NcrEscape).unwrap()),
            None => Cow::Borrowed(input.as_bytes()),  // UTF-8
        }
    }
}

#[cfg(not(feature = "query_encoding"))]
#[derive(Copy, Clone)]
pub struct EncodingOverride;

#[cfg(not(feature = "query_encoding"))]
impl EncodingOverride {
    pub fn utf8() -> EncodingOverride {
        EncodingOverride
    }

    pub fn lookup(_label: &[u8]) -> Option<EncodingOverride> {
        None
    }

    pub fn is_utf8(&self) -> bool {
        true
    }

    pub fn decode(&self, input: &[u8]) -> String {
        String::from_utf8_lossy(input).into_owned()
    }

    pub fn encode<'a>(&self, input: &'a str) -> Cow<'a, [u8]> {
        Cow::Borrowed(input.as_bytes())
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Data structures containing extracted URL, mention, tag, and media information.
//!
//! These structures are meant to be received in an API call to describe the data they accompany.
//! For example, a `UrlEntity` describes a hyperlink in a tweet or user description text, and a
//! `HashtagEntity` describes a hashtag or stock symbol extracted from a tweet.
//!
//! For more information on the data in these structures, see Twitter's documentation for
//! [Entities][] and [Entities in Objects][obj].
//!
//! [Entities]: https://dev.twitter.com/overview/api/entities
//! [obj]: https://dev.twitter.com/overview/api/entities-in-twitter-objects
//!
//! ## Entity Ranges
//!
//! Entities that refer to elements within a text have a `range` field that contains the text span
//! that is being referenced. The numbers in question are byte offsets, so if you have an entity
//! that you'd like to slice out of the source text, you can use the indices directly in slicing
//! operations:
//!
//! ```rust
//! # use egg_mode::entities::HashtagEntity;
//! # let entity = HashtagEntity { range: (0, 0), text: "".to_string() };
//! # let text = "asdf";
//! let slice = &text[entity.range.0..entity.range.1];
//! ```
//!
//! ### Shortened, Display, and Expanded URLs
//!
//! URL and Media entities contain references to a URL within their parent text. However, due to
//! the nature of how Twitter handles URLs in tweets and user bios, each entity struct has three
//! URLs within it:
//!
//! - `url`: This is the `t.co` shortened URL as returned directly from twitter. This is what
//!   contributes to character count in tweets and user bios.
//! - `expanded_url`: This is the original URL the user entered in their tweet. While it is given
//!   to API client, Twitter recommends still sending users to the shortened link, for analytics
//!   purposes. Twitter Web uses this field to supply hover-text for where the URL resolves to.
//! - `display_url`: This is a truncated version of `expanded_url`, meant to be displayed inline
//!   with the parent text. This is useful to show users where the link resolves to, without
//!   potentially filling up a lot of space with the fullly expanded URL.
use mime;
use serde::{Deserialize, Deserializer};

use common::deserialize_mime;

///Represents a hashtag or symbol extracted from another piece of text.
#[derive(Debug, Clone, Deserialize)]
pub struct HashtagEntity {
    ///The byte offsets where the hashtag is located. The first index is the location of the # or $
    ///character; the second is the location of the first character following the hashtag.
    #[serde(rename = "indices")]
    pub range: (usize, usize),
    ///The text of the hashtag, without the leading # or $ character.
    pub text: String,
}

///Represents a piece of media attached to a tweet.
///
///The information in this struct is subtly different depending on what media is being referenced,
///and which entity container is holding this instance. For videos and GIFs, the `media_url` and
///`media_url_https` fields each link to a thumbnail image of the media, typically of the first
///frame. The real video information can be found on the `video_info` field, including various
///encodings if available.
///
///Image links available in `media_url` and `media_url_https` can be obtained in different sizes by
///appending a colon and one of the available sizes in the `MediaSizes` struct. For example, the
///cropped thumbnail can be viewed by appending `:thumb` to the end of the URL, and the full-size
///image can be viewed by appending `:large`.
#[derive(Debug, Clone, Deserialize)]
pub struct MediaEntity {
    ///A shortened URL to display to clients.
    pub display_url: String,
    ///An expanded version of `display_url`; links to the media display page.
    pub expanded_url: String,
    ///A numeric ID for the media.
    pub id: u64,
    ///The byte offsets where the media URL is located. The first index is the location of the
    ///first character of the URL; the second is the location of the first character following the
    ///URL.
    #[serde(rename = "indices")]
    pub range: (usize, usize),
    ///A URL pointing directly to the media file. Uses HTTP as the protocol.
    ///
    ///For videos and GIFs, this link will be to a thumbnail of the media, and the real video link
    ///will be contained in `video_info`.
    pub media_url: String,
    ///A URL pointing directly to the media file. Uses HTTPS as the protocol.
    ///
    ///For videos and GIFs, this link will be to a thumbnail of the media, and the real video link
    ///will be contained in `video_info`.
    pub media_url_https: String,
    ///Various sizes available for the media file.
    pub sizes: MediaSizes,
    ///For tweets containing media that was originally associated with a different tweet, this
    ///contains the ID of the original tweet.
    pub source_status_id: Option<u64>,
    ///The type of media being represented.
    #[serde(rename = "type")]
    pub media_type: MediaType,
    ///The t.co link from the original text.
    pub url: String,
    ///For media entities corresponding to videos, this contains extra information about the linked
    ///video.
    pub video_info: Option<VideoInfo>,
}

///Represents the types of media that can be attached to a tweet.
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum MediaType {
    ///A static image.
    #[serde(rename = "photo")]
    Photo,
    ///A video.
    #[serde(rename = "video")]
    Video,
    ///An animated GIF, delivered as a video without audio.
    #[serde(rename = "animated_gif")]
    Gif,
}

///Represents the available sizes for a media file.
#[derive(Debug, Copy, Clone, Deserialize)]
pub struct MediaSizes {
    ///Information for a thumbnail-sized version of the media.
    pub thumb: MediaSize,
    ///Information for a small-sized version of the media.
    pub small: MediaSize,
    ///Information for a medium-sized version of the media.
    pub medium: MediaSize,
    ///Information for a large-sized version of the media.
    pub large: MediaSize,
}

///Represents how an image has been resized for a given size variant.
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum ResizeMode {
    ///The media was resized to fit one dimension, keeping its aspect ratio.
    #[serde(rename = "fit")]
    Fit,
    ///The media was cropped to fit a specific resolution.
    #[serde(rename = "crop")]
    Crop,
}

///Represents the dimensions of a media file.
#[derive(Debug, Copy, Clone, Deserialize)]
pub struct MediaSize {
    ///The size variant's width in pixels.
    pub w: i32,
    ///The size variant's height in pixels.
    pub h: i32,
    ///The method used to obtain the given dimensions.
    pub resize: ResizeMode,
}

///Represents metadata specific to videos.
#[derive(Debug, Clone, Deserialize)]
pub struct VideoInfo {
    ///The aspect ratio of the video.
    pub aspect_ratio: (i32, i32),
    ///The duration of the video, in milliseconds.
    ///
    ///This field is not given for animated GIFs.
    pub duration_millis: Option<i32>,
    ///Information about various encodings available for the video.
    pub variants: Vec<VideoVariant>,
}

///Represents information about a specific encoding of a video.
#[derive(Debug, Clone, Deserialize)]
pub struct VideoVariant {
    ///The bitrate of the video. This value is present for GIFs, but it will be zero.
    pub bitrate: Option<i32>,
    ///The file format of the video variant.
    #[serde(deserialize_with = "deserialize_mime")]
    pub content_type: mime::Mime,
    ///The URL for the video variant.
    pub url: String,
}

///Represents a link extracted from another piece of text.
#[derive(Debug, Clone, Deserialize)]
pub struct UrlEntity {
    ///A truncated URL meant to be displayed inline with the text.
    #[serde(default)]
    pub display_url: String,
    ///The URL that the t.co URL resolves to.
    ///
    ///Meant to be used as hover-text when a user mouses over a link.
    #[serde(default)]
    pub expanded_url: String,
    ///The byte offsets in the companion text where the URL was extracted from.
    #[serde(rename = "indices")]
    pub range: (usize, usize),
    ///The t.co URL extracted from the companion text.
    pub url: String,
}

///Represnts a user mention extracted from another piece of text.
#[derive(Debug, Clone, Deserialize)]
pub struct MentionEntity {
    ///Numeric ID of the mentioned user.
    #[serde(deserialize_with = "nullable_id")]  // Very rarely this field is null
    pub id: u64,
    ///The byte offsets where the user mention is located in the original text. The first index is
    ///the location of the @ symbol; the second is the location of the first character following
    ///the user screen name.
    #[serde(rename = "indices")]
    pub range: (usize, usize),
    ///Display name of the mentioned user.
    #[serde(deserialize_with = "nullable_str")]  // Very rarely, this field is null
    pub name: String,
    ///Screen name of the mentioned user, without the leading @ symbol.
    pub screen_name: String,
}

fn nullable_id<'de, D>(deserializer: D) -> Result<u64, D::Error> where D: Deserializer<'de> {
    let opt = Option::deserialize(deserializer)?;
    Ok(opt.unwrap_or_default())
}

fn nullable_str<'de, D>(deserializer: D) -> Result<String, D::Error> where D: Deserializer<'de> {
    let opt = Option::deserialize(deserializer)?;
    Ok(opt.unwrap_or_default())
}
<commit_msg>fix(media): Add alt text support for accessibility<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Data structures containing extracted URL, mention, tag, and media information.
//!
//! These structures are meant to be received in an API call to describe the data they accompany.
//! For example, a `UrlEntity` describes a hyperlink in a tweet or user description text, and a
//! `HashtagEntity` describes a hashtag or stock symbol extracted from a tweet.
//!
//! For more information on the data in these structures, see Twitter's documentation for
//! [Entities][] and [Entities in Objects][obj].
//!
//! [Entities]: https://dev.twitter.com/overview/api/entities
//! [obj]: https://dev.twitter.com/overview/api/entities-in-twitter-objects
//!
//! ## Entity Ranges
//!
//! Entities that refer to elements within a text have a `range` field that contains the text span
//! that is being referenced. The numbers in question are byte offsets, so if you have an entity
//! that you'd like to slice out of the source text, you can use the indices directly in slicing
//! operations:
//!
//! ```rust
//! # use egg_mode::entities::HashtagEntity;
//! # let entity = HashtagEntity { range: (0, 0), text: "".to_string() };
//! # let text = "asdf";
//! let slice = &text[entity.range.0..entity.range.1];
//! ```
//!
//! ### Shortened, Display, and Expanded URLs
//!
//! URL and Media entities contain references to a URL within their parent text. However, due to
//! the nature of how Twitter handles URLs in tweets and user bios, each entity struct has three
//! URLs within it:
//!
//! - `url`: This is the `t.co` shortened URL as returned directly from twitter. This is what
//!   contributes to character count in tweets and user bios.
//! - `expanded_url`: This is the original URL the user entered in their tweet. While it is given
//!   to API client, Twitter recommends still sending users to the shortened link, for analytics
//!   purposes. Twitter Web uses this field to supply hover-text for where the URL resolves to.
//! - `display_url`: This is a truncated version of `expanded_url`, meant to be displayed inline
//!   with the parent text. This is useful to show users where the link resolves to, without
//!   potentially filling up a lot of space with the fullly expanded URL.
use mime;
use serde::{Deserialize, Deserializer};

use common::deserialize_mime;

///Represents a hashtag or symbol extracted from another piece of text.
#[derive(Debug, Clone, Deserialize)]
pub struct HashtagEntity {
    ///The byte offsets where the hashtag is located. The first index is the location of the # or $
    ///character; the second is the location of the first character following the hashtag.
    #[serde(rename = "indices")]
    pub range: (usize, usize),
    ///The text of the hashtag, without the leading # or $ character.
    pub text: String,
}

///Represents a piece of media attached to a tweet.
///
///The information in this struct is subtly different depending on what media is being referenced,
///and which entity container is holding this instance. For videos and GIFs, the `media_url` and
///`media_url_https` fields each link to a thumbnail image of the media, typically of the first
///frame. The real video information can be found on the `video_info` field, including various
///encodings if available.
///
///Image links available in `media_url` and `media_url_https` can be obtained in different sizes by
///appending a colon and one of the available sizes in the `MediaSizes` struct. For example, the
///cropped thumbnail can be viewed by appending `:thumb` to the end of the URL, and the full-size
///image can be viewed by appending `:large`.
#[derive(Debug, Clone, Deserialize)]
pub struct MediaEntity {
    ///A shortened URL to display to clients.
    pub display_url: String,
    ///An expanded version of `display_url`; links to the media display page.
    pub expanded_url: String,
    ///A numeric ID for the media.
    pub id: u64,
    ///The byte offsets where the media URL is located. The first index is the location of the
    ///first character of the URL; the second is the location of the first character following the
    ///URL.
    #[serde(rename = "indices")]
    pub range: (usize, usize),
    ///A URL pointing directly to the media file. Uses HTTP as the protocol.
    ///
    ///For videos and GIFs, this link will be to a thumbnail of the media, and the real video link
    ///will be contained in `video_info`.
    pub media_url: String,
    ///A URL pointing directly to the media file. Uses HTTPS as the protocol.
    ///
    ///For videos and GIFs, this link will be to a thumbnail of the media, and the real video link
    ///will be contained in `video_info`.
    pub media_url_https: String,
    ///Various sizes available for the media file.
    pub sizes: MediaSizes,
    ///For tweets containing media that was originally associated with a different tweet, this
    ///contains the ID of the original tweet.
    pub source_status_id: Option<u64>,
    ///The type of media being represented.
    #[serde(rename = "type")]
    pub media_type: MediaType,
    ///The t.co link from the original text.
    pub url: String,
    ///For media entities corresponding to videos, this contains extra information about the linked
    ///video.
    pub video_info: Option<VideoInfo>,
    ///Alt text for accessibility. If alt text isn't available for a given image, this will be
    ///`None`.
    pub ext_alt_text: Option<String>,
}

///Represents the types of media that can be attached to a tweet.
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum MediaType {
    ///A static image.
    #[serde(rename = "photo")]
    Photo,
    ///A video.
    #[serde(rename = "video")]
    Video,
    ///An animated GIF, delivered as a video without audio.
    #[serde(rename = "animated_gif")]
    Gif,
}

///Represents the available sizes for a media file.
#[derive(Debug, Copy, Clone, Deserialize)]
pub struct MediaSizes {
    ///Information for a thumbnail-sized version of the media.
    pub thumb: MediaSize,
    ///Information for a small-sized version of the media.
    pub small: MediaSize,
    ///Information for a medium-sized version of the media.
    pub medium: MediaSize,
    ///Information for a large-sized version of the media.
    pub large: MediaSize,
}

///Represents how an image has been resized for a given size variant.
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum ResizeMode {
    ///The media was resized to fit one dimension, keeping its aspect ratio.
    #[serde(rename = "fit")]
    Fit,
    ///The media was cropped to fit a specific resolution.
    #[serde(rename = "crop")]
    Crop,
}

///Represents the dimensions of a media file.
#[derive(Debug, Copy, Clone, Deserialize)]
pub struct MediaSize {
    ///The size variant's width in pixels.
    pub w: i32,
    ///The size variant's height in pixels.
    pub h: i32,
    ///The method used to obtain the given dimensions.
    pub resize: ResizeMode,
}

///Represents metadata specific to videos.
#[derive(Debug, Clone, Deserialize)]
pub struct VideoInfo {
    ///The aspect ratio of the video.
    pub aspect_ratio: (i32, i32),
    ///The duration of the video, in milliseconds.
    ///
    ///This field is not given for animated GIFs.
    pub duration_millis: Option<i32>,
    ///Information about various encodings available for the video.
    pub variants: Vec<VideoVariant>,
}

///Represents information about a specific encoding of a video.
#[derive(Debug, Clone, Deserialize)]
pub struct VideoVariant {
    ///The bitrate of the video. This value is present for GIFs, but it will be zero.
    pub bitrate: Option<i32>,
    ///The file format of the video variant.
    #[serde(deserialize_with = "deserialize_mime")]
    pub content_type: mime::Mime,
    ///The URL for the video variant.
    pub url: String,
}

///Represents a link extracted from another piece of text.
#[derive(Debug, Clone, Deserialize)]
pub struct UrlEntity {
    ///A truncated URL meant to be displayed inline with the text.
    #[serde(default)]
    pub display_url: String,
    ///The URL that the t.co URL resolves to.
    ///
    ///Meant to be used as hover-text when a user mouses over a link.
    #[serde(default)]
    pub expanded_url: String,
    ///The byte offsets in the companion text where the URL was extracted from.
    #[serde(rename = "indices")]
    pub range: (usize, usize),
    ///The t.co URL extracted from the companion text.
    pub url: String,
}

///Represnts a user mention extracted from another piece of text.
#[derive(Debug, Clone, Deserialize)]
pub struct MentionEntity {
    ///Numeric ID of the mentioned user.
    #[serde(deserialize_with = "nullable_id")]  // Very rarely this field is null
    pub id: u64,
    ///The byte offsets where the user mention is located in the original text. The first index is
    ///the location of the @ symbol; the second is the location of the first character following
    ///the user screen name.
    #[serde(rename = "indices")]
    pub range: (usize, usize),
    ///Display name of the mentioned user.
    #[serde(deserialize_with = "nullable_str")]  // Very rarely, this field is null
    pub name: String,
    ///Screen name of the mentioned user, without the leading @ symbol.
    pub screen_name: String,
}

fn nullable_id<'de, D>(deserializer: D) -> Result<u64, D::Error> where D: Deserializer<'de> {
    let opt = Option::deserialize(deserializer)?;
    Ok(opt.unwrap_or_default())
}

fn nullable_str<'de, D>(deserializer: D) -> Result<String, D::Error> where D: Deserializer<'de> {
    let opt = Option::deserialize(deserializer)?;
    Ok(opt.unwrap_or_default())
}
<|endoftext|>


<commit_before>use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_void, ptrdiff_t, size_t};

pub enum Object { }

pub struct Sel {
	ptr: *const c_void,
}

pub struct Ivar {
	_ptr: *const c_void,
}

pub struct Class {
	ptr: *mut Object,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn objc_getClass(name: *const c_char) -> Class;
	pub fn class_getName(cls: Class) -> *const c_char;
	pub fn class_addMethod(cls: Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: Class, name: *const c_char, extraBytes: size_t) -> Class;
	pub fn objc_disposeClassPair(cls: Class);
	pub fn objc_registerClassPair(cls: Class);

	pub fn object_setInstanceVariable(obj: *mut Object, name: *const c_char, value: *mut c_void) -> Ivar;
	pub fn object_getInstanceVariable(obj: *mut Object, name: *const c_char, outValue: *mut *mut c_void) -> Ivar;
	pub fn object_setIvar(obj: *mut Object, ivar: Ivar, value: *mut Object);
	pub fn object_getIvar(obj: *mut Object, ivar: Ivar) -> *mut Object;
	pub fn object_getClass(obj: *mut Object) -> Class;

	pub fn ivar_getName(ivar: Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

impl PartialEq for Sel {
	fn eq(&self, other: &Sel) -> bool {
		self.ptr == other.ptr
	}
}

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel {
		Sel { ptr: self.ptr }
	}
}

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(*self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getName(*self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Object {
	unsafe fn get_ivar_ptr<T>(obj: *mut Object, name: &str) -> *mut T {
		if obj.is_null() {
			RawPtr::null()
		} else {
			let ivar = name.with_c_str(|name| {
				object_getInstanceVariable(obj, name, RawPtr::null())
			});
			let bytes = obj as *mut u8;
			let offset = ivar.offset();
			bytes.offset(offset) as *mut T
		}
	}

	pub unsafe fn get_ivar<T>(&self, name: &str) -> &T {
		let obj = self as *const Object as *mut Object;
		&*Object::get_ivar_ptr(obj, name)
	}

	pub unsafe fn get_mut_ivar<T>(&mut self, name: &str) -> &mut T {
		&mut *Object::get_ivar_ptr(self, name)
	}

	pub unsafe fn set_ivar<T>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

impl Class {
	pub fn get(name: &str) -> Option<Class> {
		let cls = name.with_c_str(|name| unsafe {
			objc_getClass(name)
		});
		if cls.is_nil() {
			None
		} else {
			Some(cls)
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

pub trait Message { }

impl Message for Object { }

pub trait ToMessage {
	fn as_ptr(&self) -> *mut Object;

	fn is_nil(&self) -> bool {
		self.as_ptr().is_null()
	}
}

impl<T: Message> ToMessage for *mut T {
	fn as_ptr(&self) -> *mut Object {
		*self as *mut Object
	}
}

impl<'a, T: Message> ToMessage for &'a T {
	fn as_ptr(&self) -> *mut Object {
		(*self as *const T as *mut T).as_ptr()
	}
}

impl ToMessage for Class {
	fn as_ptr(&self) -> *mut Object {
		self.ptr
	}
}
<commit_msg>Remove Clone for Sel since it's Copy.<commit_after>use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_void, ptrdiff_t, size_t};

pub enum Object { }

pub struct Sel {
	ptr: *const c_void,
}

pub struct Ivar {
	_ptr: *const c_void,
}

pub struct Class {
	ptr: *mut Object,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn objc_getClass(name: *const c_char) -> Class;
	pub fn class_getName(cls: Class) -> *const c_char;
	pub fn class_addMethod(cls: Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: Class, name: *const c_char, extraBytes: size_t) -> Class;
	pub fn objc_disposeClassPair(cls: Class);
	pub fn objc_registerClassPair(cls: Class);

	pub fn object_setInstanceVariable(obj: *mut Object, name: *const c_char, value: *mut c_void) -> Ivar;
	pub fn object_getInstanceVariable(obj: *mut Object, name: *const c_char, outValue: *mut *mut c_void) -> Ivar;
	pub fn object_setIvar(obj: *mut Object, ivar: Ivar, value: *mut Object);
	pub fn object_getIvar(obj: *mut Object, ivar: Ivar) -> *mut Object;
	pub fn object_getClass(obj: *mut Object) -> Class;

	pub fn ivar_getName(ivar: Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

impl PartialEq for Sel {
	fn eq(&self, other: &Sel) -> bool {
		self.ptr == other.ptr
	}
}

impl Eq for Sel { }

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(*self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getName(*self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Object {
	unsafe fn get_ivar_ptr<T>(obj: *mut Object, name: &str) -> *mut T {
		if obj.is_null() {
			RawPtr::null()
		} else {
			let ivar = name.with_c_str(|name| {
				object_getInstanceVariable(obj, name, RawPtr::null())
			});
			let bytes = obj as *mut u8;
			let offset = ivar.offset();
			bytes.offset(offset) as *mut T
		}
	}

	pub unsafe fn get_ivar<T>(&self, name: &str) -> &T {
		let obj = self as *const Object as *mut Object;
		&*Object::get_ivar_ptr(obj, name)
	}

	pub unsafe fn get_mut_ivar<T>(&mut self, name: &str) -> &mut T {
		&mut *Object::get_ivar_ptr(self, name)
	}

	pub unsafe fn set_ivar<T>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

impl Class {
	pub fn get(name: &str) -> Option<Class> {
		let cls = name.with_c_str(|name| unsafe {
			objc_getClass(name)
		});
		if cls.is_nil() {
			None
		} else {
			Some(cls)
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

pub trait Message { }

impl Message for Object { }

pub trait ToMessage {
	fn as_ptr(&self) -> *mut Object;

	fn is_nil(&self) -> bool {
		self.as_ptr().is_null()
	}
}

impl<T: Message> ToMessage for *mut T {
	fn as_ptr(&self) -> *mut Object {
		*self as *mut Object
	}
}

impl<'a, T: Message> ToMessage for &'a T {
	fn as_ptr(&self) -> *mut Object {
		(*self as *const T as *mut T).as_ptr()
	}
}

impl ToMessage for Class {
	fn as_ptr(&self) -> *mut Object {
		self.ptr
	}
}
<|endoftext|>


<commit_before>pub mod listeners;

extern crate csv;
extern crate hyper;
extern crate regex;

use std::io::Read;
use config::Config;
use util::error::DetailedError;
use self::hyper::client::Client;
use self::regex::Regex;

enum FeedSource {
    Top,
    State(u32),
}

#[derive(Debug)]
pub struct Feed {
    pub id:        u32,
    pub state_id:  u32,
    pub county:    String,
    pub name:      String,
    pub listeners: u32,
    pub alert:     Option<String>,
}

impl PartialEq for Feed {
    fn eq(&self, other: &Feed) -> bool {
        self.id == other.id
    }
}

fn parse(html: &str, source: FeedSource) -> Result<Vec<Feed>, DetailedError> {
    lazy_static! {
        static ref TOP: Regex =
            Regex::new(
                r#"(?s)(?P<listeners>\d+)	.+?/listen/stid/(?P<state_id>\d+).+?/listen/ctid/\d+">(?P<county>.+?).+?/listen/feed/(?P<id>\d+)">(?P<name>.+?)(?:

.
(?P<alert>.+?)
)?"#)
                .unwrap();

        static ref STATE: Regex =
            Regex::new(
                r#"(?s)listen/ctid/\d+">(?P<county>.+?).+?w1p">.+?<a href="/listen/feed/(?P<id>\d+)">(?P<name>.+?).+?(?:bold">(?P<alert>.+?).+?)?(?P<listeners>\d+)</'td>"#)
                .unwrap();
    }

    let regex = match source {
        FeedSource::Top      => &*TOP,
        FeedSource::State(_) => &*STATE,
    };

    let mut feeds = Vec::new();

    for cap in regex.captures_iter(&html) {
        let state_id = match source {
            FeedSource::Top       => try_detailed!(cap["state_id"].parse::<u32>()),
            FeedSource::State(id) => id,
        };

        feeds.push(
            Feed {
                id:        try_detailed!(cap["id"].parse()),
                state_id:  state_id,
                county:    cap["county"].to_string(),
                name:      cap["name"].to_string(),
                listeners: try_detailed!(cap["listeners"].parse()),
                alert:     cap.name("alert").map(|s| s.as_str().to_string()),
            }
        );
    }

    Ok(feeds)
}

fn download_feed_data(config: &Config, client: &Client, source: FeedSource) ->
    Result<String, DetailedError> {

    let url = match source {
        FeedSource::Top       => config.links.top_feeds.clone(),
        FeedSource::State(id) => format!("{}{}", &config.links.state_feeds, id),
    };

    let mut resp = try_detailed!(client.get(&url).send());

    let mut body = String::new();
    try_detailed!(resp.read_to_string(&mut body));

    Ok(body)
}

fn filter(config: &Config, feeds: &mut Vec<Feed>) {
    if config.whitelist.len() > 0 {
        feeds.retain(|ref feed| {
            config.whitelist
                .iter()
                .any(|entry| entry.matches_feed(&feed))
        });
    }

    if config.blacklist.len() > 0 {
        feeds.retain(|ref feed| {
            config.blacklist
                .iter()
                .any(|entry| !entry.matches_feed(&feed))
        });
    }
}

pub fn get_latest(config: &Config) -> Result<Vec<Feed>, DetailedError> {
    use self::FeedSource::*;

    let client = Client::new();
    let mut feeds = parse(&download_feed_data(&config, &client, Top)?, Top)?;

    if let Some(id) = config.misc.state_feeds_id {
        feeds.extend(parse(&download_feed_data(&config, &client, State(id))?, State(id))?);

        // Remove any state feeds that show up in the top 50 list
        feeds.sort_by_key(|f| f.id);
        feeds.dedup();
    }

    filter(&config, &mut feeds);
    Ok(feeds)
}<commit_msg>Fix feeds marked with numerous counties not being captured<commit_after>pub mod listeners;

extern crate csv;
extern crate hyper;
extern crate regex;

use std::io::Read;
use config::Config;
use util::error::DetailedError;
use self::hyper::client::Client;
use self::regex::Regex;

enum FeedSource {
    Top,
    State(u32),
}

#[derive(Debug)]
pub struct Feed {
    pub id:        u32,
    pub state_id:  u32,
    pub county:    String,
    pub name:      String,
    pub listeners: u32,
    pub alert:     Option<String>,
}

impl PartialEq for Feed {
    fn eq(&self, other: &Feed) -> bool {
        self.id == other.id
    }
}

fn parse(html: &str, source: FeedSource) -> Result<Vec<Feed>, DetailedError> {
    lazy_static! {
        static ref TOP: Regex =
            Regex::new(
                r#"(?s)(?P<listeners>\d+)	.+?/listen/stid/(?P<state_id>\d+)(?:.+?/listen/ctid/\d+">(?P<county>.+?))?.+?/listen/feed/(?P<id>\d+)">(?P<name>.+?)(?:

.
(?P<alert>.+?)
)?"#)
                .unwrap();

        static ref STATE: Regex =
            Regex::new(
                r#"(?s)listen/ctid/\d+">(?P<county>.+?).+?w1p">.+?<a href="/listen/feed/(?P<id>\d+)">(?P<name>.+?).+?(?:bold">(?P<alert>.+?).+?)?(?P<listeners>\d+)</'td>"#)
                .unwrap();
    }

    let regex = match source {
        FeedSource::Top      => &*TOP,
        FeedSource::State(_) => &*STATE,
    };

    let mut feeds = Vec::new();

    for cap in regex.captures_iter(&html) {
        let state_id = match source {
            FeedSource::Top       => try_detailed!(cap["state_id"].parse::<u32>()),
            FeedSource::State(id) => id,
        };

        feeds.push(
            Feed {
                id:        try_detailed!(cap["id"].parse()),
                state_id:  state_id,
                county:    cap.name("county")
                              .map(|s| s.as_str())
                              .unwrap_or("Numerous")
                              .to_string(),
                name:      cap["name"].to_string(),
                listeners: try_detailed!(cap["listeners"].parse()),
                alert:     cap.name("alert").map(|s| s.as_str().to_string()),
            }
        );
    }

    Ok(feeds)
}

fn download_feed_data(config: &Config, client: &Client, source: FeedSource) ->
    Result<String, DetailedError> {

    let url = match source {
        FeedSource::Top       => config.links.top_feeds.clone(),
        FeedSource::State(id) => format!("{}{}", &config.links.state_feeds, id),
    };

    let mut resp = try_detailed!(client.get(&url).send());

    let mut body = String::new();
    try_detailed!(resp.read_to_string(&mut body));

    Ok(body)
}

fn filter(config: &Config, feeds: &mut Vec<Feed>) {
    if config.whitelist.len() > 0 {
        feeds.retain(|ref feed| {
            config.whitelist
                .iter()
                .any(|entry| entry.matches_feed(&feed))
        });
    }

    if config.blacklist.len() > 0 {
        feeds.retain(|ref feed| {
            config.blacklist
                .iter()
                .any(|entry| !entry.matches_feed(&feed))
        });
    }
}

pub fn get_latest(config: &Config) -> Result<Vec<Feed>, DetailedError> {
    use self::FeedSource::*;

    let client = Client::new();
    let mut feeds = parse(&download_feed_data(&config, &client, Top)?, Top)?;

    if let Some(id) = config.misc.state_feeds_id {
        feeds.extend(parse(&download_feed_data(&config, &client, State(id))?, State(id))?);

        // Remove any state feeds that show up in the top 50 list
        feeds.sort_by_key(|f| f.id);
        feeds.dedup();
    }

    filter(&config, &mut feeds);
    Ok(feeds)
}<|endoftext|>


<commit_before>//! # generator
//!
//! Rust generator implementation
//!

use std::fmt;
use std::panic;
use std::thread;
use std::any::Any;
use std::marker::PhantomData;

use scope::Scope;
use yield_::yield_now;
use rt::{Context, ContextStack, Error};
use reg_context::RegContext;

// default stack size, in usize
// windows has a minimal size as 0x4a8!!!!
pub const DEFAULT_STACK_SIZE: usize = 0x1000;

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    #[cfg_attr(feature = "cargo-clippy", allow(boxed_local))]
    fn call_box(self: Box<Self>) {
        self()
    }
}

/// Generator helper
pub struct Gn<A> {
    dummy: PhantomData<A>,
}

/// the generator type
pub type Generator<'a, A, T> = Box<GeneratorImpl<'a, A, T>>;
unsafe impl<A, T> Send for GeneratorImpl<'static, A, T> {}

impl<A> Gn<A> {
    /// create a scoped generator with default stack size
    pub fn new_scoped<'a, T, F>(f: F) -> Generator<'a, A, T>
    where
        F: FnOnce(Scope<A, T>) -> T + 'a,
        T: 'a,
        A: 'a,
    {
        Self::new_scoped_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a scoped generator with specified stack size
    pub fn new_scoped_opt<'a, T, F>(size: usize, f: F) -> Generator<'a, A, T>
    where
        F: FnOnce(Scope<A, T>) -> T + 'a,
        T: 'a,
        A: 'a,
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        let scope = g.get_scope();
        g.init(move || f(scope));
        g
    }
}

impl<A: Any> Gn<A> {
    /// create a new generator with default stack size
    pub fn new<'a, T: Any, F>(f: F) -> Generator<'a, A, T>
    where
        F: FnOnce() -> T + 'a,
    {
        Self::new_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a new generator with specified stack size
    pub fn new_opt<'a, T: Any, F>(size: usize, f: F) -> Generator<'a, A, T>
    where
        F: FnOnce() -> T + 'a,
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        g.init_context();
        g.init(f);
        g
    }
}

/// `GeneratorImpl`
pub struct GeneratorImpl<'a, A, T> {
    // run time context
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<Box<FnBox + 'a>>,
}

impl<'a, A: Any, T: Any> GeneratorImpl<'a, A, T> {
    /// create a new generator with default stack size
    pub fn init_context(&mut self) {
        self.context.para = &mut self.para as &mut Any;
        self.context.ret = &mut self.ret as &mut Any;
    }
}

impl<'a, A, T> GeneratorImpl<'a, A, T> {
    /// create a new generator with specified stack size
    pub fn new(size: usize) -> Box<Self> {
        Box::new(GeneratorImpl {
            para: None,
            ret: None,
            f: None,
            context: Context::new(size),
        })
    }

    /// prefech the generator into cache
    #[inline]
    pub fn prefetch(&self) {
        self.context.regs.prefetch();
    }

    /// get the scope object
    pub fn get_scope(&mut self) -> Scope<A, T> {
        Scope::new(&mut self.para, &mut self.ret)
    }

    /// init a heap based generator
    // it's can be used to re-init a 'done' generator before it's get dropped
    pub fn init<F: FnOnce() -> T + 'a>(&mut self, f: F)
    where
        T: 'a,
    {
        // make sure the last one is finished
        if self.f.is_none() && self.context._ref == 0 {
            unsafe {
                self.cancel();
            }
        }

        // init ctx parent to itself, this would be the new top
        self.context.parent = &mut self.context;

        // init the ref to 0 means that it's ready to start
        self.context._ref = 0;
        let ret = &mut self.ret as *mut _;
        let contex = &mut self.context as *mut Context;
        // windows box::new is quite slow than unix
        self.f = Some(Box::new(move || {
            let r = f();
            let ret = unsafe { &mut *ret };
            let _ref = unsafe { (*contex)._ref };
            if _ref == 0xf {
                *ret = None; // this is a done return
            } else {
                *ret = Some(r); // normal return
            }
        }));

        let stk = &self.context.stack;
        self.context
            .regs
            .init_with(gen_init, 0, &mut self.f as *mut _ as *mut usize, stk);
    }

    /// resume the generator
    #[inline]
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        // get the current regs
        let cur = &mut env.top().regs;

        // switch to new context, always use the top ctx's reg
        // for normal generator self.context.parent == self.context
        // for coroutine self.context.parent == top generator context
        assert!(!self.context.parent.is_null());
        let top = unsafe { &mut *self.context.parent };

        // save current generator context on stack
        env.push_context(&mut self.context);

        // swap to the generator
        RegContext::swap(cur, &mut top.regs);

        // comes back, check the panic status
        // this would propagate the panic until root context
        // if it's a coroutine just stop propagate
        if !self.context.local_data.is_null() {
            return;
        }

        if let Some(err) = self.context.err.take() {
            // pass the error to the parent until root
            panic::resume_unwind(err);
        }
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }

    /// prepare the para that passed into generator before send
    #[inline]
    pub fn set_para(&mut self, para: A) {
        self.para = Some(para);
    }

    /// set the generator local data
    #[inline]
    pub fn set_local_data(&mut self, data: *mut u8) {
        self.context.local_data = data;
    }

    /// get the generator local data
    #[inline]
    pub fn get_local_data(&self) -> *mut u8 {
        self.context.local_data
    }

    /// get the generator panic data
    #[inline]
    pub fn get_panic_data(&mut self) -> Option<Box<Any + Send>> {
        self.context.err.take()
    }

    /// get the _ref pointer, this is used for coroutine cancel
    /// don't call this function for a normal generator!!
    #[inline]
    pub unsafe fn get_ref_ptr(&mut self) -> *mut u32 {
        &self.context._ref as *const _ as *mut _
    }

    /// resume the generator without touch the para
    /// you should call `set_para` before this method
    #[inline]
    pub fn resume(&mut self) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// `raw_send`
    #[inline]
    pub fn raw_send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        self.para = para;

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// send interface
    pub fn send(&mut self, para: A) -> T {
        let ret = self.raw_send(Some(para));
        ret.expect("send got None return")
    }

    /// cancel the generator without any check
    #[inline]
    unsafe fn raw_cancel(&mut self) {
        // tell the func to panic
        // so that we can stop the inner func
        self.context._ref = 2;
        // save the old panic hook, we don't want to print anything for the Cancel
        let old = ::std::panic::take_hook();
        ::std::panic::set_hook(Box::new(|_| {}));
        self.resume_gen();
        ::std::panic::set_hook(old);
    }

    /// cancel the generator
    /// this will trigger a Cancel panic, it's unsafe in that you must care about the resource
    pub unsafe fn cancel(&mut self) {
        if self.is_done() {
            return;
        }

        // consume the fun if it's not started
        if !self.is_started() {
            self.f.take();
            self.context._ref = 1;
        } else {
            self.raw_cancel();
        }
    }

    /// is finished
    #[inline]
    pub fn is_done(&self) -> bool {
        self.is_started() && (self.context._ref & 0x3) != 0
    }

    /// get stack total size and used size in word
    pub fn stack_usage(&self) -> (usize, usize) {
        (
            self.context.stack.size(),
            self.context.stack.get_used_size(),
        )
    }
}

impl<'a, A, T> Drop for GeneratorImpl<'a, A, T> {
    fn drop(&mut self) {
        // when the thread is already panic, do nothing
        if thread::panicking() {
            return;
        }

        if !self.is_started() {
            // not started yet, just drop the gen
            return;
        }

        if !self.is_done() {
            warn!("generator is not done while drop");
            unsafe { self.raw_cancel() }
        }

        assert!(self.is_done());

        let (total_stack, used_stack) = self.stack_usage();
        if used_stack < total_stack {
            // here we should record the stack in the class
            // next time will just use
            // set_stack_size::<F>(used_stack);
        } else {
            error!("stack overflow detected!");
            panic!(Error::StackErr);
        }
    }
}

impl<'a, T> Iterator for GeneratorImpl<'a, (), T> {
    type Item = T;
    // The 'Iterator' trait only requires the 'next' method to be defined. The
    // return type is 'Option<T>', 'None' is returned when the 'Iterator' is
    // over, otherwise the next value is returned wrapped in 'Some'
    fn next(&mut self) -> Option<T> {
        self.resume()
    }
}

impl<'a, A, T> fmt::Debug for GeneratorImpl<'a, A, T> {
    #[cfg(nightly)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::intrinsics::type_name;
        write!(
            f,
            "Generator<{}, Output={}> {{ ... }}",
            unsafe { type_name::<A>() },
            unsafe { type_name::<T>() }
        )
    }

    #[cfg(not(nightly))]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Generator {{ ... }}")
    }
}

/// the init function passed to reg_context
fn gen_init(_: usize, f: *mut usize) -> ! {
    let clo = move || {
        // consume self.f
        let f: &mut Option<Box<FnBox>> = unsafe { &mut *(f as *mut _) };
        let func = f.take().unwrap();
        func.call_box();
    };

    fn check_err(cause: Box<Any + Send + 'static>) {
        match cause.downcast_ref::<Error>() {
            // this is not an error at all, ignore it
            Some(_e @ &Error::Cancel) => return,
            _ => {}
        }
        error!("set panicked inside generator");
        ContextStack::current().top().err = Some(cause);
    }

    // we can't panic inside the generator context
    // need to propagate the panic to the main thread
    if let Err(cause) = panic::catch_unwind(clo) {
        check_err(cause);
    }

    yield_now();

    unreachable!("Should never comeback");
}
<commit_msg>:pencil: remove useless get_ref_ptr()<commit_after>//! # generator
//!
//! Rust generator implementation
//!

use std::fmt;
use std::panic;
use std::thread;
use std::any::Any;
use std::marker::PhantomData;

use scope::Scope;
use yield_::yield_now;
use rt::{Context, ContextStack, Error};
use reg_context::RegContext;

// default stack size, in usize
// windows has a minimal size as 0x4a8!!!!
pub const DEFAULT_STACK_SIZE: usize = 0x1000;

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    #[cfg_attr(feature = "cargo-clippy", allow(boxed_local))]
    fn call_box(self: Box<Self>) {
        self()
    }
}

/// Generator helper
pub struct Gn<A> {
    dummy: PhantomData<A>,
}

/// the generator type
pub type Generator<'a, A, T> = Box<GeneratorImpl<'a, A, T>>;
unsafe impl<A, T> Send for GeneratorImpl<'static, A, T> {}

impl<A> Gn<A> {
    /// create a scoped generator with default stack size
    pub fn new_scoped<'a, T, F>(f: F) -> Generator<'a, A, T>
    where
        F: FnOnce(Scope<A, T>) -> T + 'a,
        T: 'a,
        A: 'a,
    {
        Self::new_scoped_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a scoped generator with specified stack size
    pub fn new_scoped_opt<'a, T, F>(size: usize, f: F) -> Generator<'a, A, T>
    where
        F: FnOnce(Scope<A, T>) -> T + 'a,
        T: 'a,
        A: 'a,
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        let scope = g.get_scope();
        g.init(move || f(scope));
        g
    }
}

impl<A: Any> Gn<A> {
    /// create a new generator with default stack size
    pub fn new<'a, T: Any, F>(f: F) -> Generator<'a, A, T>
    where
        F: FnOnce() -> T + 'a,
    {
        Self::new_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a new generator with specified stack size
    pub fn new_opt<'a, T: Any, F>(size: usize, f: F) -> Generator<'a, A, T>
    where
        F: FnOnce() -> T + 'a,
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        g.init_context();
        g.init(f);
        g
    }
}

/// `GeneratorImpl`
pub struct GeneratorImpl<'a, A, T> {
    // run time context
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<Box<FnBox + 'a>>,
}

impl<'a, A: Any, T: Any> GeneratorImpl<'a, A, T> {
    /// create a new generator with default stack size
    pub fn init_context(&mut self) {
        self.context.para = &mut self.para as &mut Any;
        self.context.ret = &mut self.ret as &mut Any;
    }
}

impl<'a, A, T> GeneratorImpl<'a, A, T> {
    /// create a new generator with specified stack size
    pub fn new(size: usize) -> Box<Self> {
        Box::new(GeneratorImpl {
            para: None,
            ret: None,
            f: None,
            context: Context::new(size),
        })
    }

    /// prefech the generator into cache
    #[inline]
    pub fn prefetch(&self) {
        self.context.regs.prefetch();
    }

    /// get the scope object
    pub fn get_scope(&mut self) -> Scope<A, T> {
        Scope::new(&mut self.para, &mut self.ret)
    }

    /// init a heap based generator
    // it's can be used to re-init a 'done' generator before it's get dropped
    pub fn init<F: FnOnce() -> T + 'a>(&mut self, f: F)
    where
        T: 'a,
    {
        // make sure the last one is finished
        if self.f.is_none() && self.context._ref == 0 {
            unsafe {
                self.cancel();
            }
        }

        // init ctx parent to itself, this would be the new top
        self.context.parent = &mut self.context;

        // init the ref to 0 means that it's ready to start
        self.context._ref = 0;
        let ret = &mut self.ret as *mut _;
        let contex = &mut self.context as *mut Context;
        // windows box::new is quite slow than unix
        self.f = Some(Box::new(move || {
            let r = f();
            let ret = unsafe { &mut *ret };
            let _ref = unsafe { (*contex)._ref };
            if _ref == 0xf {
                *ret = None; // this is a done return
            } else {
                *ret = Some(r); // normal return
            }
        }));

        let stk = &self.context.stack;
        self.context
            .regs
            .init_with(gen_init, 0, &mut self.f as *mut _ as *mut usize, stk);
    }

    /// resume the generator
    #[inline]
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        // get the current regs
        let cur = &mut env.top().regs;

        // switch to new context, always use the top ctx's reg
        // for normal generator self.context.parent == self.context
        // for coroutine self.context.parent == top generator context
        assert!(!self.context.parent.is_null());
        let top = unsafe { &mut *self.context.parent };

        // save current generator context on stack
        env.push_context(&mut self.context);

        // swap to the generator
        RegContext::swap(cur, &mut top.regs);

        // comes back, check the panic status
        // this would propagate the panic until root context
        // if it's a coroutine just stop propagate
        if !self.context.local_data.is_null() {
            return;
        }

        if let Some(err) = self.context.err.take() {
            // pass the error to the parent until root
            panic::resume_unwind(err);
        }
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }

    /// prepare the para that passed into generator before send
    #[inline]
    pub fn set_para(&mut self, para: A) {
        self.para = Some(para);
    }

    /// set the generator local data
    #[inline]
    pub fn set_local_data(&mut self, data: *mut u8) {
        self.context.local_data = data;
    }

    /// get the generator local data
    #[inline]
    pub fn get_local_data(&self) -> *mut u8 {
        self.context.local_data
    }

    /// get the generator panic data
    #[inline]
    pub fn get_panic_data(&mut self) -> Option<Box<Any + Send>> {
        self.context.err.take()
    }

    /// resume the generator without touch the para
    /// you should call `set_para` before this method
    #[inline]
    pub fn resume(&mut self) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// `raw_send`
    #[inline]
    pub fn raw_send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        self.para = para;

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// send interface
    pub fn send(&mut self, para: A) -> T {
        let ret = self.raw_send(Some(para));
        ret.expect("send got None return")
    }

    /// cancel the generator without any check
    #[inline]
    unsafe fn raw_cancel(&mut self) {
        // tell the func to panic
        // so that we can stop the inner func
        self.context._ref = 2;
        // save the old panic hook, we don't want to print anything for the Cancel
        let old = ::std::panic::take_hook();
        ::std::panic::set_hook(Box::new(|_| {}));
        self.resume_gen();
        ::std::panic::set_hook(old);
    }

    /// cancel the generator
    /// this will trigger a Cancel panic, it's unsafe in that you must care about the resource
    pub unsafe fn cancel(&mut self) {
        if self.is_done() {
            return;
        }

        // consume the fun if it's not started
        if !self.is_started() {
            self.f.take();
            self.context._ref = 1;
        } else {
            self.raw_cancel();
        }
    }

    /// is finished
    #[inline]
    pub fn is_done(&self) -> bool {
        self.is_started() && (self.context._ref & 0x3) != 0
    }

    /// get stack total size and used size in word
    pub fn stack_usage(&self) -> (usize, usize) {
        (
            self.context.stack.size(),
            self.context.stack.get_used_size(),
        )
    }
}

impl<'a, A, T> Drop for GeneratorImpl<'a, A, T> {
    fn drop(&mut self) {
        // when the thread is already panic, do nothing
        if thread::panicking() {
            return;
        }

        if !self.is_started() {
            // not started yet, just drop the gen
            return;
        }

        if !self.is_done() {
            warn!("generator is not done while drop");
            unsafe { self.raw_cancel() }
        }

        assert!(self.is_done());

        let (total_stack, used_stack) = self.stack_usage();
        if used_stack < total_stack {
            // here we should record the stack in the class
            // next time will just use
            // set_stack_size::<F>(used_stack);
        } else {
            error!("stack overflow detected!");
            panic!(Error::StackErr);
        }
    }
}

impl<'a, T> Iterator for GeneratorImpl<'a, (), T> {
    type Item = T;
    // The 'Iterator' trait only requires the 'next' method to be defined. The
    // return type is 'Option<T>', 'None' is returned when the 'Iterator' is
    // over, otherwise the next value is returned wrapped in 'Some'
    fn next(&mut self) -> Option<T> {
        self.resume()
    }
}

impl<'a, A, T> fmt::Debug for GeneratorImpl<'a, A, T> {
    #[cfg(nightly)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::intrinsics::type_name;
        write!(
            f,
            "Generator<{}, Output={}> {{ ... }}",
            unsafe { type_name::<A>() },
            unsafe { type_name::<T>() }
        )
    }

    #[cfg(not(nightly))]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Generator {{ ... }}")
    }
}

/// the init function passed to reg_context
fn gen_init(_: usize, f: *mut usize) -> ! {
    let clo = move || {
        // consume self.f
        let f: &mut Option<Box<FnBox>> = unsafe { &mut *(f as *mut _) };
        let func = f.take().unwrap();
        func.call_box();
    };

    fn check_err(cause: Box<Any + Send + 'static>) {
        match cause.downcast_ref::<Error>() {
            // this is not an error at all, ignore it
            Some(_e @ &Error::Cancel) => return,
            _ => {}
        }
        error!("set panicked inside generator");
        ContextStack::current().top().err = Some(cause);
    }

    // we can't panic inside the generator context
    // need to propagate the panic to the main thread
    if let Err(cause) = panic::catch_unwind(clo) {
        check_err(cause);
    }

    yield_now();

    unreachable!("Should never comeback");
}
<|endoftext|>