<commit_before>use { CopyReadable, ConsumeReadable, LoadedVariable, Pushable, Index };
use liblua;

pub struct LuaTable<'lua> {
    variable: LoadedVariable<'lua>
}

// while the LuaTableIterator is active, the current key is constantly pushed over the table
pub struct LuaTableIterator<'lua, 'table> {
    table: &'table mut LuaTable<'lua>
}

impl<'lua> ConsumeReadable<'lua> for LuaTable<'lua> {
    fn read_from_variable(var: LoadedVariable<'lua>)
        -> Result<LuaTable<'lua>, LoadedVariable<'lua>>
    {
        if unsafe { liblua::lua_istable(var.lua.lua, -1) } {
            Ok(LuaTable{ variable: var })
        } else {
            Err(var)
        }
    }
}

impl<'lua> LuaTable<'lua> {
    pub fn iter<'me>(&'me mut self)
        -> LuaTableIterator<'lua, 'me>
    {
        unsafe { liblua::lua_pushnil(self.variable.lua.lua) };
        LuaTableIterator { table: self }
    }

    pub fn get<R: CopyReadable, I: Index>(&mut self, index: I) -> Option<R> {
        index.push_to_lua(self.variable.lua);
        unsafe { liblua::lua_gettable(self.variable.lua.lua, -2); }
        let value = CopyReadable::read_from_lua(self.variable.lua, -1);
        unsafe { liblua::lua_pop(self.variable.lua.lua, 1); }
        value
    }

    pub fn set<I: Index, V: Pushable>(&mut self, index: I, value: V) {
        index.push_to_lua(self.variable.lua);
        value.push_to_lua(self.variable.lua);
        unsafe { liblua::lua_settable(self.variable.lua.lua, -3); }
    }
}

impl<'a, 'b, K: CopyReadable, V: CopyReadable> Iterator<Option<(K,V)>> for LuaTableIterator<'a, 'b> {
    fn next(&mut self)
        -> Option<Option<(K,V)>>
    {
        // this call pushes the next key and value on the stack
        if unsafe { liblua::lua_next(self.table.variable.lua.lua, -2) } == 0 {
            return None
        }

        let key = CopyReadable::read_from_lua(self.table.variable.lua, -2);
        let value = CopyReadable::read_from_lua(self.table.variable.lua, -1);

        // removing the value, leaving only the key on the top of the stack
        unsafe { liblua::lua_pop(self.table.variable.lua.lua, 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

// TODO: this destructor crashes the compiler
/*impl<'a, 'b> Drop for LuaTableIterator<'a, 'b> {
    fn drop(&mut self) {
        unsafe { liblua::lua_pop(self.table.variable.lua.lua, 1) }
    }
}*/

#[cfg(test)]
mod tests {
    use Lua;
    use lua_tables::LuaTable;

    #[test]
    fn iterable() {
        let mut lua = Lua::new();

        let _:() = lua.execute("a = { 9, 8, 7 }").unwrap();

        let mut table: LuaTable = lua.get("a").unwrap();
        let mut counter = 0u;

        for (key, value) in table.iter().filter_map(|e| e) {
            let _: uint = key;
            let _: uint = value;
            assert_eq!(key + value, 10);
            counter += 1;
        }

        assert_eq!(counter, 3);
    }

    #[test]
    fn iterable_multipletimes() {
        let mut lua = Lua::new();

        let _:() = lua.execute("a = { 9, 8, 7 }").unwrap();

        let mut table: LuaTable = lua.get("a").unwrap();

        for _ in range(0u, 10) {
            let tableContent: Vec<Option<(uint, uint)>> = table.iter().collect();
            assert_eq!(tableContent, vec!( Some((1,9)), Some((2,8)), Some((3,7)) ));
        }
    }

    #[test]
    fn get_set() {
        let mut lua = Lua::new();

        let _:() = lua.execute("a = { 9, 8, 7 }").unwrap();
        let mut table: LuaTable = lua.get("a").unwrap();

        let x: int = table.get(2i).unwrap();
        assert_eq!(x, 8);

        table.set(3i, "hello");
        let y: String = table.get(3i).unwrap();
        assert_eq!(y.as_slice(), "hello");

        let z: int = table.get(1i).unwrap();
        assert_eq!(z, 9);
    }
}
<commit_msg>Add support for metatables for LuaTable<commit_after>use { CopyReadable, ConsumeReadable, LoadedVariable, Pushable, Index };
use liblua;

pub struct LuaTable<'lua> {
    variable: LoadedVariable<'lua>
}

// while the LuaTableIterator is active, the current key is constantly pushed over the table
pub struct LuaTableIterator<'lua, 'table> {
    table: &'table mut LuaTable<'lua>
}

impl<'lua> ConsumeReadable<'lua> for LuaTable<'lua> {
    fn read_from_variable(var: LoadedVariable<'lua>)
        -> Result<LuaTable<'lua>, LoadedVariable<'lua>>
    {
        if unsafe { liblua::lua_istable(var.lua.lua, -1) } {
            Ok(LuaTable{ variable: var })
        } else {
            Err(var)
        }
    }
}

impl<'lua> LuaTable<'lua> {
    pub fn iter<'me>(&'me mut self)
        -> LuaTableIterator<'lua, 'me>
    {
        unsafe { liblua::lua_pushnil(self.variable.lua.lua) };
        LuaTableIterator { table: self }
    }

    pub fn get<R: CopyReadable, I: Index>(&mut self, index: I) -> Option<R> {
        index.push_to_lua(self.variable.lua);
        unsafe { liblua::lua_gettable(self.variable.lua.lua, -2); }
        let value = CopyReadable::read_from_lua(self.variable.lua, -1);
        unsafe { liblua::lua_pop(self.variable.lua.lua, 1); }
        value
    }

    pub fn set<I: Index, V: Pushable>(&mut self, index: I, value: V) {
        index.push_to_lua(self.variable.lua);
        value.push_to_lua(self.variable.lua);
        unsafe { liblua::lua_settable(self.variable.lua.lua, -3); }
    }

    // Obtains or create the metatable of the table
    pub fn get_or_create_metatable(self) -> LuaTable<'lua> {
        let result = unsafe { liblua::lua_getmetatable(self.variable.lua.lua, -1) };

        if result == 0 {
            unsafe {
                liblua::lua_newtable(self.variable.lua.lua);
                liblua::lua_setmetatable(self.variable.lua.lua, -2);
                let r = liblua::lua_getmetatable(self.variable.lua.lua, -1);
                assert!(r != 0);
            }
        }

        LuaTable { variable: LoadedVariable { lua: self.variable.lua, size: self.variable.size + 1 } }
    }
}

impl<'a, 'b, K: CopyReadable, V: CopyReadable> Iterator<Option<(K,V)>> for LuaTableIterator<'a, 'b> {
    fn next(&mut self)
        -> Option<Option<(K,V)>>
    {
        // this call pushes the next key and value on the stack
        if unsafe { liblua::lua_next(self.table.variable.lua.lua, -2) } == 0 {
            return None
        }

        let key = CopyReadable::read_from_lua(self.table.variable.lua, -2);
        let value = CopyReadable::read_from_lua(self.table.variable.lua, -1);

        // removing the value, leaving only the key on the top of the stack
        unsafe { liblua::lua_pop(self.table.variable.lua.lua, 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

// TODO: this destructor crashes the compiler
/*impl<'a, 'b> Drop for LuaTableIterator<'a, 'b> {
    fn drop(&mut self) {
        unsafe { liblua::lua_pop(self.table.variable.lua.lua, 1) }
    }
}*/

#[cfg(test)]
mod tests {
    use Lua;
    use lua_tables::LuaTable;

    #[test]
    fn iterable() {
        let mut lua = Lua::new();

        let _:() = lua.execute("a = { 9, 8, 7 }").unwrap();

        let mut table: LuaTable = lua.get("a").unwrap();
        let mut counter = 0u;

        for (key, value) in table.iter().filter_map(|e| e) {
            let _: uint = key;
            let _: uint = value;
            assert_eq!(key + value, 10);
            counter += 1;
        }

        assert_eq!(counter, 3);
    }

    #[test]
    fn iterable_multipletimes() {
        let mut lua = Lua::new();

        let _:() = lua.execute("a = { 9, 8, 7 }").unwrap();

        let mut table: LuaTable = lua.get("a").unwrap();

        for _ in range(0u, 10) {
            let tableContent: Vec<Option<(uint, uint)>> = table.iter().collect();
            assert_eq!(tableContent, vec!( Some((1,9)), Some((2,8)), Some((3,7)) ));
        }
    }

    #[test]
    fn get_set() {
        let mut lua = Lua::new();

        let _:() = lua.execute("a = { 9, 8, 7 }").unwrap();
        let mut table: LuaTable = lua.get("a").unwrap();

        let x: int = table.get(2i).unwrap();
        assert_eq!(x, 8);

        table.set(3i, "hello");
        let y: String = table.get(3i).unwrap();
        assert_eq!(y.as_slice(), "hello");

        let z: int = table.get(1i).unwrap();
        assert_eq!(z, 9);
    }

    #[test]
    fn metatable() {
        let mut lua = Lua::new();

        let _:() = lua.execute("a = { 9, 8, 7 }").unwrap();

        {
            let table: LuaTable = lua.get("a").unwrap();

            let mut metatable = table.get_or_create_metatable();
            fn handler() -> int { 5 };
            metatable.set("__add".to_string(), handler);
        }

        let r: int = lua.execute("return a + a").unwrap();
        assert_eq!(r, 5);
    }
}
<|endoftext|>


<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::io;                           // Error
use std::io::{Read,BufReader,BufRead}; // read_to_string
use std::path::Path;
use std::num;                          // ParseIntError
use std::fmt;                          // Formatter, format!, Display, Debug, write!
use std::error;
use std::fs::File;                     // File, open
use std::result;
use self::itertools::Itertools;        // fold_results

use nfa::core::{NFA,NFABuilder,NFAError,NFABuilding};

/// Type `NFAReaderError` describes the list of errors that can occur during
/// the parsing of a NFA file.
#[derive(Debug)]
pub enum NFAReaderError {
    /// Error `MissingStartingState` means the file does not contains the starting state.
    MissingStartingState,
    /// Error `MissingFinalStates` means the file does not contains the list of final states.
    MissingFinalStates,
    /// Error `IncompleteTransition` means the transition on the specified line does not contain
    /// one of these elements: symbol, source state, destination state.
    IncompleteTransition(usize),
    /// Error `IllformedTransition` means the transition contains to much elements or that
    /// the symbole is composed with modre than two characters.
    IllformedTransition(usize),
    /// Error `NFA` encapsules the error specific to the NFA building process (no final
    /// states,...).
    NFA(NFAError,usize),
    /// Error `Io` is relative to the input errors (the file does not exist, the file can not be
    /// read,...à.
    Io(io::Error),
    /// Error `Parse` is relative to the parsing errors (a state is an intger).
    Parse(num::ParseIntError,usize),
}

impl fmt::Display for NFAReaderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            NFAReaderError::Io(ref err) => write!(f, "IO error: {}", err),
            NFAReaderError::MissingStartingState => write!(f, "The file is empty or only contains white characters."),
            NFAReaderError::MissingFinalStates => write!(f, "The file does not specify the list of final states."),
            NFAReaderError::IncompleteTransition(ref line) => write!(f, "Line {}: missing the src or the dest state.", line),
            NFAReaderError::IllformedTransition(ref line) => write!(f, "Line {}: too much elements.", line),
            NFAReaderError::NFA(ref err,ref line) => write!(f, "Line {}: NFAError {}", line, err),
            NFAReaderError::Parse(ref err,ref line) => write!(f, "Line {}: parse error {}", line, err),
        }
    }
}

impl error::Error for NFAReaderError {
    fn description(&self) -> &str {
        match *self {
            NFAReaderError::Io(ref err) => err.description(),
            NFAReaderError::MissingStartingState => "The file is empty or only contains white characters.",
            NFAReaderError::MissingFinalStates => "The file does not specify the list of final states.",
            NFAReaderError::IncompleteTransition(_) => "Missing the src or the dest state.",
            NFAReaderError::IllformedTransition(_) => "Too much elements.",
            NFAReaderError::NFA(ref err,_) => err.description(),
            NFAReaderError::Parse(ref err,_) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            NFAReaderError::Io(ref err) => Some(err),
            NFAReaderError::Parse(ref err,_) => Some(err),
            NFAReaderError::NFA(ref err,_) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for NFAReaderError {
    fn from(err: io::Error) -> NFAReaderError {
        NFAReaderError::Io(err)
    }
}

impl From<num::ParseIntError> for NFAReaderError {
    fn from(err: num::ParseIntError) -> NFAReaderError {
        NFAReaderError::Parse(err,0)
    }
}

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

/// Struct `NFAReader` is an empty structure that builds a `NFA` from a file
/// or from a `&str`.
pub struct NFAReader;

impl NFAReader {
    fn parse_nfa_error(contents: &str, line: usize) -> Result<usize> {
            contents.parse::<usize>()
                    .map_err(|e| NFAReaderError::Parse(e,line))
    }

    /// Reads a NFA from a file.
    ///
    /// # Description
    ///
    /// * `file_path` - The path to the file that contains the NFA.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate automata;
    ///
    /// use automata::nfa::reader::*;
    /// use std::error::Error;
    ///
    /// fn main() {
    ///     let nfa = NFAReader::new_from_file("nfa.txt");
    ///     match nfa {
    ///         Ok(nfa) => {
    ///            // Do stuff with the nfa
    ///         },
    ///         Err(e) => println!("{}", e),
    ///     }
    /// }
    /// ```
    pub fn new_from_file<P: AsRef<Path>>(file_path: P) -> Result<NFA> {
        let file = try!(File::open(file_path));
        let file = BufReader::new(file);
        NFAReader::new_from_lines(&mut file.lines())
    }

    fn read_start(nfa: NFABuilder, lines : &mut Iterator<Item=(usize,io::Result<String>)>) -> Result<NFABuilder> {
        let (nline,line) = try!(lines.next().ok_or(NFAReaderError::MissingStartingState));
        let line = try!(line);
        let start = try!(NFAReader::parse_nfa_error(&line,nline));
        let nfa = nfa.add_start(start);
        match nfa {
            Ok(nfa) => Ok(nfa),
            Err(e) => Err(NFAReaderError::NFA(e,nline)),
        }
    }

    fn read_finals(nfa: NFABuilder, lines : &mut Iterator<Item=(usize,io::Result<String>)>) -> Result<NFABuilder> {
        let (nline,line) = try!(lines.next().ok_or(NFAReaderError::MissingFinalStates));
        let line = try!(line);
        let nfa = try!(try!(line
            .split_whitespace()
            .map(|token| NFAReader::parse_nfa_error(token,nline))
            .fold_results(Ok(nfa), |acc, elt| acc.add_final(elt)))
            .map_err(|e| NFAReaderError::NFA(e,nline)));
        Ok(nfa)
    }

    fn read_transition(nfa: NFABuilder, line : (usize,io::Result<String>))-> Result<NFABuilder> {
        let (nline,line) = line;
        let line = try!(line);
        let mut tokens = line.split_whitespace();
        // can't fail because lines iterates over the non-empty line
        let mut symbs = tokens.next().unwrap().chars();
        let symb = symbs.nth(0).unwrap();
        if symbs.next().is_some() {
            return Err(NFAReaderError::IllformedTransition(nline));
        }
        let src = try!(tokens
            .next()
            .ok_or(NFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| NFAReader::parse_nfa_error(contents,nline)));
        let dest = try!(tokens
            .next()
            .ok_or(NFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| NFAReader::parse_nfa_error(contents,nline)));
        if tokens.next().is_some() {
            return Err(NFAReaderError::IllformedTransition(nline));
        }
        let nfa = try!(nfa.add_transition(symb,src,dest).map_err(|e| NFAReaderError::NFA(e,nline)));;
        Ok(nfa)
    }

    fn new_from_lines(lines : &mut Iterator<Item=io::Result<String>>) -> Result<NFA> {
        let mut nfa = try!(NFABuilder::new().map_err(|e| NFAReaderError::NFA(e,0)));
        let mut lines = lines
            .map(|line| {
                line.and_then(|contents| Ok(contents.split('#').nth(0).unwrap().trim().to_owned()))
            })
            .enumerate().map(|(nline,line)| (nline+1,line))
            .filter(|&(_,ref line)| {
                // Mandatory otherwise unwrap will take the ownership of the String
                let line = line.as_ref();
                line.is_err() || !line.unwrap().is_empty()
            });
        nfa = try!(NFAReader::read_start(nfa, &mut lines));
        nfa = try!(NFAReader::read_finals(nfa, &mut lines));
        for line in lines {
            nfa = try!(NFAReader::read_transition(nfa, line));
        }
        nfa.finalize().map_err(|e| NFAReaderError::NFA(e,0))
    }

    /// Reads a NFA from a `&str`.
    ///
    /// # Description
    ///
    /// * `nfa` - The string representation of the NFA.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate automata;
    ///
    /// use automata::nfa::reader::*;
    /// use std::error::Error;
    ///
    /// fn main() {
    ///     // (abc)*
    ///     let nfa =
    ///         "0 1\n\
    ///          0 3\n\
    ///          a 0 1\n\
    ///          b 1 2\n\
    ///          c 2 3\n\
    ///          a 3 0";
    ///     let nfa = NFAReader::new_from_string(nfa);
    ///     match nfa {
    ///         Ok(nfa) => {
    ///            // Do stuff with the nfa
    ///         },
    ///         Err(e) => println!("{}", e),
    ///     }
    /// }
    /// ```
    pub fn new_from_string(nfa: &str) -> Result<NFA> {
        NFAReader::new_from_lines(&mut nfa.lines().map(|line| Ok(line.to_string())))
    }
}

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

    #[test]
    fn test_empty_file() {
        let model =
            "";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::MissingStartingState) => assert!(true),
            _ => assert!(false, "MissingStartingState expected."),
        }
    }

    #[test]
    fn test_start_not_a_number() {
        let model =
            "a";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::Parse(_,line)) => assert!(line == 1),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_many_starts() {
        let model =
            "0 1\n\
             3\n\
             a 0 1\n\
             c 0 3\n\
             b 1 2\n\
             a 2 1\n\
             c 2 3";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::Parse(_,line)) => assert!(line == 1),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_no_finals() {
        let model =
            "1\n\
            ";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::MissingFinalStates) => assert!(true),
            _ => assert!(false, "MissingFinalStates expected."),
        }
    }

    #[test]
    fn test_finals_not_a_number() {
        let model =
            "1\n\
             2 a 3";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::Parse(_,line)) => assert!(line == 2),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_no_transistions() {
        let model =
            "0\n\
             3";
        let _nfa = NFAReader::new_from_string(&model).unwrap();
    }

    #[test]
    fn test_transitions_with_at_least_four_elements() {
        let model =
            "0\n\
             3\n\
             a 0 1 8";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::IllformedTransition(line)) => assert!(line == 3),
            _ => assert!(false, "IllformedTransition expected."),
        }
    }

    #[test]
    fn test_transitions_start_with_at_least_two_chars() {
        let model =
            "0\n\
             3\n\
             ab 2 3";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::IllformedTransition(line)) => assert!(line == 3),
            _ => assert!(false, "IllformedTransition expected."),
        }
    }

    #[test]
    fn test_transitions_with_src_not_a_number() {
        let model =
            "0\n\
             3\n\
             c b 3";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::Parse(_,line)) => assert!(line == 3),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_transitions_with_dest_not_a_number() {
        let model =
            "0\n\
             3\n\
             c 2 b";
        match NFAReader::new_from_string(model) {
            Err(NFAReaderError::Parse(_,line)) => assert!(line == 3),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_read_from_fake_file() {
        let file = "fake.txt";
        match NFAReader::new_from_file(file) {
            Err(NFAReaderError::Io(_)) => assert!(true),
            _ => assert!(false, "Io::Error expected."),
        }
    }
}
<commit_msg>NFA reader<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::io;                           // Error
use std::io::{Read,BufReader,BufRead}; // read_to_string
use std::path::Path;
use std::num;                          // ParseIntError
use std::fmt;                          // Formatter, format!, Display, Debug, write!
use std::error;
use std::fs::File;                     // File, open
use std::result;
use self::itertools::Itertools;        // fold_results

use e_nfa::core::{ENFA,ENFABuilder,ENFAError,ENFABuilding};

/// Type `ENFAReaderError` describes the list of errors that can occur during
/// the parsing of a ENFA file.
#[derive(Debug)]
pub enum ENFAReaderError {
    /// Error `MissingStartingState` means the file does not contains the starting state.
    MissingStartingState,
    /// Error `MissingFinalStates` means the file does not contains the list of final states.
    MissingFinalStates,
    /// Error `IncompleteTransition` means the transition on the specified line does not contain
    /// one of these elements: symbol, source state, destination state.
    IncompleteTransition(usize),
    /// Error `IllformedTransition` means the transition contains to much elements or that
    /// the symbole is composed with modre than two characters.
    IllformedTransition(usize),
    /// Error `ENFA` encapsules the error specific to the ENFA building process (no final
    /// states,...).
    ENFA(ENFAError,usize),
    /// Error `Io` is relative to the input errors (the file does not exist, the file can not be
    /// read,...à.
    Io(io::Error),
    /// Error `Parse` is relative to the parsing errors (a state is an intger).
    Parse(num::ParseIntError,usize),
}

impl fmt::Display for ENFAReaderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ENFAReaderError::Io(ref err) => write!(f, "IO error: {}", err),
            ENFAReaderError::MissingStartingState => write!(f, "The file is empty or only contains white characters."),
            ENFAReaderError::MissingFinalStates => write!(f, "The file does not specify the list of final states."),
            ENFAReaderError::IncompleteTransition(ref line) => write!(f, "Line {}: missing the src or the dest state.", line),
            ENFAReaderError::IllformedTransition(ref line) => write!(f, "Line {}: too much elements.", line),
            ENFAReaderError::ENFA(ref err,ref line) => write!(f, "Line {}: ENFAError {}", line, err),
            ENFAReaderError::Parse(ref err,ref line) => write!(f, "Line {}: parse error {}", line, err),
        }
    }
}

impl error::Error for ENFAReaderError {
    fn description(&self) -> &str {
        match *self {
            ENFAReaderError::Io(ref err) => err.description(),
            ENFAReaderError::MissingStartingState => "The file is empty or only contains white characters.",
            ENFAReaderError::MissingFinalStates => "The file does not specify the list of final states.",
            ENFAReaderError::IncompleteTransition(_) => "Missing the src or the dest state.",
            ENFAReaderError::IllformedTransition(_) => "Too much elements.",
            ENFAReaderError::ENFA(ref err,_) => err.description(),
            ENFAReaderError::Parse(ref err,_) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ENFAReaderError::Io(ref err) => Some(err),
            ENFAReaderError::Parse(ref err,_) => Some(err),
            ENFAReaderError::ENFA(ref err,_) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for ENFAReaderError {
    fn from(err: io::Error) -> ENFAReaderError {
        ENFAReaderError::Io(err)
    }
}

impl From<num::ParseIntError> for ENFAReaderError {
    fn from(err: num::ParseIntError) -> ENFAReaderError {
        ENFAReaderError::Parse(err,0)
    }
}

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

/// Struct `ENFAReader` is an empty structure that builds a `ENFA` from a file
/// or from a `&str`.
pub struct ENFAReader;

impl ENFAReader {
    fn parse_nfa_error(contents: &str, line: usize) -> Result<usize> {
            contents.parse::<usize>()
                    .map_err(|e| ENFAReaderError::Parse(e,line))
    }

    /// Reads a ENFA from a file.
    ///
    /// # Description
    ///
    /// * `file_path` - The path to the file that contains the ENFA.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate automata;
    ///
    /// use automata::nfa::reader::*;
    /// use std::error::Error;
    ///
    /// fn main() {
    ///     let nfa = ENFAReader::new_from_file("nfa.txt");
    ///     match nfa {
    ///         Ok(nfa) => {
    ///            // Do stuff with the nfa
    ///         },
    ///         Err(e) => println!("{}", e),
    ///     }
    /// }
    /// ```
    pub fn new_from_file<P: AsRef<Path>>(file_path: P) -> Result<ENFA> {
        let file = try!(File::open(file_path));
        let file = BufReader::new(file);
        ENFAReader::new_from_lines(&mut file.lines())
    }

    fn read_start(nfa: ENFABuilder, lines : &mut Iterator<Item=(usize,io::Result<String>)>) -> Result<ENFABuilder> {
        let (nline,line) = try!(lines.next().ok_or(ENFAReaderError::MissingStartingState));
        let line = try!(line);
        let start = try!(ENFAReader::parse_nfa_error(&line,nline));
        let nfa = nfa.add_start(start);
        match nfa {
            Ok(nfa) => Ok(nfa),
            Err(e) => Err(ENFAReaderError::ENFA(e,nline)),
        }
    }

    fn read_finals(nfa: ENFABuilder, lines : &mut Iterator<Item=(usize,io::Result<String>)>) -> Result<ENFABuilder> {
        let (nline,line) = try!(lines.next().ok_or(ENFAReaderError::MissingFinalStates));
        let line = try!(line);
        let nfa = try!(try!(line
            .split_whitespace()
            .map(|token| ENFAReader::parse_nfa_error(token,nline))
            .fold_results(Ok(nfa), |acc, elt| acc.add_final(elt)))
            .map_err(|e| ENFAReaderError::ENFA(e,nline)));
        Ok(nfa)
    }

    // TODO swap order line <=> nline
    fn read_complete_transition(nfa: ENFABuilder, line : String, nline: usize) -> Result<ENFABuilder> {
        let mut tokens = line.split_whitespace();
        // can't fail because lines iterates over the non-empty line
        let mut symbs = tokens.next().unwrap().chars();
        let symb = symbs.nth(0).unwrap();
        if symbs.next().is_some() {
            return Err(ENFAReaderError::IllformedTransition(nline));
        }
        let src = try!(tokens
            .next()
            .ok_or(ENFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| ENFAReader::parse_nfa_error(contents,nline)));
        let dest = try!(tokens
            .next()
            .ok_or(ENFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| ENFAReader::parse_nfa_error(contents,nline)));
        if tokens.next().is_some() {
            return Err(ENFAReaderError::IllformedTransition(nline));
        }
        let nfa = try!(nfa.add_transition(symb,src,dest).map_err(|e| ENFAReaderError::ENFA(e,nline)));;
        Ok(nfa)
    }

    // TODO swap order line <=> nline
    fn read_e_transition(nfa: ENFABuilder, line : String, nline: usize) -> Result<ENFABuilder> {
        let mut tokens = line.split_whitespace();
        let src = try!(tokens
            .next()
            .ok_or(ENFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| ENFAReader::parse_nfa_error(contents,nline)));
        let dest = try!(tokens
            .next()
            .ok_or(ENFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| ENFAReader::parse_nfa_error(contents,nline)));
        if tokens.next().is_some() {
            return Err(ENFAReaderError::IllformedTransition(nline));
        }
        let nfa = try!(nfa.add_e_transition(src,dest).map_err(|e| ENFAReaderError::ENFA(e,nline)));;
        Ok(nfa)
    }

    fn read_transition(nfa: ENFABuilder, line : (usize,io::Result<String>))-> Result<ENFABuilder> {
        let (nline,line) = line;
        let line = try!(line);
        match line.split_whitespace().count() {
            3 => ENFAReader::read_complete_transition(nfa, line, nline),
            2 => ENFAReader::read_e_transition(nfa, line, nline),
            _ => unimplemented!()
        }
    }

    fn new_from_lines(lines : &mut Iterator<Item=io::Result<String>>) -> Result<ENFA> {
        let mut nfa = try!(ENFABuilder::new().map_err(|e| ENFAReaderError::ENFA(e,0)));
        let mut lines = lines
            .map(|line| {
                line.and_then(|contents| Ok(contents.split('#').nth(0).unwrap().trim().to_owned()))
            })
            .enumerate().map(|(nline,line)| (nline+1,line))
            .filter(|&(_,ref line)| {
                // Mandatory otherwise unwrap will take the ownership of the String
                let line = line.as_ref();
                line.is_err() || !line.unwrap().is_empty()
            });
        nfa = try!(ENFAReader::read_start(nfa, &mut lines));
        nfa = try!(ENFAReader::read_finals(nfa, &mut lines));
        for line in lines {
            nfa = try!(ENFAReader::read_transition(nfa, line));
        }
        nfa.finalize().map_err(|e| ENFAReaderError::ENFA(e,0))
    }

    /// Reads a ENFA from a `&str`.
    ///
    /// # Description
    ///
    /// * `nfa` - The string representation of the ENFA.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate automata;
    ///
    /// use automata::nfa::reader::*;
    /// use std::error::Error;
    ///
    /// fn main() {
    ///     // (abc)*
    ///     let nfa =
    ///         "0 1\n\
    ///          0 3\n\
    ///          a 0 1\n\
    ///          b 1 2\n\
    ///          c 2 3\n\
    ///          a 3 0";
    ///     let nfa = ENFAReader::new_from_string(nfa);
    ///     match nfa {
    ///         Ok(nfa) => {
    ///            // Do stuff with the nfa
    ///         },
    ///         Err(e) => println!("{}", e),
    ///     }
    /// }
    /// ```
    pub fn new_from_string(nfa: &str) -> Result<ENFA> {
        ENFAReader::new_from_lines(&mut nfa.lines().map(|line| Ok(line.to_string())))
    }
}

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

    #[test]
    fn test_empty_file() {
        let model =
            "";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::MissingStartingState) => assert!(true),
            _ => assert!(false, "MissingStartingState expected."),
        }
    }

    #[test]
    fn test_start_not_a_number() {
        let model =
            "a";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::Parse(_,line)) => assert!(line == 1),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_many_starts() {
        let model =
            "0 1\n\
             3\n\
             a 0 1\n\
             c 0 3\n\
             b 1 2\n\
             a 2 1\n\
             c 2 3";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::Parse(_,line)) => assert!(line == 1),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_no_finals() {
        let model =
            "1\n\
            ";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::MissingFinalStates) => assert!(true),
            _ => assert!(false, "MissingFinalStates expected."),
        }
    }

    #[test]
    fn test_finals_not_a_number() {
        let model =
            "1\n\
             2 a 3";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::Parse(_,line)) => assert!(line == 2),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_no_transistions() {
        let model =
            "0\n\
             3";
        let _nfa = ENFAReader::new_from_string(&model).unwrap();
    }

    #[test]
    fn test_transitions_with_at_least_four_elements() {
        let model =
            "0\n\
             3\n\
             a 0 1 8";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::IllformedTransition(line)) => assert!(line == 3),
            _ => assert!(false, "IllformedTransition expected."),
        }
    }

    #[test]
    fn test_transitions_start_with_at_least_two_chars() {
        let model =
            "0\n\
             3\n\
             ab 2 3";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::IllformedTransition(line)) => assert!(line == 3),
            _ => assert!(false, "IllformedTransition expected."),
        }
    }

    #[test]
    fn test_transitions_with_src_not_a_number() {
        let model =
            "0\n\
             3\n\
             c b 3";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::Parse(_,line)) => assert!(line == 3),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_transitions_with_dest_not_a_number() {
        let model =
            "0\n\
             3\n\
             c 2 b";
        match ENFAReader::new_from_string(model) {
            Err(ENFAReaderError::Parse(_,line)) => assert!(line == 3),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_read_from_fake_file() {
        let file = "fake.txt";
        match ENFAReader::new_from_file(file) {
            Err(ENFAReaderError::Io(_)) => assert!(true),
            _ => assert!(false, "Io::Error expected."),
        }
    }
}
<|endoftext|>


<commit_before>use header::HeaderList;
use header::Header;
use header::ContentLength;
use header::StompHeaderSet;
use subscription::AckMode;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::InvalidInput;
use std::io::Write;
use std::io::Read;
use std::io::BufRead;
use std::str::from_utf8;
use std::fmt;
use std::fmt::Formatter;
use frame::{Frame, Transmission};

pub struct FrameBuffer {
  buffer: Vec<u8>,
  parse_state: ParseState
}

#[derive(Clone, Copy)]
struct ByteRange {
  pub start: u32,
  pub end : u32
}

struct ParseState {
  offset: u32,
  command_range: Option<ByteRange>,
  header_ranges: Vec<ByteRange>,
  body_range: Option<ByteRange>,
  section: FrameSection,
}

impl ParseState {
  fn new() -> ParseState {
    ParseState {
      offset: 0,
      command_range: None,
      header_ranges: Vec::new(),
      body_range: None,
      section: FrameSection::Command
    }
  }
}

enum FrameSection {
  Command,
  Headers,
  Body
}

enum ReadCommandResult {
  HeartBeat,
  Command(ByteRange),
  Incomplete
}

enum ReadHeaderResult {
  Header(ByteRange),
  EndOfHeaders,
  Incomplete
}

enum ReadBodyResult {
  Body(ByteRange),
  Incomplete
}

impl FrameBuffer {
  pub fn new() -> FrameBuffer {
    FrameBuffer {
      buffer: Vec::with_capacity(512),
      parse_state: ParseState::new()
    }
  }

  pub fn append(&mut self, bytes: &[u8]) { // TODO: Return result?
    self.buffer.push_all(bytes);
  }

  pub fn read_transmission(&mut self) -> Option<Transmission> {
    match self.parse_state.section {
      FrameSection::Command => self.resume_parsing_at_command(),
      FrameSection::Headers => self.resume_parsing_at_headers(),
      FrameSection::Body    => self.resume_parsing_at_body()
    }
  }

  fn resume_parsing_at_command(&mut self) -> Option<Transmission> {
    debug!("Parsing command.");
    match self.read_command() {
      ReadCommandResult::HeartBeat => Some(Transmission::HeartBeat),
      ReadCommandResult::Command(byte_range) => {
        self.parse_state.command_range = Some(byte_range);
        self.parse_state.section = FrameSection::Headers;
        self.resume_parsing_at_headers()
      },
      ReadCommandResult::Incomplete => None
    }
  }

  fn resume_parsing_at_headers(&mut self) -> Option<Transmission> {
    debug!("Parsing headers.");
    match self.read_header() {
      ReadHeaderResult::Header(byte_range) => {
        self.parse_state.header_ranges.push(byte_range);
        self.resume_parsing_at_headers()
      },
      ReadHeaderResult::EndOfHeaders => {
        self.parse_state.section = FrameSection::Body;
        self.resume_parsing_at_body()
      },
      ReadHeaderResult::Incomplete => None
    }
  }

  fn resume_parsing_at_body(&mut self) -> Option<Transmission> {
    debug!("Parsing body.");
    match self.read_body() {
      ReadBodyResult::Body(byte_range) => {
        self.parse_state.body_range = Some(byte_range);
        let frame = Frame {
          command: self.create_command_string(),
          headers: self.create_header_list(),
          body: self.create_body()
        };
        self.reset_parse_state();
        Some(Transmission::CompleteFrame(frame))
      },
      ReadBodyResult::Incomplete => None
    }
  }

  fn reset_parse_state(&mut self) {
    self.parse_state.offset = 0;
    self.parse_state.command_range = None;
    self.parse_state.header_ranges.clear();
    self.parse_state.body_range = None;
    self.parse_state.section = FrameSection::Command;
  }

  fn create_command_string(&mut self) -> String {
    let buffer : &[u8] = self.buffer.as_ref();
    let command_range = self.parse_state.command_range.expect("No command range was found.");
    let start = command_range.start;
    let end = command_range.end;
    let command_slice = &buffer[start as usize..end as usize];
    let command_str : &str = match from_utf8(&command_slice) {
      Ok(command_str) => command_str,
      _ =>panic!("Command was not utf8.")
    };
    return command_str.to_string();
  }

  fn create_header_list(&mut self) -> HeaderList {
    let buffer : &[u8] = self.buffer.as_ref();
    let mut header_list = header_list![];
    for header_range in &self.parse_state.header_ranges {
      let start = header_range.start;
      let end = header_range.end;
      let header_slice = &buffer[start as usize..end as usize];
      let header_str : &str = match from_utf8(&header_slice) {
        Ok(header_str) => header_str,
        _ =>panic!("Header was not utf8.")
      };
      let header = Header::decode_string(header_str);
      match header {
        Some(header) => header_list.push(header),
        None => panic!("Header was not decodable.")
      }
    }
    header_list
  }

  fn create_body(&mut self) -> Vec<u8> {
    let buffer : &[u8] = self.buffer.as_ref();
    let body_range = self.parse_state.body_range.expect("No body range was found.");
    let start = body_range.start;
    let end = body_range.end;
    let body_slice = &buffer[start as usize ..end as usize];
    return Vec::from(body_slice);
  }

  fn read_command(&self) -> ReadCommandResult {
    ReadCommandResult::Incomplete
  }

  fn read_header(&self) -> ReadHeaderResult {
    ReadHeaderResult::Incomplete
  }

  fn read_body(&self) -> ReadBodyResult {
    ReadBodyResult::Incomplete
  }

  fn find_next(&self, offset: u32, needle: u8) -> Option<u32> {
    let mut step = 0u32;
    for byte in &self.buffer[offset as usize..] {
      if *byte == needle {
        return Some(offset + step);
      }
      step += 1;
    }
    None
  }
}
<commit_msg>Added functions for reading from byte buffer.<commit_after>use header::HeaderList;
use header::Header;
use header::ContentLength;
use header::StompHeaderSet;
use subscription::AckMode;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::InvalidInput;
use std::io::Write;
use std::io::Read;
use std::io::BufRead;
use std::str::from_utf8;
use std::fmt;
use std::fmt::Formatter;
use frame::{Frame, Transmission};

pub struct FrameBuffer {
  buffer: Vec<u8>,
  parse_state: ParseState
}

#[derive(Clone, Copy)]
struct ByteRange {
  pub start: u32,
  pub end : u32
}

struct ParseState {
  offset: u32,
  command_range: Option<ByteRange>,
  header_ranges: Vec<ByteRange>,
  body_range: Option<ByteRange>,
  section: FrameSection,
}

impl ParseState {
  fn new() -> ParseState {
    ParseState {
      offset: 0,
      command_range: None,
      header_ranges: Vec::new(),
      body_range: None,
      section: FrameSection::Command
    }
  }
}

enum FrameSection {
  Command,
  Headers,
  Body
}

enum ReadCommandResult {
  HeartBeat,
  Command(ByteRange),
  Incomplete
}

enum ReadHeaderResult {
  Header(ByteRange),
  EndOfHeaders,
  Incomplete
}

enum ReadBodyResult {
  Body(ByteRange),
  Incomplete
}

impl FrameBuffer {
  pub fn new() -> FrameBuffer {
    FrameBuffer {
      buffer: Vec::with_capacity(512),
      parse_state: ParseState::new()
    }
  }

  pub fn append(&mut self, bytes: &[u8]) { // TODO: Return result?
    self.buffer.push_all(bytes);
  }

  pub fn read_transmission(&mut self) -> Option<Transmission> {
    match self.parse_state.section {
      FrameSection::Command => self.resume_parsing_at_command(),
      FrameSection::Headers => self.resume_parsing_at_headers(),
      FrameSection::Body    => self.resume_parsing_at_body()
    }
  }

  fn resume_parsing_at_command(&mut self) -> Option<Transmission> {
    debug!("Parsing command.");
    match self.read_command() {
      ReadCommandResult::HeartBeat => Some(Transmission::HeartBeat),
      ReadCommandResult::Command(byte_range) => {
        self.parse_state.command_range = Some(byte_range);
        self.parse_state.section = FrameSection::Headers;
        self.resume_parsing_at_headers()
      },
      ReadCommandResult::Incomplete => None
    }
  }

  fn resume_parsing_at_headers(&mut self) -> Option<Transmission> {
    debug!("Parsing headers.");
    match self.read_header() {
      ReadHeaderResult::Header(byte_range) => {
        self.parse_state.header_ranges.push(byte_range);
        self.resume_parsing_at_headers()
      },
      ReadHeaderResult::EndOfHeaders => {
        self.parse_state.section = FrameSection::Body;
        self.resume_parsing_at_body()
      },
      ReadHeaderResult::Incomplete => None
    }
  }

  fn resume_parsing_at_body(&mut self) -> Option<Transmission> {
    debug!("Parsing body.");
    match self.read_body() {
      ReadBodyResult::Body(byte_range) => {
        self.parse_state.body_range = Some(byte_range);
        let frame = Frame {
          command: self.create_command_string(),
          headers: self.create_header_list(),
          body: self.create_body()
        };
        self.reset_parse_state();
        Some(Transmission::CompleteFrame(frame))
      },
      ReadBodyResult::Incomplete => None
    }
  }

  fn reset_parse_state(&mut self) {
    self.buffer.clear();
    self.parse_state.offset = 0;
    self.parse_state.command_range = None;
    self.parse_state.header_ranges.clear();
    self.parse_state.body_range = None;
    self.parse_state.section = FrameSection::Command;
  }

  fn create_command_string(&mut self) -> String {
    let buffer : &[u8] = self.buffer.as_ref();
    let command_range = self.parse_state.command_range.expect("No command range was found.");
    let start = command_range.start;
    let end = command_range.end;
    let command_slice = &buffer[start as usize..end as usize];
    let command_str : &str = match from_utf8(&command_slice) {
      Ok(command_str) => command_str,
      _ =>panic!("Command was not utf8.")
    };
    return command_str.to_string();
  }

  fn create_header_list(&mut self) -> HeaderList {
    let buffer : &[u8] = self.buffer.as_ref();
    let mut header_list = header_list![];
    for header_range in &self.parse_state.header_ranges {
      let start = header_range.start;
      let end = header_range.end;
      let header_slice = &buffer[start as usize..end as usize];
      let header_str : &str = match from_utf8(&header_slice) {
        Ok(header_str) => header_str,
        _ =>panic!("Header was not utf8.")
      };
      let header = Header::decode_string(header_str);
      match header {
        Some(header) => header_list.push(header),
        None => panic!("Header was not decodable.")
      }
    }
    header_list
  }

  fn create_body(&mut self) -> Vec<u8> {
    let buffer : &[u8] = self.buffer.as_ref();
    let body_range = self.parse_state.body_range.expect("No body range was found.");
    let start = body_range.start;
    let end = body_range.end;
    let body_slice = &buffer[start as usize ..end as usize];
    return Vec::from(body_slice);
  }

  fn read_command(&self) -> ReadCommandResult {
    let offset = self.parse_state.offset;
    match self.find_next(offset, '\n' as u8) {
      Some(index) => {
        self.parse_state.offset += index - offset;
        if index == offset {
          ReadCommandResult::HeartBeat(ByteRange{start: offset, end: index})
        } else {
          ReadCommandResult::Command(ByteRange{start: offset, end: index})
        }
      }
      None => ReadCommandResult::Incomplete
    }
  }

  fn read_header(&self) -> ReadHeaderResult {
    let offset = self.parse_state.offset;
    match self.find_next(offset, '\n' as u8) {
      Some(index) => {
        self.parse_state.offset += index - offset;
        ReadHeaderResult::Header(ByteRange{start: offset, end: index})
      },
      None => ReadHeaderResult::Incomplete
    }
  }

  // Need to read both by Content-Length and by null byte
  fn read_body(&self) -> ReadBodyResult {
    ReadBodyResult::Incomplete
  }

  fn find_next(&self, offset: u32, needle: u8) -> Option<u32> {
    // What's the len() of the underlying slice? capacity or size?
    let mut step = 0u32;
    for byte in &self.buffer[offset as usize..] {
      if *byte == needle {
        return Some(offset + step);
      }
      step += 1;
    }
    None
  }
}
<|endoftext|>


<commit_before>
use std::ffi::CStr;
use std::error::Error;
use std::fmt::{self,Display,Formatter};
use std::default::Default;

use libc::{c_int,c_ulong};

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult,DeviceError};

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

pub mod caps;

#[allow(dead_code,non_camel_case_types,non_snake_case)]
pub mod properties {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/frontend-properties.rs"));
}

pub struct Frontend {
    device: DeviceFileDescriptor
}

impl Frontend {
    pub fn open(filename: &str, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Frontend> {
        let device = try!(DeviceFileDescriptor::open(filename, rw_mode, block_mode));
        Ok(Frontend { device: device })
    }

    pub fn get_info(&self) -> DeviceResult<FrontendInfo> {
        let mut ffi_info: ffi::Struct_dvb_frontend_info = Default::default();
        try!(self.device.ioctl_pointer(ffi::FE_GET_INFO as c_ulong, &mut ffi_info));
        let c_name = unsafe { CStr::from_ptr(ffi_info.name.as_ptr()) };
        Ok(FrontendInfo {
            name: String::from_utf8_lossy(c_name.to_bytes()).into_owned(),
            frequency_min: ffi_info.frequency_min,
            frequency_max: ffi_info.frequency_max,
            frequency_stepsize: ffi_info.frequency_stepsize,
            frequency_tolerance: ffi_info.frequency_tolerance,
            symbol_rate_min: ffi_info.symbol_rate_min,
            symbol_rate_max: ffi_info.symbol_rate_max,
            symbol_rate_tolerance: ffi_info.symbol_rate_tolerance,
            // Is truncate a good choice?
            caps: caps::FrontendCaps::from_bits_truncate(ffi_info.caps),
        })
    }
    pub fn read_status(&self) -> DeviceResult<FrontendStatus> {
        let mut ffi_status: ffi::Enum_fe_status = 0;
        try!(self.device.ioctl_pointer(ffi::FE_READ_STATUS as c_ulong, &mut ffi_status));
        Ok(FrontendStatus {
            has_signal: ffi_status & ffi::FE_HAS_SIGNAL != 0,
            has_carrier: ffi_status & ffi::FE_HAS_CARRIER != 0,
            has_viterbi: ffi_status & ffi::FE_HAS_VITERBI != 0,
            has_sync: ffi_status & ffi::FE_HAS_SYNC != 0,
            has_lock: ffi_status & ffi::FE_HAS_LOCK != 0,
            timedout: ffi_status & ffi::FE_TIMEDOUT != 0,
            reinit: ffi_status & ffi::FE_REINIT != 0,
        })
    }
    pub fn set_properties(&self, properties: &[properties::SetPropertyValue]) -> DeviceResult<()> {
        unimplemented!();
    }
    pub fn get_properties(&self, properties: &[properties::GetProperty]) -> PropertyResult<Vec<properties::GetPropertyValue>> {
        unimplemented!();
    }

    pub fn diseqc_reset_overload(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::FE_DISEQC_RESET_OVERLOAD as c_ulong)
    }

    pub fn diseqc_send_master_cmd(&self, command: DiseqcMasterCommand) -> DeviceResult<()> {
        let mut ffi_cmd = ffi::Struct_dvb_diseqc_master_cmd {
            msg: command.msg,
            msg_len: command.msg_len
        };
        self.device.ioctl_pointer(ffi::FE_DISEQC_SEND_MASTER_CMD as c_ulong, &mut ffi_cmd)
    }

    /// The timeout parameter is not used by most drivers. (2015-06-17)
    pub fn diseqc_recv_slave_reply(&self, timeout: u32) -> DeviceResult<DiseqcSlaveReply> {
        let mut ffi_reply: ffi::Struct_dvb_diseqc_slave_reply = Default::default();
        ffi_reply.timeout = timeout as c_int;
        try!(self.device.ioctl_pointer(ffi::FE_DISEQC_RECV_SLAVE_REPLY as c_ulong, &mut ffi_reply));
        Ok(DiseqcSlaveReply {
            msg: ffi_reply.msg,
            msg_len: ffi_reply.msg_len
        })
    }

    pub fn diseqc_send_burst(&self, command: SecMiniCmd) -> DeviceResult<()> {
        let mut command = match command {
            SecMiniCmd::A => ffi::SEC_MINI_A,
            SecMiniCmd::B => ffi::SEC_MINI_B
        };
        self.device.ioctl_pointer(ffi::FE_DISEQC_SEND_BURST as c_ulong, &mut command)
    }

    pub fn set_tone(&self, tone: SecToneMode) -> DeviceResult<()> {
        let mut tone = match tone {
            SecToneMode::On => ffi::SEC_TONE_ON,
            SecToneMode::Off => ffi::SEC_TONE_OFF
        };
        self.device.ioctl_pointer(ffi::FE_SET_TONE as c_ulong, &mut tone)
    }

    pub fn set_voltage(&self, voltage: properties::Voltage) -> DeviceResult<()> {
        let voltage = match voltage {
            properties::Voltage::SecVoltage13 => ffi::SEC_VOLTAGE_13,
            properties::Voltage::SecVoltage18 => ffi::SEC_VOLTAGE_18,
            properties::Voltage::SecVoltageOff => ffi::SEC_VOLTAGE_OFF,
        };
        self.device.ioctl_value(ffi::FE_SET_VOLTAGE as c_ulong, voltage)
    }

    pub fn enable_high_lnb_voltage(&self, high: u32) -> DeviceResult<()> {
        self.device.ioctl_value(ffi::FE_ENABLE_HIGH_LNB_VOLTAGE as c_ulong, high)
    }

    pub fn set_frontend_tune_mode(&self, tune_mode: TuneMode) -> DeviceResult<()> {
        let value = match tune_mode {
            TuneMode::Normal => 0,
            TuneMode::OneShot => ffi::FE_TUNE_MODE_ONESHOT
        };
        self.device.ioctl_value(ffi::FE_SET_FRONTEND_TUNE_MODE as c_ulong, value)
    }
}

#[derive(Clone,Debug)]
pub struct FrontendInfo {
    pub name: String,
    pub frequency_min: u32,
    pub frequency_max: u32,
    pub frequency_stepsize: u32,
    pub frequency_tolerance: u32,
    pub symbol_rate_min: u32,
    pub symbol_rate_max: u32,
    pub symbol_rate_tolerance: u32,
    pub caps: caps::FrontendCaps,
}

#[derive(Copy,Clone,Debug)]
pub struct FrontendStatus {
    pub has_signal: bool,
    pub has_carrier: bool,
    pub has_viterbi: bool,
    pub has_sync: bool,
    pub has_lock: bool,
    pub timedout: bool,
    pub reinit: bool
}

#[derive(Copy,Clone,Debug)]
pub struct DiseqcSlaveReply {
    pub msg: [u8; 4],
    pub msg_len: u8
}

#[derive(Copy,Clone,Debug)]
pub struct DiseqcMasterCommand {
    pub msg: [u8; 6],
    pub msg_len: u8
}

#[derive(Copy,Clone,Debug)]
pub enum SecMiniCmd {
    A,
    B
}

#[derive(Copy,Clone,Debug)]
pub enum SecToneMode {
    On,
    Off
}

#[derive(Copy,Clone,Debug)]
pub enum TuneMode {
    Normal,
    OneShot
}

pub type PropertyResult<T> = Result<T, PropertyError>;

#[derive(Clone,Debug)]
pub enum PropertyError {
    DeviceError(DeviceError),
    PropertyMappingError(properties::PropertyMappingError)
}

impl Error for PropertyError {
    fn description(&self) -> &str {
        match *self {
            PropertyError::DeviceError(ref err) => err.description(),
            PropertyError::PropertyMappingError(ref err) => err.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            PropertyError::DeviceError(ref err) => Some(err),
            PropertyError::PropertyMappingError(ref err) => Some(err)
        }
    }
}

impl Display for PropertyError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "PropertyError: {}", self.description())
    }
}<commit_msg>Implement Frontend::get_properties().<commit_after>
use std::ffi::CStr;
use std::error::Error;
use std::fmt::{self,Display,Formatter};
use std::default::Default;

use libc::{c_int,c_ulong};

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult,DeviceError};

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

pub mod caps;

#[allow(dead_code,non_camel_case_types,non_snake_case)]
pub mod properties {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/frontend-properties.rs"));
}

pub struct Frontend {
    device: DeviceFileDescriptor
}

impl Frontend {
    pub fn open(filename: &str, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Frontend> {
        let device = try!(DeviceFileDescriptor::open(filename, rw_mode, block_mode));
        Ok(Frontend { device: device })
    }

    pub fn get_info(&self) -> DeviceResult<FrontendInfo> {
        let mut ffi_info: ffi::Struct_dvb_frontend_info = Default::default();
        try!(self.device.ioctl_pointer(ffi::FE_GET_INFO as c_ulong, &mut ffi_info));
        let c_name = unsafe { CStr::from_ptr(ffi_info.name.as_ptr()) };
        Ok(FrontendInfo {
            name: String::from_utf8_lossy(c_name.to_bytes()).into_owned(),
            frequency_min: ffi_info.frequency_min,
            frequency_max: ffi_info.frequency_max,
            frequency_stepsize: ffi_info.frequency_stepsize,
            frequency_tolerance: ffi_info.frequency_tolerance,
            symbol_rate_min: ffi_info.symbol_rate_min,
            symbol_rate_max: ffi_info.symbol_rate_max,
            symbol_rate_tolerance: ffi_info.symbol_rate_tolerance,
            // Is truncate a good choice?
            caps: caps::FrontendCaps::from_bits_truncate(ffi_info.caps),
        })
    }
    pub fn read_status(&self) -> DeviceResult<FrontendStatus> {
        let mut ffi_status: ffi::Enum_fe_status = 0;
        try!(self.device.ioctl_pointer(ffi::FE_READ_STATUS as c_ulong, &mut ffi_status));
        Ok(FrontendStatus {
            has_signal: ffi_status & ffi::FE_HAS_SIGNAL != 0,
            has_carrier: ffi_status & ffi::FE_HAS_CARRIER != 0,
            has_viterbi: ffi_status & ffi::FE_HAS_VITERBI != 0,
            has_sync: ffi_status & ffi::FE_HAS_SYNC != 0,
            has_lock: ffi_status & ffi::FE_HAS_LOCK != 0,
            timedout: ffi_status & ffi::FE_TIMEDOUT != 0,
            reinit: ffi_status & ffi::FE_REINIT != 0,
        })
    }
    pub fn set_properties(&self, properties: &[properties::SetPropertyValue]) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn get_properties(&self, properties: &[properties::GetProperty]) -> PropertyResult<Vec<properties::GetPropertyValue>> {
        let mut ffi_property_list: Vec<ffi::Struct_dtv_property> = properties.iter().map(
            |p| ffi::Struct_dtv_property { cmd: (*p).into(), ..Default::default() }
        ).collect();
        let mut ffi_properties = ffi::Struct_dtv_properties {
            num: ffi_property_list.len() as u32,
            props: ffi_property_list.as_mut_ptr()
        };
        try!(self.device.ioctl_pointer(ffi::FE_GET_PROPERTY as c_ulong, &mut ffi_properties));
        let mut values = vec!();
        for ffi_property in ffi_property_list {
            let value = try!(properties::get_property_value(ffi_property));
            values.push(value);
        }
        Ok(values)
    }

    pub fn diseqc_reset_overload(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::FE_DISEQC_RESET_OVERLOAD as c_ulong)
    }

    pub fn diseqc_send_master_cmd(&self, command: DiseqcMasterCommand) -> DeviceResult<()> {
        let mut ffi_cmd = ffi::Struct_dvb_diseqc_master_cmd {
            msg: command.msg,
            msg_len: command.msg_len
        };
        self.device.ioctl_pointer(ffi::FE_DISEQC_SEND_MASTER_CMD as c_ulong, &mut ffi_cmd)
    }

    /// The timeout parameter is not used by most drivers. (2015-06-17)
    pub fn diseqc_recv_slave_reply(&self, timeout: u32) -> DeviceResult<DiseqcSlaveReply> {
        let mut ffi_reply: ffi::Struct_dvb_diseqc_slave_reply = Default::default();
        ffi_reply.timeout = timeout as c_int;
        try!(self.device.ioctl_pointer(ffi::FE_DISEQC_RECV_SLAVE_REPLY as c_ulong, &mut ffi_reply));
        Ok(DiseqcSlaveReply {
            msg: ffi_reply.msg,
            msg_len: ffi_reply.msg_len
        })
    }

    pub fn diseqc_send_burst(&self, command: SecMiniCmd) -> DeviceResult<()> {
        let mut command = match command {
            SecMiniCmd::A => ffi::SEC_MINI_A,
            SecMiniCmd::B => ffi::SEC_MINI_B
        };
        self.device.ioctl_pointer(ffi::FE_DISEQC_SEND_BURST as c_ulong, &mut command)
    }

    pub fn set_tone(&self, tone: SecToneMode) -> DeviceResult<()> {
        let mut tone = match tone {
            SecToneMode::On => ffi::SEC_TONE_ON,
            SecToneMode::Off => ffi::SEC_TONE_OFF
        };
        self.device.ioctl_pointer(ffi::FE_SET_TONE as c_ulong, &mut tone)
    }

    pub fn set_voltage(&self, voltage: properties::Voltage) -> DeviceResult<()> {
        let voltage = match voltage {
            properties::Voltage::SecVoltage13 => ffi::SEC_VOLTAGE_13,
            properties::Voltage::SecVoltage18 => ffi::SEC_VOLTAGE_18,
            properties::Voltage::SecVoltageOff => ffi::SEC_VOLTAGE_OFF,
        };
        self.device.ioctl_value(ffi::FE_SET_VOLTAGE as c_ulong, voltage)
    }

    pub fn enable_high_lnb_voltage(&self, high: u32) -> DeviceResult<()> {
        self.device.ioctl_value(ffi::FE_ENABLE_HIGH_LNB_VOLTAGE as c_ulong, high)
    }

    pub fn set_frontend_tune_mode(&self, tune_mode: TuneMode) -> DeviceResult<()> {
        let value = match tune_mode {
            TuneMode::Normal => 0,
            TuneMode::OneShot => ffi::FE_TUNE_MODE_ONESHOT
        };
        self.device.ioctl_value(ffi::FE_SET_FRONTEND_TUNE_MODE as c_ulong, value)
    }
}

#[derive(Clone,Debug)]
pub struct FrontendInfo {
    pub name: String,
    pub frequency_min: u32,
    pub frequency_max: u32,
    pub frequency_stepsize: u32,
    pub frequency_tolerance: u32,
    pub symbol_rate_min: u32,
    pub symbol_rate_max: u32,
    pub symbol_rate_tolerance: u32,
    pub caps: caps::FrontendCaps,
}

#[derive(Copy,Clone,Debug)]
pub struct FrontendStatus {
    pub has_signal: bool,
    pub has_carrier: bool,
    pub has_viterbi: bool,
    pub has_sync: bool,
    pub has_lock: bool,
    pub timedout: bool,
    pub reinit: bool
}

#[derive(Copy,Clone,Debug)]
pub struct DiseqcSlaveReply {
    pub msg: [u8; 4],
    pub msg_len: u8
}

#[derive(Copy,Clone,Debug)]
pub struct DiseqcMasterCommand {
    pub msg: [u8; 6],
    pub msg_len: u8
}

#[derive(Copy,Clone,Debug)]
pub enum SecMiniCmd {
    A,
    B
}

#[derive(Copy,Clone,Debug)]
pub enum SecToneMode {
    On,
    Off
}

#[derive(Copy,Clone,Debug)]
pub enum TuneMode {
    Normal,
    OneShot
}

pub type PropertyResult<T> = Result<T, PropertyError>;

#[derive(Clone,Debug)]
pub enum PropertyError {
    DeviceError(DeviceError),
    PropertyMappingError(properties::PropertyMappingError)
}

impl Error for PropertyError {
    fn description(&self) -> &str {
        match *self {
            PropertyError::DeviceError(ref err) => err.description(),
            PropertyError::PropertyMappingError(ref err) => err.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            PropertyError::DeviceError(ref err) => Some(err),
            PropertyError::PropertyMappingError(ref err) => Some(err)
        }
    }
}

impl From<DeviceError> for PropertyError {
    fn from(err: DeviceError) -> PropertyError {
        PropertyError::DeviceError(err)
    }
}

impl From<properties::PropertyMappingError> for PropertyError {
    fn from(err: properties::PropertyMappingError) -> PropertyError {
        PropertyError::PropertyMappingError(err)
    }
}

impl Display for PropertyError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "PropertyError: {}", self.description())
    }
}<|endoftext|>


<commit_before>use gfx::handle::ShaderResourceView;
use gfx::{texture, Factory, Resources};
use gfx::format::Rgba8;
use cgmath;
use cgmath::{Matrix4, Point3, Vector3, Point2, Rad};
use game::constants::{TILE_WIDTH, RESOLUTION_X, RESOLUTION_Y, VIEW_DISTANCE};
use graphics::orientation::Orientation;
use gfx_app::mouse_controls::MouseInputState;
use image;
use shaders::Projection;
use std::f32::consts::PI;
use std::io::Cursor;

pub mod camera;
pub mod orientation;

#[derive(Debug)]
pub struct DeltaTime(pub f64);

#[derive(Debug, Clone)]
pub struct Dimensions {
  width: u32,
  height: u32,
}

impl Dimensions {
  pub fn new(_window_width: u32, _window_height: u32) -> Dimensions {
    Dimensions {
      width: RESOLUTION_X,
      height: RESOLUTION_Y,
    }
  }

  pub fn get_view_matrix() -> Matrix4<f32> {
    Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    )
  }

  pub fn world_to_projection(&self, input: &camera::CameraInputState) -> Projection {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, input.distance),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );
    let aspect_ratio = self.width as f32 / self.height as f32;
    Projection {
      model: view.into(),
      view: view.into(),
      proj: cgmath::perspective(cgmath::Deg(75.0f32), aspect_ratio, 0.1, 4000.0).into(),
    }
  }
}

pub fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2 {
    x: point.x,
    y: RESOLUTION_Y as f32 - point.y
  }
}

pub fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> i32 {

  let theta= cgmath::Angle::atan2(end_point.y - start_point.y, (end_point.x - start_point.x));
  let angle = match theta {
    Rad(i) => i
  };
  let rad_to_deg = 180.0 / PI;
  let anglei = if angle < 0.0 {
    (angle + 2.0 * PI) * rad_to_deg
  } else {
    angle * rad_to_deg
  };
  anglei.floor() as i32
}

pub fn direction_movement(direction: u32) -> Point2<f32> {
  println!("Implement direction x,y calculation {}", direction);
  Point2 {
    x: 0.0,
    y: 0.0
  }
}

pub fn get_orientation(mouse_input: &MouseInputState) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2 {
      x: (RESOLUTION_X / 2) as f32,
      y: (RESOLUTION_Y / 2) as f32
    };
    let angle_in_degrees = direction(start_point, flip_y_axel(end_point_gl));

    match angle_in_degrees {
      345 ... 360 | 0 ... 22 => Orientation::Right,
      23 ... 68 => Orientation::UpRight,
      69 ... 114 => Orientation::Up,
      115 ... 160 => Orientation::UpLeft,
      161 ... 206 => Orientation::Left,
      207 ... 252 => Orientation::DownLeft,
      253 ... 298 => Orientation::Down,
      299 ... 344 => Orientation::DownRight,
      _ => unreachable!("Invalid orientation")
    }
  } else {
    Orientation::Right
  }
}

fn is_within_map_borders(point: Point2<f64>) -> bool {
  point.x > 0.0 && point.x < 63.0 && point.y > 0.0 && point.y < 63.0
}
pub fn can_move(screen_pos: [f32; 2]) -> bool {
  let x_coord = f64::from(screen_pos[0]);
  let y_coord = f64::from(screen_pos[1]);
  let point = Point2 {
    x: (x_coord / TILE_WIDTH + y_coord / TILE_WIDTH).round() + 31.0,
    y: (y_coord / TILE_WIDTH - x_coord / TILE_WIDTH).round() + 32.0
  };
  is_within_map_borders(point)
}

pub fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<ShaderResourceView<R, [f32; 4]>, String> where R: Resources, F: Factory<R> {
  let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
  let (width, height) = img.dimensions();
  let kind = texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single);
  let (_, view) = factory.create_texture_immutable_u8::<Rgba8>(kind, &[&img]).unwrap();
  Ok(view)
}
<commit_msg>Refactor direction calculation<commit_after>use gfx::handle::ShaderResourceView;
use gfx::{texture, Factory, Resources};
use gfx::format::Rgba8;
use cgmath;
use cgmath::{Angle, Deg, Matrix4, Point3, Vector3, Point2, Rad};
use game::constants::{TILE_WIDTH, RESOLUTION_X, RESOLUTION_Y, VIEW_DISTANCE};
use graphics::orientation::Orientation;
use gfx_app::mouse_controls::MouseInputState;
use image;
use shaders::Projection;
use std::io::Cursor;

pub mod camera;
pub mod orientation;

#[derive(Debug)]
pub struct DeltaTime(pub f64);

#[derive(Debug, Clone)]
pub struct Dimensions {
  width: u32,
  height: u32,
}

impl Dimensions {
  pub fn new(_window_width: u32, _window_height: u32) -> Dimensions {
    Dimensions {
      width: RESOLUTION_X,
      height: RESOLUTION_Y,
    }
  }

  pub fn get_view_matrix() -> Matrix4<f32> {
    Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    )
  }

  pub fn world_to_projection(&self, input: &camera::CameraInputState) -> Projection {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, input.distance),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );
    let aspect_ratio = self.width as f32 / self.height as f32;
    Projection {
      model: view.into(),
      view: view.into(),
      proj: cgmath::perspective(cgmath::Deg(75.0f32), aspect_ratio, 0.1, 4000.0).into(),
    }
  }
}

pub fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2 {
    x: point.x,
    y: RESOLUTION_Y as f32 - point.y
  }
}

pub fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> i32 {
  let theta= cgmath::Angle::atan2(end_point.y - start_point.y, end_point.x - start_point.x);
  let angle = match theta {
    Deg(i) => i
  };
  let a = angle.floor() as i32;
  if a < 0 { 360 + a } else { a }
}

pub fn direction_movement(direction: u32) -> Point2<f32> {
  println!("Implement direction x,y calculation {}", direction);

  let f_direction = (direction as f32 - 360.0).abs() + 90.0;

  let foo = Point2 {
    x: Angle::sin(Rad(f_direction)),
    y: Angle::cos(Rad(f_direction)),
  };
  print!("movement {:?}", foo);
  foo
}

pub fn get_orientation(mouse_input: &MouseInputState) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2 {
      x: (RESOLUTION_X / 2) as f32,
      y: (RESOLUTION_Y / 2) as f32
    };
    let angle_in_degrees = direction(start_point, flip_y_axel(end_point_gl));

    match angle_in_degrees {
      345 ... 360 | 0 ... 22 => Orientation::Right,
      23 ... 68 => Orientation::UpRight,
      69 ... 114 => Orientation::Up,
      115 ... 160 => Orientation::UpLeft,
      161 ... 206 => Orientation::Left,
      207 ... 252 => Orientation::DownLeft,
      253 ... 298 => Orientation::Down,
      299 ... 344 => Orientation::DownRight,
      _ => unreachable!("Invalid orientation")
    }
  } else {
    Orientation::Right
  }
}

fn is_within_map_borders(point: Point2<f64>) -> bool {
  point.x > 0.0 && point.x < 63.0 && point.y > 0.0 && point.y < 63.0
}
pub fn can_move(screen_pos: [f32; 2]) -> bool {
  let x_coord = f64::from(screen_pos[0]);
  let y_coord = f64::from(screen_pos[1]);
  let point = Point2 {
    x: (x_coord / TILE_WIDTH + y_coord / TILE_WIDTH).round() + 31.0,
    y: (y_coord / TILE_WIDTH - x_coord / TILE_WIDTH).round() + 32.0
  };
  is_within_map_borders(point)
}

pub fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<ShaderResourceView<R, [f32; 4]>, String> where R: Resources, F: Factory<R> {
  let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
  let (width, height) = img.dimensions();
  let kind = texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single);
  let (_, view) = factory.create_texture_immutable_u8::<Rgba8>(kind, &[&img]).unwrap();
  Ok(view)
}
<|endoftext|>


<commit_before>//! Implementation of Xen's ring mechanism
<commit_msg>xen/ring: Add SharedRing implementation<commit_after>//! Implementation of Xen's ring mechanism

use core::{mem, cmp};

use core::marker::PhantomData;

use rlibc::memset;

use alloc_uni::__rust_allocate;

use hal::mmu::{Vaddr, Mfn};

use hal::arch::utils::mb;

use hal::arch::defs::PAGE_SIZE;

use hal::xen::grant::Ref as GrantRef;
use hal::xen::grant::Table as GrantTable;

// Round a 32-bit unsigned constant down to the nearest power of two.
// Taken from xen/interface/io/ring.h
macro_rules! RD2 {
    ($x:expr) => (
        if $x & 0x2 != 0 {
            0x2
        } else {
            $x & 0x1
        }
    );
}

macro_rules! RD4 {
    ($x:expr) => (
        if $x & 0xC != 0 {
            RD2!($x >> 2) << 2
        } else {
            RD2!($x)
        }
    );
}

macro_rules! RD8 {
    ($x:expr) => (
        if $x & 0xF0 != 0 {
            RD4!($x >> 4) << 4
        } else {
            RD4!($x)
        }
    );
}

macro_rules! RD16 {
    ($x:expr) => (
        if $x & 0xFF00 != 0 {
            RD8!($x >> 8) << 8
        } else {
            RD8!($x)
        }
    );
}

macro_rules! RD32 {
    ($x:expr) => (
        if $x & 0xFFFF0000 != 0 {
            RD16!($x >> 16) << 16
        } else {
            RD16!($x)
        }
    );
}

/// Ring index type
pub type Idx = u32;

#[repr(C)]
/// Shared ring page
///
/// Equivalent of struct __name##_sring defined by DEFINE_RING_TYPES
struct XenSharedRing {
    req_prod: Idx,
    req_event: Idx,
    rsp_prod: Idx,
    rsp_event: Idx,
    pad: [u8; 48],
    ring: u8, // Variable length
}

// XXX: deallocate/end grant access on Drop ?
/// Xen's shared ring
///
/// `Req` is the type of the request
///
/// `Resp` is the type of the response
pub struct SharedRing<Req, Resp> {
    sring: *mut XenSharedRing,
    size: usize,
    elt_size: usize,
    grant_ref: Option<GrantRef>,
    _req: PhantomData<Req>,
    _resp: PhantomData<Resp>,
}

impl<Req, Resp> SharedRing<Req, Resp> {
    /// Allocate a new shared ring
    ///
    /// May return None for two reasons:
    /// - `size` is not aligned on PAGE_SIZE
    /// - The system is out of memory
    pub fn new(size: usize) -> Option<SharedRing<Req, Resp>> {
        if size < PAGE_SIZE || size % PAGE_SIZE != 0 {
            return None;
        }

        // Allocate memory for the ring
        let sring = __rust_allocate(size, PAGE_SIZE) as *mut XenSharedRing;

        if sring.is_null() {
            return None;
        }

        // Initialize the ring
        unsafe {
            memset(sring as *mut u8, 0, PAGE_SIZE);

            (*sring).req_prod = 0;
            (*sring).rsp_prod = 0;
            (*sring).req_event = 1;
            (*sring).rsp_event = 1;
        }

        Some(SharedRing {
            sring: sring,
            size: size,
            elt_size: cmp::max(mem::size_of::<Req>(), mem::size_of::<Resp>()),
            grant_ref: None,
            _req: PhantomData,
            _resp: PhantomData,
        })
    }

    /// Create a shared ring from an existing memory area
    pub unsafe fn from_ptr(ptr: *mut u8, size: usize) -> SharedRing<Req, Resp> {
        SharedRing {
            sring: ptr as *mut _,
            size: size,
            elt_size: cmp::max(mem::size_of::<Req>(), mem::size_of::<Resp>()),
            grant_ref: None,
            _req: PhantomData,
            _resp: PhantomData,
        }
    }

    #[inline]
    /// Returns the request production index
    pub fn req_prod(&self) -> Idx {
        unsafe {
            (*self.sring).req_prod
        }
    }

    #[inline]
    /// Returns the response production index
    pub fn rsp_prod(&self) -> Idx {
        unsafe {
            (*self.sring).rsp_prod
        }
    }

    #[inline]
    /// Returns the request event index
    pub fn req_event(&self) -> Idx {
        unsafe {
            (*self.sring).req_event
        }
    }

    #[inline]
    /// Returns the response event index
    pub fn rsp_event(&self) -> Idx {
        unsafe {
            (*self.sring).rsp_event
        }
    }

    /// Set the request production index
    ///
    /// This is unsafe as an invalid index can corrupt the ring
    pub unsafe fn req_prod_set(&mut self, req: Idx) {
        (*self.sring).req_prod = req;
        mb();
    }

    /// Set the response production index
    ///
    /// This is unsafe as an invalid index can corrupt the ring
    pub unsafe fn rsp_prod_set(&mut self, rsp: Idx) {
        (*self.sring).rsp_prod = rsp;
        mb();
    }

    #[inline]
    /// Set the request event index
    pub unsafe fn req_event_set(&mut self, req: Idx) {
        (*self.sring).req_event = req;
    }

    #[inline]
    /// Set the response event index
    pub unsafe fn rsp_event_set(&mut self, rsp: Idx) {
        (*self.sring).rsp_event = rsp;
    }

    /// Returns the size of the ring
    ///
    /// Equivalent to __RING_SIZE
    pub fn size(&self) -> usize {
        let ring_addr = unsafe { &(*self.sring).ring } as *const _ as isize;
        let sring_addr = self.sring as isize;

        RD32!((self.size as isize - ring_addr + sring_addr) as usize /
              self.elt_size)
    }

    /// Grant access to the ring to a foreign domain with id `domid`
    pub fn grant_access(&mut self, domid: u16) -> Option<GrantRef> {
        if let Some(ref r) = self.grant_ref {
            return Some(r.clone());
        }

        match GrantTable::alloc_ref() {
            None => None,
            Some(r) => {
                r.grant_access(domid, Mfn::from(Vaddr::from_ptr(self.sring)),
                               false);

                self.grant_ref = Some(r.clone());

                Some(r)
            }
        }
    }

    #[inline]
    fn ptr_from_index(&mut self, mut idx: usize) -> *mut u8 {
        idx = idx & (self.size() - 1);

        unsafe {
            let ring_ptr: *mut u8 = &mut (*self.sring).ring;

            ring_ptr.offset((idx * self.elt_size) as isize) as *mut u8
        }
    }

    /// Get a reference over the request at position `idx`
    pub fn request_from_index(&mut self, idx: usize) -> &mut Req {
        unsafe {
            &mut *(self.ptr_from_index(idx) as *mut Req)
        }
    }

    /// Get a reference over the response at position `idx`
    pub fn response_from_index(&mut self, idx: usize) -> &mut Resp {
        unsafe {
            &mut *(self.ptr_from_index(idx) as *mut Resp)
        }
    }
}
<|endoftext|>