<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 automata::dfa::{DFA,DFABuilder,DFAError,DFABuilding};

#[derive(Debug)]
pub enum DFAReaderError {
    MissingStartingState,
    MissingFinalStates,
    IncompleteTransition(usize),
    IllformedTransition(usize),
    DFA(DFAError,usize),
    Io(io::Error),
    Parse(num::ParseIntError,usize),
}

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

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

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

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

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

pub type Result<T> = result::Result<T,DFAReaderError>;

pub struct DFAReader;

impl DFAReader {
    fn parse_dfa_error(contents: &str, line: usize) -> Result<usize> {
            contents.parse::<usize>()
                    .map_err(|e| DFAReaderError::Parse(e,line))
    }

    pub fn new_from_file<P: AsRef<Path>>(file_path: P) -> Result<DFA> {
        let file = try!(File::open(file_path));
        let file = BufReader::new(file);
        DFAReader::new_from_lines(&mut file.lines())
    }

    fn read_start(dfa: DFABuilder, lines : &mut Iterator<Item=(usize,io::Result<String>)>) -> Result<DFABuilder> {
        let (nline,line) = try!(lines.next().ok_or(DFAReaderError::MissingStartingState));
        let line = try!(line);
        let start = try!(DFAReader::parse_dfa_error(&line,nline));
        let dfa = dfa.add_start(start);
        match dfa {
            Ok(dfa) => Ok(dfa),
            Err(e) => Err(DFAReaderError::DFA(e,nline)),
        }
    }

    fn read_finals(dfa: DFABuilder, lines : &mut Iterator<Item=(usize,io::Result<String>)>) -> Result<DFABuilder> {
        let (nline,line) = try!(lines.next().ok_or(DFAReaderError::MissingFinalStates));
        let line = try!(line);
        let dfa = try!(try!(line
            .split_whitespace()
            .map(|token| DFAReader::parse_dfa_error(token,nline))
            .fold_results(Ok(dfa), |acc, elt| acc.add_final(elt)))
            .map_err(|e| DFAReaderError::DFA(e,nline)));
        Ok(dfa)
    }

    fn read_transition(dfa: DFABuilder, line : (usize,io::Result<String>))-> Result<DFABuilder> {
        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(DFAReaderError::IllformedTransition(nline));
        }
        let src = try!(tokens
            .next()
            .ok_or(DFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| DFAReader::parse_dfa_error(contents,nline)));
        let dest = try!(tokens
            .next()
            .ok_or(DFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| DFAReader::parse_dfa_error(contents,nline)));
        if tokens.next().is_some() {
            return Err(DFAReaderError::IllformedTransition(nline));
        }
        let dfa = try!(dfa.add_transition(symb,src,dest).map_err(|e| DFAReaderError::DFA(e,nline)));;
        Ok(dfa)
    }

    fn new_from_lines(lines : &mut Iterator<Item=io::Result<String>>) -> Result<DFA> {
        let mut dfa = try!(DFABuilder::new().map_err(|e| DFAReaderError::DFA(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()
            });
        dfa = try!(DFAReader::read_start(dfa, &mut lines));
        dfa = try!(DFAReader::read_finals(dfa, &mut lines));
        for line in lines {
            dfa = try!(DFAReader::read_transition(dfa, line));
        }
        dfa.finalize().map_err(|e| DFAReaderError::DFA(e,0))
    }

    pub fn new_from_string(file: &str) -> Result<DFA> {
        DFAReader::new_from_lines(&mut file.lines().map(|line| Ok(line.to_string())))
    }
}

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

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

    #[test]
    fn test_start_not_a_number() {
        let model =
            "a";
        match DFAReader::new_from_string(model) {
            Err(DFAReaderError::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::Parse(_,line)) => assert!(line == 1),
            _ => assert!(false, "Parse expected."),
        }
    }

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

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

    #[test]
    fn test_no_transistions() {
        let model =
            "0\n\
             3";
        let _dfa = DFAReader::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::Parse(_,line)) => assert!(line == 3),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_duplicated_transition() {
        let model =
            "0\n\
             3\n\
             c 2 3\n\
             c 2 4";
        match DFAReader::new_from_string(model) {
            Err(DFAReaderError::DFA(_,line)) => assert!(line == 4),
            _ => assert!(false, "DuplicatedTransition expected."),
        }
    }

    #[test]
    fn test_read_from_fake_file() {
        let file = "fake.txt";
        match DFAReader::new_from_file(file) {
            Err(DFAReaderError::Io(_)) => assert!(true),
            _ => assert!(false, "Io::Error expected."),
        }
    }
}
<commit_msg>Reader documentation.<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 automata::dfa::{DFA,DFABuilder,DFAError,DFABuilding};

/// Type `DFAReaderError` describes the list of errors that can occur during
/// the parsing of a DFA file.
#[derive(Debug)]
pub enum DFAReaderError {
    /// 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 `DFA` encapsules the error specific to the DFA building process (no final
    /// states,...).
    DFA(DFAError,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 DFAReaderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DFAReaderError::Io(ref err) => write!(f, "IO error: {}", err),
            DFAReaderError::MissingStartingState => write!(f, "The file is empty or only contains white characters."),
            DFAReaderError::MissingFinalStates => write!(f, "The file does not specify the list of final states."),
            DFAReaderError::IncompleteTransition(ref line) => write!(f, "Line {}: missing the src or the dest state.", line),
            DFAReaderError::IllformedTransition(ref line) => write!(f, "Line {}: too much elements.", line),
            DFAReaderError::DFA(ref err,ref line) => write!(f, "Line {}: DFAError {}", line, err),
            DFAReaderError::Parse(ref err,ref line) => write!(f, "Line {}: parse error {}", line, err),
        }
    }
}

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

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

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

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

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

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

impl DFAReader {
    fn parse_dfa_error(contents: &str, line: usize) -> Result<usize> {
            contents.parse::<usize>()
                    .map_err(|e| DFAReaderError::Parse(e,line))
    }

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

    fn read_start(dfa: DFABuilder, lines : &mut Iterator<Item=(usize,io::Result<String>)>) -> Result<DFABuilder> {
        let (nline,line) = try!(lines.next().ok_or(DFAReaderError::MissingStartingState));
        let line = try!(line);
        let start = try!(DFAReader::parse_dfa_error(&line,nline));
        let dfa = dfa.add_start(start);
        match dfa {
            Ok(dfa) => Ok(dfa),
            Err(e) => Err(DFAReaderError::DFA(e,nline)),
        }
    }

    fn read_finals(dfa: DFABuilder, lines : &mut Iterator<Item=(usize,io::Result<String>)>) -> Result<DFABuilder> {
        let (nline,line) = try!(lines.next().ok_or(DFAReaderError::MissingFinalStates));
        let line = try!(line);
        let dfa = try!(try!(line
            .split_whitespace()
            .map(|token| DFAReader::parse_dfa_error(token,nline))
            .fold_results(Ok(dfa), |acc, elt| acc.add_final(elt)))
            .map_err(|e| DFAReaderError::DFA(e,nline)));
        Ok(dfa)
    }

    fn read_transition(dfa: DFABuilder, line : (usize,io::Result<String>))-> Result<DFABuilder> {
        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(DFAReaderError::IllformedTransition(nline));
        }
        let src = try!(tokens
            .next()
            .ok_or(DFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| DFAReader::parse_dfa_error(contents,nline)));
        let dest = try!(tokens
            .next()
            .ok_or(DFAReaderError::IncompleteTransition(nline))
            .and_then(|contents| DFAReader::parse_dfa_error(contents,nline)));
        if tokens.next().is_some() {
            return Err(DFAReaderError::IllformedTransition(nline));
        }
        let dfa = try!(dfa.add_transition(symb,src,dest).map_err(|e| DFAReaderError::DFA(e,nline)));;
        Ok(dfa)
    }

    fn new_from_lines(lines : &mut Iterator<Item=io::Result<String>>) -> Result<DFA> {
        let mut dfa = try!(DFABuilder::new().map_err(|e| DFAReaderError::DFA(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()
            });
        dfa = try!(DFAReader::read_start(dfa, &mut lines));
        dfa = try!(DFAReader::read_finals(dfa, &mut lines));
        for line in lines {
            dfa = try!(DFAReader::read_transition(dfa, line));
        }
        dfa.finalize().map_err(|e| DFAReaderError::DFA(e,0))
    }

    pub fn new_from_string(file: &str) -> Result<DFA> {
        DFAReader::new_from_lines(&mut file.lines().map(|line| Ok(line.to_string())))
    }
}

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

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

    #[test]
    fn test_start_not_a_number() {
        let model =
            "a";
        match DFAReader::new_from_string(model) {
            Err(DFAReaderError::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::Parse(_,line)) => assert!(line == 1),
            _ => assert!(false, "Parse expected."),
        }
    }

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

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

    #[test]
    fn test_no_transistions() {
        let model =
            "0\n\
             3";
        let _dfa = DFAReader::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::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 DFAReader::new_from_string(model) {
            Err(DFAReaderError::Parse(_,line)) => assert!(line == 3),
            _ => assert!(false, "Parse expected."),
        }
    }

    #[test]
    fn test_duplicated_transition() {
        let model =
            "0\n\
             3\n\
             c 2 3\n\
             c 2 4";
        match DFAReader::new_from_string(model) {
            Err(DFAReaderError::DFA(_,line)) => assert!(line == 4),
            _ => assert!(false, "DuplicatedTransition expected."),
        }
    }

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


<commit_before>extern crate termion;

extern crate chan_signal;

use self::termion::color as tcolor;
use self::termion::event::Event as TEvent;
use self::termion::event::Key as TKey;
use self::termion::input::TermRead;
use self::termion::raw::IntoRawMode;
use self::termion::style as tstyle;
use backend;
use chan;
use event::{Event, Key};
use std::cell::Cell;
use std::collections::BTreeMap;
use std::fmt;
use std::io::Write;
use std::thread;

use theme;

pub struct Concrete {
    terminal: termion::raw::RawTerminal<::std::io::Stdout>,
    current_style: Cell<theme::ColorStyle>,
    colors: BTreeMap<i16, (Box<tcolor::Color>, Box<tcolor::Color>)>,

    input: chan::Receiver<Event>,
    resize: chan::Receiver<chan_signal::Signal>,
    timeout: Option<u32>,
}

trait Effectable {
    fn on(&self);
    fn off(&self);
}

struct ColorRef<'a>(&'a tcolor::Color);

impl<'a> tcolor::Color for ColorRef<'a> {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_fg(f)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_bg(f)
    }
}

impl Effectable for theme::Effect {
    fn on(&self) {
        match *self {
            theme::Effect::Simple => (),
            theme::Effect::Reverse => print!("{}", tstyle::Invert),
        }
    }

    fn off(&self) {
        match *self {
            theme::Effect::Simple => (),
            theme::Effect::Reverse => print!("{}", tstyle::NoInvert),
        }
    }
}

fn apply_colors(fg: &tcolor::Color, bg: &tcolor::Color) {
    print!("{}{}", tcolor::Fg(ColorRef(fg)), tcolor::Bg(ColorRef(bg)));
}

impl Concrete {
    fn apply_colorstyle(&self, color_style: theme::ColorStyle) {
        let (ref fg, ref bg) = self.colors[&color_style.id()];
        apply_colors(&**fg, &**bg);
    }
}

impl backend::Backend for Concrete {
    fn init() -> Self {
        print!("{}", termion::cursor::Hide);

        let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]);

        let terminal = ::std::io::stdout().into_raw_mode().unwrap();
        let (sender, receiver) = chan::async();

        thread::spawn(move || for key in ::std::io::stdin().events() {
                          if let Ok(key) = key {
                              sender.send(map_key(key))
                          }
                      });

        let backend = Concrete {
            terminal: terminal,
            current_style: Cell::new(theme::ColorStyle::Background),
            colors: BTreeMap::new(),
            input: receiver,
            resize: resize,
            timeout: None,
        };

        backend
    }

    fn finish(&mut self) {
        print!("{}{}", termion::cursor::Show, termion::cursor::Goto(1, 1));
        print!("{}[49m{}[39m{}",
               27 as char,
               27 as char,
               termion::clear::All);
    }

    fn init_color_style(&mut self, style: theme::ColorStyle,
                        foreground: &theme::Color, background: &theme::Color) {
        // Step 1: convert foreground and background into proper termion Color
        self.colors.insert(style.id(),
                           (colour_to_termion_colour(foreground),
                            colour_to_termion_colour(background)));
    }

    fn with_color<F: FnOnce()>(&self, color: theme::ColorStyle, f: F) {
        let current_style = self.current_style.get();

        self.apply_colorstyle(color);

        self.current_style.set(color);
        f();
        self.current_style.set(current_style);

        self.apply_colorstyle(current_style);
    }

    fn with_effect<F: FnOnce()>(&self, effect: theme::Effect, f: F) {
        effect.on();
        f();
        effect.off();
    }

    fn has_colors(&self) -> bool {
        // TODO: color support detection?
        true
    }

    fn screen_size(&self) -> (usize, usize) {
        let (x, y) = termion::terminal_size().unwrap_or((1, 1));
        (x as usize, y as usize)
    }

    fn clear(&self) {
        self.apply_colorstyle(theme::ColorStyle::Background);
        print!("{}", termion::clear::All);
    }

    fn refresh(&mut self) {
        self.terminal.flush().unwrap();
    }

    fn print_at(&self, (x, y): (usize, usize), text: &str) {
        print!("{}{}",
               termion::cursor::Goto(1 + x as u16, 1 + y as u16),
               text);
    }

    fn set_refresh_rate(&mut self, fps: u32) {
        self.timeout = Some(1000 / fps as u32);
    }

    fn poll_event(&self) -> Event {
        let input = &self.input;
        let resize = &self.resize;

        if let Some(timeout) = self.timeout {
            let timeout = chan::after_ms(timeout);
            chan_select!{
                timeout.recv() => return Event::Refresh,
                resize.recv() => return Event::WindowResize,
                input.recv() -> input => return input.unwrap(),
            }
        } else {
            chan_select!{
                resize.recv() => return Event::WindowResize,
                input.recv() -> input => return input.unwrap(),
            }
        }
    }
}

fn map_key(event: TEvent) -> Event {
    match event {
        TEvent::Unsupported(bytes) => Event::Unknown(bytes),
        TEvent::Key(TKey::Esc) => Event::Key(Key::Esc),
        TEvent::Key(TKey::Backspace) => Event::Key(Key::Backspace),
        TEvent::Key(TKey::Left) => Event::Key(Key::Left),
        TEvent::Key(TKey::Right) => Event::Key(Key::Right),
        TEvent::Key(TKey::Up) => Event::Key(Key::Up),
        TEvent::Key(TKey::Down) => Event::Key(Key::Down),
        TEvent::Key(TKey::Home) => Event::Key(Key::Home),
        TEvent::Key(TKey::End) => Event::Key(Key::End),
        TEvent::Key(TKey::PageUp) => Event::Key(Key::PageUp),
        TEvent::Key(TKey::PageDown) => Event::Key(Key::PageDown),
        TEvent::Key(TKey::Delete) => Event::Key(Key::Del),
        TEvent::Key(TKey::Insert) => Event::Key(Key::Ins),
        TEvent::Key(TKey::F(i)) if i < 12 => Event::Key(Key::from_f(i)),
        TEvent::Key(TKey::F(j)) => Event::Unknown(vec![j]),
        TEvent::Key(TKey::Char('\n')) => Event::Key(Key::Enter),
        TEvent::Key(TKey::Char('\t')) => Event::Key(Key::Tab),
        TEvent::Key(TKey::Char(c)) => Event::Char(c),
        TEvent::Key(TKey::Ctrl('c')) => Event::Exit,
        TEvent::Key(TKey::Ctrl(c)) => Event::CtrlChar(c),
        TEvent::Key(TKey::Alt(c)) => Event::AltChar(c),
        _ => Event::Unknown(vec![]),
    }

}

fn colour_to_termion_colour(clr: &theme::Color) -> Box<tcolor::Color> {
    match *clr {
        theme::Color::Dark(theme::BaseColor::Black) => Box::new(tcolor::Black),
        theme::Color::Dark(theme::BaseColor::Red) => Box::new(tcolor::Red),
        theme::Color::Dark(theme::BaseColor::Green) => Box::new(tcolor::Green),
        theme::Color::Dark(theme::BaseColor::Yellow) => {
            Box::new(tcolor::Yellow)
        }
        theme::Color::Dark(theme::BaseColor::Blue) => Box::new(tcolor::Blue),
        theme::Color::Dark(theme::BaseColor::Magenta) => {
            Box::new(tcolor::Magenta)
        }
        theme::Color::Dark(theme::BaseColor::Cyan) => Box::new(tcolor::Cyan),
        theme::Color::Dark(theme::BaseColor::White) => Box::new(tcolor::White),

        theme::Color::Light(theme::BaseColor::Black) => {
            Box::new(tcolor::LightBlack)
        }
        theme::Color::Light(theme::BaseColor::Red) => {
            Box::new(tcolor::LightRed)
        }
        theme::Color::Light(theme::BaseColor::Green) => {
            Box::new(tcolor::LightGreen)
        }
        theme::Color::Light(theme::BaseColor::Yellow) => {
            Box::new(tcolor::LightYellow)
        }
        theme::Color::Light(theme::BaseColor::Blue) => {
            Box::new(tcolor::LightBlue)
        }
        theme::Color::Light(theme::BaseColor::Magenta) => {
            Box::new(tcolor::LightMagenta)
        }
        theme::Color::Light(theme::BaseColor::Cyan) => {
            Box::new(tcolor::LightCyan)
        }
        theme::Color::Light(theme::BaseColor::White) => {
            Box::new(tcolor::LightWhite)
        }

        theme::Color::Rgb(r, g, b) => Box::new(tcolor::Rgb(r, g, b)),
        theme::Color::RgbLowRes(r, g, b) => {
            Box::new(tcolor::AnsiValue::rgb(r, g, b))
        }
    }
}
<commit_msg>Add termion AlternateScreen support<commit_after>extern crate termion;

extern crate chan_signal;

use self::termion::color as tcolor;
use self::termion::event::Event as TEvent;
use self::termion::event::Key as TKey;
use self::termion::input::TermRead;
use self::termion::raw::IntoRawMode;
use self::termion::screen::AlternateScreen;
use self::termion::style as tstyle;
use backend;
use chan;
use event::{Event, Key};
use std::cell::Cell;
use std::collections::BTreeMap;
use std::fmt;
use std::io::Write;
use std::thread;

use theme;

pub struct Concrete {
    terminal: AlternateScreen<termion::raw::RawTerminal<::std::io::Stdout>>,
    current_style: Cell<theme::ColorStyle>,
    colors: BTreeMap<i16, (Box<tcolor::Color>, Box<tcolor::Color>)>,

    input: chan::Receiver<Event>,
    resize: chan::Receiver<chan_signal::Signal>,
    timeout: Option<u32>,
}

trait Effectable {
    fn on(&self);
    fn off(&self);
}

struct ColorRef<'a>(&'a tcolor::Color);

impl<'a> tcolor::Color for ColorRef<'a> {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_fg(f)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_bg(f)
    }
}

impl Effectable for theme::Effect {
    fn on(&self) {
        match *self {
            theme::Effect::Simple => (),
            theme::Effect::Reverse => print!("{}", tstyle::Invert),
        }
    }

    fn off(&self) {
        match *self {
            theme::Effect::Simple => (),
            theme::Effect::Reverse => print!("{}", tstyle::NoInvert),
        }
    }
}

fn apply_colors(fg: &tcolor::Color, bg: &tcolor::Color) {
    print!("{}{}", tcolor::Fg(ColorRef(fg)), tcolor::Bg(ColorRef(bg)));
}

impl Concrete {
    fn apply_colorstyle(&self, color_style: theme::ColorStyle) {
        let (ref fg, ref bg) = self.colors[&color_style.id()];
        apply_colors(&**fg, &**bg);
    }
}

impl backend::Backend for Concrete {
    fn init() -> Self {
        print!("{}", termion::cursor::Hide);

        let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]);

        let terminal = AlternateScreen::from(::std::io::stdout().into_raw_mode().unwrap());
        let (sender, receiver) = chan::async();

        thread::spawn(move || for key in ::std::io::stdin().events() {
                          if let Ok(key) = key {
                              sender.send(map_key(key))
                          }
                      });

        let backend = Concrete {
            terminal: terminal,
            current_style: Cell::new(theme::ColorStyle::Background),
            colors: BTreeMap::new(),
            input: receiver,
            resize: resize,
            timeout: None,
        };

        backend
    }

    fn finish(&mut self) {
        print!("{}{}", termion::cursor::Show, termion::cursor::Goto(1, 1));
        print!("{}[49m{}[39m{}",
               27 as char,
               27 as char,
               termion::clear::All);
    }

    fn init_color_style(&mut self, style: theme::ColorStyle,
                        foreground: &theme::Color, background: &theme::Color) {
        // Step 1: convert foreground and background into proper termion Color
        self.colors.insert(style.id(),
                           (colour_to_termion_colour(foreground),
                            colour_to_termion_colour(background)));
    }

    fn with_color<F: FnOnce()>(&self, color: theme::ColorStyle, f: F) {
        let current_style = self.current_style.get();

        self.apply_colorstyle(color);

        self.current_style.set(color);
        f();
        self.current_style.set(current_style);

        self.apply_colorstyle(current_style);
    }

    fn with_effect<F: FnOnce()>(&self, effect: theme::Effect, f: F) {
        effect.on();
        f();
        effect.off();
    }

    fn has_colors(&self) -> bool {
        // TODO: color support detection?
        true
    }

    fn screen_size(&self) -> (usize, usize) {
        let (x, y) = termion::terminal_size().unwrap_or((1, 1));
        (x as usize, y as usize)
    }

    fn clear(&self) {
        self.apply_colorstyle(theme::ColorStyle::Background);
        print!("{}", termion::clear::All);
    }

    fn refresh(&mut self) {
        self.terminal.flush().unwrap();
    }

    fn print_at(&self, (x, y): (usize, usize), text: &str) {
        print!("{}{}",
               termion::cursor::Goto(1 + x as u16, 1 + y as u16),
               text);
    }

    fn set_refresh_rate(&mut self, fps: u32) {
        self.timeout = Some(1000 / fps as u32);
    }

    fn poll_event(&self) -> Event {
        let input = &self.input;
        let resize = &self.resize;

        if let Some(timeout) = self.timeout {
            let timeout = chan::after_ms(timeout);
            chan_select!{
                timeout.recv() => return Event::Refresh,
                resize.recv() => return Event::WindowResize,
                input.recv() -> input => return input.unwrap(),
            }
        } else {
            chan_select!{
                resize.recv() => return Event::WindowResize,
                input.recv() -> input => return input.unwrap(),
            }
        }
    }
}

fn map_key(event: TEvent) -> Event {
    match event {
        TEvent::Unsupported(bytes) => Event::Unknown(bytes),
        TEvent::Key(TKey::Esc) => Event::Key(Key::Esc),
        TEvent::Key(TKey::Backspace) => Event::Key(Key::Backspace),
        TEvent::Key(TKey::Left) => Event::Key(Key::Left),
        TEvent::Key(TKey::Right) => Event::Key(Key::Right),
        TEvent::Key(TKey::Up) => Event::Key(Key::Up),
        TEvent::Key(TKey::Down) => Event::Key(Key::Down),
        TEvent::Key(TKey::Home) => Event::Key(Key::Home),
        TEvent::Key(TKey::End) => Event::Key(Key::End),
        TEvent::Key(TKey::PageUp) => Event::Key(Key::PageUp),
        TEvent::Key(TKey::PageDown) => Event::Key(Key::PageDown),
        TEvent::Key(TKey::Delete) => Event::Key(Key::Del),
        TEvent::Key(TKey::Insert) => Event::Key(Key::Ins),
        TEvent::Key(TKey::F(i)) if i < 12 => Event::Key(Key::from_f(i)),
        TEvent::Key(TKey::F(j)) => Event::Unknown(vec![j]),
        TEvent::Key(TKey::Char('\n')) => Event::Key(Key::Enter),
        TEvent::Key(TKey::Char('\t')) => Event::Key(Key::Tab),
        TEvent::Key(TKey::Char(c)) => Event::Char(c),
        TEvent::Key(TKey::Ctrl('c')) => Event::Exit,
        TEvent::Key(TKey::Ctrl(c)) => Event::CtrlChar(c),
        TEvent::Key(TKey::Alt(c)) => Event::AltChar(c),
        _ => Event::Unknown(vec![]),
    }

}

fn colour_to_termion_colour(clr: &theme::Color) -> Box<tcolor::Color> {
    match *clr {
        theme::Color::Dark(theme::BaseColor::Black) => Box::new(tcolor::Black),
        theme::Color::Dark(theme::BaseColor::Red) => Box::new(tcolor::Red),
        theme::Color::Dark(theme::BaseColor::Green) => Box::new(tcolor::Green),
        theme::Color::Dark(theme::BaseColor::Yellow) => {
            Box::new(tcolor::Yellow)
        }
        theme::Color::Dark(theme::BaseColor::Blue) => Box::new(tcolor::Blue),
        theme::Color::Dark(theme::BaseColor::Magenta) => {
            Box::new(tcolor::Magenta)
        }
        theme::Color::Dark(theme::BaseColor::Cyan) => Box::new(tcolor::Cyan),
        theme::Color::Dark(theme::BaseColor::White) => Box::new(tcolor::White),

        theme::Color::Light(theme::BaseColor::Black) => {
            Box::new(tcolor::LightBlack)
        }
        theme::Color::Light(theme::BaseColor::Red) => {
            Box::new(tcolor::LightRed)
        }
        theme::Color::Light(theme::BaseColor::Green) => {
            Box::new(tcolor::LightGreen)
        }
        theme::Color::Light(theme::BaseColor::Yellow) => {
            Box::new(tcolor::LightYellow)
        }
        theme::Color::Light(theme::BaseColor::Blue) => {
            Box::new(tcolor::LightBlue)
        }
        theme::Color::Light(theme::BaseColor::Magenta) => {
            Box::new(tcolor::LightMagenta)
        }
        theme::Color::Light(theme::BaseColor::Cyan) => {
            Box::new(tcolor::LightCyan)
        }
        theme::Color::Light(theme::BaseColor::White) => {
            Box::new(tcolor::LightWhite)
        }

        theme::Color::Rgb(r, g, b) => Box::new(tcolor::Rgb(r, g, b)),
        theme::Color::RgbLowRes(r, g, b) => {
            Box::new(tcolor::AnsiValue::rgb(r, g, b))
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "image")]
use image;

/// A trait that must be implemented for any type that can represent the value of a pixel.
#[experimental = "Will be rewritten after UFCS land"]
pub trait PixelValue: Copy + Send {     // TODO: Clone, but [T, ..N] doesn't impl Clone
    /// Returns corresponding client format.
    fn get_format(_: Option<Self>) -> super::ClientFormat;
}

impl PixelValue for i8 {
    fn get_format(_: Option<i8>) -> super::ClientFormat {
        super::ClientFormat::I8
    }
}

impl PixelValue for (i8, i8) {
    fn get_format(_: Option<(i8, i8)>) -> super::ClientFormat {
        super::ClientFormat::I8I8
    }
}

impl PixelValue for (i8, i8, i8) {
    fn get_format(_: Option<(i8, i8, i8)>) -> super::ClientFormat {
        super::ClientFormat::I8I8I8
    }
}

impl PixelValue for (i8, i8, i8, i8) {
    fn get_format(_: Option<(i8, i8, i8, i8)>) -> super::ClientFormat {
        super::ClientFormat::I8I8I8I8
    }
}

impl PixelValue for u8 {
    fn get_format(_: Option<u8>) -> super::ClientFormat {
        super::ClientFormat::U8
    }
}

impl PixelValue for (u8, u8) {
    fn get_format(_: Option<(u8, u8)>) -> super::ClientFormat {
        super::ClientFormat::U8U8
    }
}

impl PixelValue for (u8, u8, u8) {
    fn get_format(_: Option<(u8, u8, u8)>) -> super::ClientFormat {
        super::ClientFormat::U8U8U8
    }
}

impl PixelValue for (u8, u8, u8, u8) {
    fn get_format(_: Option<(u8, u8, u8, u8)>) -> super::ClientFormat {
        super::ClientFormat::U8U8U8U8
    }
}

impl PixelValue for i16 {
    fn get_format(_: Option<i16>) -> super::ClientFormat {
        super::ClientFormat::I16
    }
}

impl PixelValue for (i16, i16) {
    fn get_format(_: Option<(i16, i16)>) -> super::ClientFormat {
        super::ClientFormat::I16I16
    }
}

impl PixelValue for (i16, i16, i16) {
    fn get_format(_: Option<(i16, i16, i16)>) -> super::ClientFormat {
        super::ClientFormat::I16I16I16
    }
}

impl PixelValue for (i16, i16, i16, i16) {
    fn get_format(_: Option<(i16, i16, i16, i16)>) -> super::ClientFormat {
        super::ClientFormat::I16I16I16I16
    }
}

impl PixelValue for u16 {
    fn get_format(_: Option<u16>) -> super::ClientFormat {
        super::ClientFormat::U16
    }
}

impl PixelValue for (u16, u16) {
    fn get_format(_: Option<(u16, u16)>) -> super::ClientFormat {
        super::ClientFormat::U16U16
    }
}

impl PixelValue for (u16, u16, u16) {
    fn get_format(_: Option<(u16, u16, u16)>) -> super::ClientFormat {
        super::ClientFormat::U16U16U16
    }
}

impl PixelValue for (u16, u16, u16, u16) {
    fn get_format(_: Option<(u16, u16, u16, u16)>) -> super::ClientFormat {
        super::ClientFormat::U16U16U16U16
    }
}

impl PixelValue for i32 {
    fn get_format(_: Option<i32>) -> super::ClientFormat {
        super::ClientFormat::I32
    }
}

impl PixelValue for (i32, i32) {
    fn get_format(_: Option<(i32, i32)>) -> super::ClientFormat {
        super::ClientFormat::I32I32
    }
}

impl PixelValue for (i32, i32, i32) {
    fn get_format(_: Option<(i32, i32, i32)>) -> super::ClientFormat {
        super::ClientFormat::I32I32I32
    }
}

impl PixelValue for (i32, i32, i32, i32) {
    fn get_format(_: Option<(i32, i32, i32, i32)>) -> super::ClientFormat {
        super::ClientFormat::I32I32I32I32
    }
}

impl PixelValue for u32 {
    fn get_format(_: Option<u32>) -> super::ClientFormat {
        super::ClientFormat::U32
    }
}

impl PixelValue for (u32, u32) {
    fn get_format(_: Option<(u32, u32)>) -> super::ClientFormat {
        super::ClientFormat::U32U32
    }
}

impl PixelValue for (u32, u32, u32) {
    fn get_format(_: Option<(u32, u32, u32)>) -> super::ClientFormat {
        super::ClientFormat::U32U32U32
    }
}

impl PixelValue for (u32, u32, u32, u32) {
    fn get_format(_: Option<(u32, u32, u32, u32)>) -> super::ClientFormat {
        super::ClientFormat::U32U32U32U32
    }
}

impl PixelValue for f32 {
    fn get_format(_: Option<f32>) -> super::ClientFormat {
        super::ClientFormat::F32
    }
}

impl PixelValue for (f32, f32) {
    fn get_format(_: Option<(f32, f32)>) -> super::ClientFormat {
        super::ClientFormat::F32F32
    }
}

impl PixelValue for (f32, f32, f32) {
    fn get_format(_: Option<(f32, f32, f32)>) -> super::ClientFormat {
        super::ClientFormat::F32F32F32
    }
}

impl PixelValue for (f32, f32, f32, f32) {
    fn get_format(_: Option<(f32, f32, f32, f32)>) -> super::ClientFormat {
        super::ClientFormat::F32F32F32F32
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Rgb<u8>{
    fn get_format(_: Option<image::Rgb<u8>>) -> super::ClientFormat {
        super::ClientFormat::U8U8U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Rgba<u8> {
    fn get_format(_: Option<image::Rgba<u8>>) -> super::ClientFormat {
        super::ClientFormat::U8U8U8U8
    }
}
<commit_msg>Add PixelValue implementations for Luma/LumaA<commit_after>#[cfg(feature = "image")]
use image;

/// A trait that must be implemented for any type that can represent the value of a pixel.
#[experimental = "Will be rewritten after UFCS land"]
pub trait PixelValue: Copy + Send {     // TODO: Clone, but [T, ..N] doesn't impl Clone
    /// Returns corresponding client format.
    fn get_format(_: Option<Self>) -> super::ClientFormat;
}

impl PixelValue for i8 {
    fn get_format(_: Option<i8>) -> super::ClientFormat {
        super::ClientFormat::I8
    }
}

impl PixelValue for (i8, i8) {
    fn get_format(_: Option<(i8, i8)>) -> super::ClientFormat {
        super::ClientFormat::I8I8
    }
}

impl PixelValue for (i8, i8, i8) {
    fn get_format(_: Option<(i8, i8, i8)>) -> super::ClientFormat {
        super::ClientFormat::I8I8I8
    }
}

impl PixelValue for (i8, i8, i8, i8) {
    fn get_format(_: Option<(i8, i8, i8, i8)>) -> super::ClientFormat {
        super::ClientFormat::I8I8I8I8
    }
}

impl PixelValue for u8 {
    fn get_format(_: Option<u8>) -> super::ClientFormat {
        super::ClientFormat::U8
    }
}

impl PixelValue for (u8, u8) {
    fn get_format(_: Option<(u8, u8)>) -> super::ClientFormat {
        super::ClientFormat::U8U8
    }
}

impl PixelValue for (u8, u8, u8) {
    fn get_format(_: Option<(u8, u8, u8)>) -> super::ClientFormat {
        super::ClientFormat::U8U8U8
    }
}

impl PixelValue for (u8, u8, u8, u8) {
    fn get_format(_: Option<(u8, u8, u8, u8)>) -> super::ClientFormat {
        super::ClientFormat::U8U8U8U8
    }
}

impl PixelValue for i16 {
    fn get_format(_: Option<i16>) -> super::ClientFormat {
        super::ClientFormat::I16
    }
}

impl PixelValue for (i16, i16) {
    fn get_format(_: Option<(i16, i16)>) -> super::ClientFormat {
        super::ClientFormat::I16I16
    }
}

impl PixelValue for (i16, i16, i16) {
    fn get_format(_: Option<(i16, i16, i16)>) -> super::ClientFormat {
        super::ClientFormat::I16I16I16
    }
}

impl PixelValue for (i16, i16, i16, i16) {
    fn get_format(_: Option<(i16, i16, i16, i16)>) -> super::ClientFormat {
        super::ClientFormat::I16I16I16I16
    }
}

impl PixelValue for u16 {
    fn get_format(_: Option<u16>) -> super::ClientFormat {
        super::ClientFormat::U16
    }
}

impl PixelValue for (u16, u16) {
    fn get_format(_: Option<(u16, u16)>) -> super::ClientFormat {
        super::ClientFormat::U16U16
    }
}

impl PixelValue for (u16, u16, u16) {
    fn get_format(_: Option<(u16, u16, u16)>) -> super::ClientFormat {
        super::ClientFormat::U16U16U16
    }
}

impl PixelValue for (u16, u16, u16, u16) {
    fn get_format(_: Option<(u16, u16, u16, u16)>) -> super::ClientFormat {
        super::ClientFormat::U16U16U16U16
    }
}

impl PixelValue for i32 {
    fn get_format(_: Option<i32>) -> super::ClientFormat {
        super::ClientFormat::I32
    }
}

impl PixelValue for (i32, i32) {
    fn get_format(_: Option<(i32, i32)>) -> super::ClientFormat {
        super::ClientFormat::I32I32
    }
}

impl PixelValue for (i32, i32, i32) {
    fn get_format(_: Option<(i32, i32, i32)>) -> super::ClientFormat {
        super::ClientFormat::I32I32I32
    }
}

impl PixelValue for (i32, i32, i32, i32) {
    fn get_format(_: Option<(i32, i32, i32, i32)>) -> super::ClientFormat {
        super::ClientFormat::I32I32I32I32
    }
}

impl PixelValue for u32 {
    fn get_format(_: Option<u32>) -> super::ClientFormat {
        super::ClientFormat::U32
    }
}

impl PixelValue for (u32, u32) {
    fn get_format(_: Option<(u32, u32)>) -> super::ClientFormat {
        super::ClientFormat::U32U32
    }
}

impl PixelValue for (u32, u32, u32) {
    fn get_format(_: Option<(u32, u32, u32)>) -> super::ClientFormat {
        super::ClientFormat::U32U32U32
    }
}

impl PixelValue for (u32, u32, u32, u32) {
    fn get_format(_: Option<(u32, u32, u32, u32)>) -> super::ClientFormat {
        super::ClientFormat::U32U32U32U32
    }
}

impl PixelValue for f32 {
    fn get_format(_: Option<f32>) -> super::ClientFormat {
        super::ClientFormat::F32
    }
}

impl PixelValue for (f32, f32) {
    fn get_format(_: Option<(f32, f32)>) -> super::ClientFormat {
        super::ClientFormat::F32F32
    }
}

impl PixelValue for (f32, f32, f32) {
    fn get_format(_: Option<(f32, f32, f32)>) -> super::ClientFormat {
        super::ClientFormat::F32F32F32
    }
}

impl PixelValue for (f32, f32, f32, f32) {
    fn get_format(_: Option<(f32, f32, f32, f32)>) -> super::ClientFormat {
        super::ClientFormat::F32F32F32F32
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Rgb<u8> {
    fn get_format(_: Option<image::Rgb<u8>>) -> super::ClientFormat {
        super::ClientFormat::U8U8U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Rgba<u8> {
    fn get_format(_: Option<image::Rgba<u8>>) -> super::ClientFormat {
        super::ClientFormat::U8U8U8U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Luma<u8> {
    fn get_format(_: Option<image::Luma<u8>>) -> super::ClientFormat {
        super::ClientFormat::U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Luma<u16> {
    fn get_format(_: Option<image::Luma<u16>>) -> super::ClientFormat {
        super::ClientFormat::U16
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Luma<f32> {
    fn get_format(_: Option<image::Luma<f32>>) -> super::ClientFormat {
        super::ClientFormat::F32
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::LumaA<u8> {
    fn get_format(_: Option<image::LumaA<u8>>) -> super::ClientFormat {
        super::ClientFormat::U8U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::LumaA<u16> {
    fn get_format(_: Option<image::LumaA<u16>>) -> super::ClientFormat {
        super::ClientFormat::U16U16
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::LumaA<f32> {
    fn get_format(_: Option<image::LumaA<f32>>) -> super::ClientFormat {
        super::ClientFormat::F32F32
    }
}
<|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/. */

use syntax::ext::base::ExtCtxt;
use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::ast::{Item, MetaItem, Expr};
use syntax::ast;
use syntax::attr;
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::{combine_substructure, EnumMatching, FieldInfo, MethodDef, Struct, Substructure, TraitDef, ty};
use syntax::parse::token::InternedString;

pub fn expand_dom_struct(_: &mut ExtCtxt, _: Span, _: &MetaItem, item: P<Item>) -> P<Item> {
    let mut item2 = (*item).clone();
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("must_root"))));
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("privatize"))));
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("jstraceable"))));
    //expand_jstraceable_inner(cx, span, mitem, &*item, |_| ());
    P(item2)
}

pub fn expand_jstraceable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Item, push: |P<Item>|) {
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: ty::Path::new(vec!("dom","bindings","trace","JSTraceable")),
        additional_bounds: Vec::new(),
        generics: ty::LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "trace",
                generics: ty::LifetimeBounds::empty(),
                explicit_self: ty::borrowed_explicit_self(),
                args: vec!(ty::Ptr(box ty::Literal(ty::Path::new(vec!("js","jsapi","JSTracer"))), ty::Raw(ast::MutMutable))),
                ret_ty: ty::nil_ty(),
                attributes: vec!(),
                combine_substructure: combine_substructure(|a, b, c| {
                    jstraceable_substructure(a, b, c)
                })
            }
        )
    };
    trait_def.expand(cx, mitem, item, push)
}

// Mostly copied from syntax::ext::deriving::hash
fn jstraceable_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    let state_expr = match substr.nonself_args {
        [ref state_expr] => state_expr,
        _ => cx.span_bug(trait_span, "incorrect number of arguments in `jstraceable`")
    };
    let trace_ident = substr.method_ident;
    let call_trace = |span, thing_expr| {
        let expr = cx.expr_method_call(span, thing_expr, trace_ident, vec!(state_expr.clone()));
        cx.stmt_expr(expr)
    };
    let mut stmts = Vec::new();

    let fields = match *substr.fields {
        Struct(ref fs) | EnumMatching(_, _, ref fs) => fs,
        _ => cx.span_bug(trait_span, "impossible substructure in `jstraceable`")
    };

    for &FieldInfo { ref self_, span, .. } in fields.iter() {
        stmts.push(call_trace(span, self_.clone()));
    }

    cx.expr_block(cx.block(trait_span, stmts, None))
}
<commit_msg>Make auto-derived JSTraceable have #[inline] methods<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/. */

use syntax::ext::base::ExtCtxt;
use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::ast::{Item, MetaItem, Expr};
use syntax::ast;
use syntax::attr;
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::{combine_substructure, EnumMatching, FieldInfo, MethodDef, Struct, Substructure, TraitDef, ty};
use syntax::parse::token::InternedString;

pub fn expand_dom_struct(_: &mut ExtCtxt, _: Span, _: &MetaItem, item: P<Item>) -> P<Item> {
    let mut item2 = (*item).clone();
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("must_root"))));
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("privatize"))));
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("jstraceable"))));
    P(item2)
}

pub fn expand_jstraceable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Item, push: |P<Item>|) {
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: ty::Path::new(vec!("dom","bindings","trace","JSTraceable")),
        additional_bounds: Vec::new(),
        generics: ty::LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "trace",
                generics: ty::LifetimeBounds::empty(),
                explicit_self: ty::borrowed_explicit_self(),
                args: vec!(ty::Ptr(box ty::Literal(ty::Path::new(vec!("js","jsapi","JSTracer"))), ty::Raw(ast::MutMutable))),
                ret_ty: ty::nil_ty(),
                attributes: vec!(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("inline")))),
                combine_substructure: combine_substructure(|a, b, c| {
                    jstraceable_substructure(a, b, c)
                })
            }
        )
    };
    trait_def.expand(cx, mitem, item, push)
}

// Mostly copied from syntax::ext::deriving::hash
fn jstraceable_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    let state_expr = match substr.nonself_args {
        [ref state_expr] => state_expr,
        _ => cx.span_bug(trait_span, "incorrect number of arguments in `jstraceable`")
    };
    let trace_ident = substr.method_ident;
    let call_trace = |span, thing_expr| {
        let expr = cx.expr_method_call(span, thing_expr, trace_ident, vec!(state_expr.clone()));
        cx.stmt_expr(expr)
    };
    let mut stmts = Vec::new();

    let fields = match *substr.fields {
        Struct(ref fs) | EnumMatching(_, _, ref fs) => fs,
        _ => cx.span_bug(trait_span, "impossible substructure in `jstraceable`")
    };

    for &FieldInfo { ref self_, span, .. } in fields.iter() {
        stmts.push(call_trace(span, self_.clone()));
    }

    cx.expr_block(cx.block(trait_span, stmts, None))
}
<|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/. */

use cg::{self, WhereClause};
use darling::util::Override;
use quote::{ToTokens, Tokens};
use syn::{self, Data};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(input: syn::DeriveInput) -> Tokens {
    let name = &input.ident;
    let trait_path = parse_quote!(::style_traits::ToCss);
    let (impl_generics, ty_generics, mut where_clause) =
        cg::trait_parts(&input, &trait_path);

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    if let Data::Enum(_) = input.data {
        assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums");
        assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
    }
    let s = Structure::new(&input);

    let match_body = s.each_variant(|variant| {
        derive_variant_arm(variant, &mut where_clause)
    });

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    where_clause: &mut WhereClause,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        let keyword = keyword.to_string();
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        derive_variant_fields_expr(bindings, where_clause, separator)
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

fn derive_variant_fields_expr(
    bindings: &[BindingInfo],
    where_clause: &mut WhereClause,
    separator: &str,
) -> Tokens {
    let mut iter = bindings.iter().filter_map(|binding| {
        let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
        if attrs.skip {
            return None;
        }
        Some((binding, attrs))
    }).peekable();

    let (first, attrs) = match iter.next() {
        Some(pair) => pair,
        None => return quote! { Ok(()) },
    };
    if !attrs.iterable && iter.peek().is_none() {
        if !attrs.ignore_bound {
            where_clause.add_trait_bound(&first.ast().ty);
        }
        return quote! { ::style_traits::ToCss::to_css(#first, dest) };
    }

    let mut expr = derive_single_field_expr(first, attrs, where_clause);
    for (binding, attrs) in iter {
        derive_single_field_expr(binding, attrs, where_clause).to_tokens(&mut expr)
    }

    quote! {{
        let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
        #expr
        Ok(())
    }}
}

fn derive_single_field_expr(
    field: &BindingInfo,
    attrs: CssFieldAttrs,
    where_clause: &mut WhereClause,
) -> Tokens {
    if attrs.iterable {
        if let Some(if_empty) = attrs.if_empty {
            return quote! {
                {
                    let mut iter = #field.iter().peekable();
                    if iter.peek().is_none() {
                        writer.item(&::style_traits::values::Verbatim(#if_empty))?;
                    } else {
                        for item in iter {
                            writer.item(&item)?;
                        }
                    }
                }
            };
        }
        quote! {
            for item in #field.iter() {
                writer.item(&item)?;
            }
        }
    } else {
        if !attrs.ignore_bound {
            where_clause.add_trait_bound(&field.ast().ty);
        }
        quote! { writer.item(#field)?; }
    }
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    if_empty: Option<String>,
    ignore_bound: bool,
    iterable: bool,
    skip: bool,
}
<commit_msg>style: Remove useless String::to_string call.<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/. */

use cg::{self, WhereClause};
use darling::util::Override;
use quote::{ToTokens, Tokens};
use syn::{self, Data};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(input: syn::DeriveInput) -> Tokens {
    let name = &input.ident;
    let trait_path = parse_quote!(::style_traits::ToCss);
    let (impl_generics, ty_generics, mut where_clause) =
        cg::trait_parts(&input, &trait_path);

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    if let Data::Enum(_) = input.data {
        assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums");
        assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
    }
    let s = Structure::new(&input);

    let match_body = s.each_variant(|variant| {
        derive_variant_arm(variant, &mut where_clause)
    });

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    where_clause: &mut WhereClause,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        derive_variant_fields_expr(bindings, where_clause, separator)
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

fn derive_variant_fields_expr(
    bindings: &[BindingInfo],
    where_clause: &mut WhereClause,
    separator: &str,
) -> Tokens {
    let mut iter = bindings.iter().filter_map(|binding| {
        let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
        if attrs.skip {
            return None;
        }
        Some((binding, attrs))
    }).peekable();

    let (first, attrs) = match iter.next() {
        Some(pair) => pair,
        None => return quote! { Ok(()) },
    };
    if !attrs.iterable && iter.peek().is_none() {
        if !attrs.ignore_bound {
            where_clause.add_trait_bound(&first.ast().ty);
        }
        return quote! { ::style_traits::ToCss::to_css(#first, dest) };
    }

    let mut expr = derive_single_field_expr(first, attrs, where_clause);
    for (binding, attrs) in iter {
        derive_single_field_expr(binding, attrs, where_clause).to_tokens(&mut expr)
    }

    quote! {{
        let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
        #expr
        Ok(())
    }}
}

fn derive_single_field_expr(
    field: &BindingInfo,
    attrs: CssFieldAttrs,
    where_clause: &mut WhereClause,
) -> Tokens {
    if attrs.iterable {
        if let Some(if_empty) = attrs.if_empty {
            return quote! {
                {
                    let mut iter = #field.iter().peekable();
                    if iter.peek().is_none() {
                        writer.item(&::style_traits::values::Verbatim(#if_empty))?;
                    } else {
                        for item in iter {
                            writer.item(&item)?;
                        }
                    }
                }
            };
        }
        quote! {
            for item in #field.iter() {
                writer.item(&item)?;
            }
        }
    } else {
        if !attrs.ignore_bound {
            where_clause.add_trait_bound(&field.ast().ty);
        }
        quote! { writer.item(#field)?; }
    }
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    if_empty: Option<String>,
    ignore_bound: bool,
    iterable: bool,
    skip: bool,
}
<|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/. */

use syn;

use bindgen::ir::Type;
use bindgen::utilities::IterHelpers;

pub type Path = String;

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct GenericPath {
    pub name: String,
    pub generics: Vec<Type>,
}

impl GenericPath {
    pub fn new(name: String, generics: Vec<Type>) -> GenericPath {
        GenericPath {
            name: name,
            generics: generics,
        }
    }

    pub fn load(path: &syn::Path) -> Result<GenericPath, String> {
        if path.segments.len() != 1 {
            return Err(format!("path contains more than one segment"));
        }

        let name = path.segments[0].ident.to_string();

        if name == "PhantomData" {
            return Ok(GenericPath::new(name, Vec::new()));
        }

        let generics = match &path.segments[0].parameters {
            &syn::PathParameters::AngleBracketed(ref d) => {
                if !d.lifetimes.is_empty() ||
                   !d.bindings.is_empty() {
                    return Err(format!("path generic parameter contains bindings, or lifetimes"));
                }

                d.types.iter()
                       .try_skip_map(|x| Type::load(x))?
            }
            &syn::PathParameters::Parenthesized(_) => {
                return Err(format!("path contains parentheses"));
            }
        };

        Ok(GenericPath::new(name, generics))
    }
}
<commit_msg>Ignore lifetimes or bindings in path parameters<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/. */

use syn;

use bindgen::ir::Type;
use bindgen::utilities::IterHelpers;

pub type Path = String;

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct GenericPath {
    pub name: String,
    pub generics: Vec<Type>,
}

impl GenericPath {
    pub fn new(name: String, generics: Vec<Type>) -> GenericPath {
        GenericPath {
            name: name,
            generics: generics,
        }
    }

    pub fn load(path: &syn::Path) -> Result<GenericPath, String> {
        if path.segments.len() != 1 {
            return Err(format!("path contains more than one segment"));
        }

        let name = path.segments[0].ident.to_string();

        if name == "PhantomData" {
            return Ok(GenericPath::new(name, Vec::new()));
        }

        let generics = match &path.segments[0].parameters {
            &syn::PathParameters::AngleBracketed(ref d) => {
                d.types.iter()
                       .try_skip_map(|x| Type::load(x))?
            }
            &syn::PathParameters::Parenthesized(_) => {
                return Err(format!("path contains parentheses"));
            }
        };

        Ok(GenericPath::new(name, generics))
    }
}
<|endoftext|>


<commit_before>//! The `ztext` module contains encoding functions to encode text in z-ascii characters.
//!

use super::zbytes::Bytes;

pub static ALPHABET: [char; 78] = [
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',

    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',

    '\0', '^', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.',
    ',', '!', '?', '_', '#', '\'','"', '/', '\\','-', ':', '(', ')'];

/// encodes an string to z-characters
/// and returns the length of the used bytes
/// TODO: Only works with lower case letters
///
/// # Examples
///
/// ```ignore
/// let data = Bytes{bytes: Vec::new()};
/// let byteLength = data.encode("hello");
/// ```
pub fn encode(data: &mut Bytes, content: &str) -> u16 {
    let zchars: Vec<u8> = string_to_zchar(content);

    let mut two_bytes: u16 = 0;
    let len = zchars.len();
    for i in 0..len {
        let zasci_id =zchars[i];

        two_bytes |= shift(zasci_id as u16, i as u8);

        if i % 3 == 2 {
            data.write_u16(two_bytes, pos_to_index(i));
            two_bytes = 0;
        }

        // end of string
        if i == len -1 {
            if i % 3 != 2 {
                for j in (i % 3) + 1..3 {
                    two_bytes |= shift(0x05 as u16, j as u8);
                }

                data.write_u16(two_bytes, pos_to_index(i));
            }

            // end bit is written to the first bit of the next to last byte
            let end_index: usize = data.bytes.len() - 2 as usize;
            let mut end_byte: u8 = data.bytes[end_index];

            end_byte |= 0x80;
            data.write_byte(end_byte, end_index as usize);
        }
    }

    data.bytes.len() as u16
}

/// reads the content and converts it to a zasci vector
fn string_to_zchar(content: &str) -> Vec<u8> {
    println!("string_to_zchar: {:?}", content);
    let string_bytes = content.to_string().into_bytes();
        let mut zchars: Vec<u8> = Vec::new();
        for i in string_bytes{
            let t_index = pos_in_alpha(i as u8);
            if i == 0x0A {
                zchars.push(0x05);
                zchars.push(7);
            } else if i == 0x20 {
                //zchars.push(0x05);
                //zchars.push(0);
                zchars.push(0x00);
            }
            else {
                if t_index >51 {
                    zchars.push(0x05);
                    zchars.push(t_index as u8 % 26 + 6);
                } else if t_index <26 {
                    zchars.push(t_index as u8 % 26 + 6);
                }
                 else {
                    zchars.push(0x04);
                    zchars.push(t_index as u8 % 26 + 6);
                }
            }
        }
    zchars
}

/// shifts the z-char in a 2 bytes-array to the right position
/// shift_length has 3 possibilities: 10, 5, 0
/// an z-char use 5 bytes
/// look into two bytes:
/// ____byte one____ ____byte two____
/// 1 2 3 4 5 6  7 8 1 2 3  4 5 6 7 8
///   ^          ^          1
///   1 2 3 4 5  1 2 3 4 5  1 2 3 4 5
///   1. zchar   2. zchar   3. zchar
///   10         5          0
fn shift(zchar: u16, position: u8) -> u16 {
    let shift_length = 10 - (position % 3) * 5;
    zchar << shift_length
}

/// Returns the location of the character of the specified index in the zcode character array
///
/// # Examples
///
/// ```ignore
/// assert_eq!(pos_in_alpha('c'), 2);
/// ```
fn pos_in_alpha(letter: u8) -> i8 {
    for i in 0..ALPHABET.len() {
        if ALPHABET[i] as u8 == letter {
            return i as i8
        }
    }

    return -1
}

/// position in the vector from the position of an character in the string
/// every 3 zchars encode() writes 2 bytes
/// for example "helloworld"
/// "h": nothing
/// "e": nothing
/// "l": write 2 bytes to position 0   (2 * 2/3))
/// "l": nothing
/// "o": nothing
/// "w": write 2 bytes to position 2   (2 * 5/3))
/// ...
///
/// # Examples
///
/// ```ignore
/// assert_eq!(pos_to_index(5), 2);
/// ```
fn pos_to_index(position: usize) -> usize {
    2 * (position / 3)
}
<commit_msg>full ascii support (without ^)<commit_after>//! The `ztext` module contains encoding functions to encode text in z-ascii characters.
//!

use super::zbytes::Bytes;

pub static ALPHABET: [char; 78] = [
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',

    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',

    '\0', '^', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.',
    ',', '!', '?', '_', '#', '\'','"', '/', '\\','-', ':', '(', ')'];

/// encodes an string to z-characters
/// and returns the length of the used bytes
/// TODO: Only works with lower case letters
///
/// # Examples
///
/// ```ignore
/// let data = Bytes{bytes: Vec::new()};
/// let byteLength = data.encode("hello");
/// ```
pub fn encode(data: &mut Bytes, content: &str) -> u16 {
    let zchars: Vec<u8> = string_to_zchar(content);

    let mut two_bytes: u16 = 0;
    let len = zchars.len();
    for i in 0..len {
        let zasci_id =zchars[i];

        two_bytes |= shift(zasci_id as u16, i as u8);

        if i % 3 == 2 {
            data.write_u16(two_bytes, pos_to_index(i));
            two_bytes = 0;
        }

        // end of string
        if i == len -1 {
            if i % 3 != 2 {
                for j in (i % 3) + 1..3 {
                    two_bytes |= shift(0x05 as u16, j as u8);
                }

                data.write_u16(two_bytes, pos_to_index(i));
            }

            // end bit is written to the first bit of the next to last byte
            let end_index: usize = data.bytes.len() - 2 as usize;
            let mut end_byte: u8 = data.bytes[end_index];

            end_byte |= 0x80;
            data.write_byte(end_byte, end_index as usize);
        }
    }

    data.bytes.len() as u16
}

/// reads the content and converts it to a zasci vector
fn string_to_zchar(content: &str) -> Vec<u8> {
    println!("string_to_zchar: {:?}", content);
    let string_bytes = content.to_string().into_bytes();
        let mut zchars: Vec<u8> = Vec::new();
        for byte in string_bytes{
            let t_index = pos_in_alpha(byte as u8);
            if t_index != -1 {
                if byte == 0x0A {
                    // newline?
                    zchars.push(0x05);
                    zchars.push(7);
                } else if byte == 0x20 {
                    // space
                    //zchars.push(0x05);
                    //zchars.push(0);
                    zchars.push(0x00);
                } else {
                    if t_index > 51 {
                        // in A2
                        zchars.push(0x05);
                        zchars.push(t_index as u8 % 26 + 6);
                    } else if t_index < 26 {
                        // in A0
                        zchars.push(t_index as u8 % 26 + 6);
                    } else {
                        // in A1
                        zchars.push(0x04);
                        zchars.push(t_index as u8 % 26 + 6);
                    }
                }
            } else {
                if t_index <= 126 {
                    // ascii, but not in alphabet

                    // to change alphabet
                    zchars.push(0x05);

                    // for special char (10 bit z-ascii)
                    zchars.push(0x06);

                    // char as 10bit
                    //let zchar_10_bit: u16
                    zchars.push(byte >> 5);
                    zchars.push(byte & 0x1f);
                } else {
                    // unicode

                }
            }
        }
    zchars
}

/// shifts the z-char in a 2 bytes-array to the right position
/// shift_length has 3 possibilities: 10, 5, 0
/// an z-char use 5 bytes
/// look into two bytes:
/// ____byte one____ ____byte two____
/// 1 2 3 4 5 6  7 8 1 2 3  4 5 6 7 8
///   ^          ^          1
///   1 2 3 4 5  1 2 3 4 5  1 2 3 4 5
///   1. zchar   2. zchar   3. zchar
///   10         5          0
fn shift(zchar: u16, position: u8) -> u16 {
    let shift_length = 10 - (position % 3) * 5;
    zchar << shift_length
}

/// Returns the location of the character of the specified index in the zcode character array
///
/// # Examples
///
/// ```ignore
/// assert_eq!(pos_in_alpha('c'), 2);
/// ```
fn pos_in_alpha(letter: u8) -> i8 {
    for i in 0..ALPHABET.len() {
        if ALPHABET[i] as u8 == letter {
            return i as i8
        }
    }

    return -1
}

/// position in the vector from the position of an character in the string
/// every 3 zchars encode() writes 2 bytes
/// for example "helloworld"
/// "h": nothing
/// "e": nothing
/// "l": write 2 bytes to position 0   (2 * 2/3))
/// "l": nothing
/// "o": nothing
/// "w": write 2 bytes to position 2   (2 * 5/3))
/// ...
///
/// # Examples
///
/// ```ignore
/// assert_eq!(pos_to_index(5), 2);
/// ```
fn pos_to_index(position: usize) -> usize {
    2 * (position / 3)
}
<|endoftext|>