<commit_before>use self::Token::*;
use self::Element::*;
use self::ComparisonOperator::*;
use regex::Regex;

static MARKUP     : Regex = regex!("\\{%.*?%\\}|\\{\\{.*?\\}\\}");
static TAG        : Regex = regex!("\\{%(.*?)%\\}");
static OUTPUT     : Regex = regex!("\\{\\{(.*?)\\}\\}");
static WHITESPACE : Regex = regex!(r"\s+");

static IDENTIFIER            : Regex = regex!(r"[a-zA-Z_][\w-]*\??");
static SINGLE_STRING_LITERAL : Regex = regex!(r"'[^']*'");
static DOUBLE_STRING_LITERAL : Regex = regex!("\"[^\"]*\"");
static NUMBER_LITERAL        : Regex = regex!(r"-?\d+(\.\d+)?");
static DOTDOT                : Regex = regex!(r"\.\.");

#[deriving(Clone, Show, PartialEq)]
pub enum ComparisonOperator{
    Equals, NotEquals,
    LessThan, GreaterThan,
    LessThanEquals, GreaterThanEquals,
    Contains
}

#[deriving(Clone, Show, PartialEq)]
pub enum Token {
    Pipe,
    Dot,
    Colon,
    Comma,
    OpenSquare,
    CloseSquare,
    OpenRound,
    CloseRound,
    Question,
    Dash,

    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f32),
    DotDot,
    Comparison(ComparisonOperator)
}

#[deriving(Clone, Show, PartialEq)]
pub enum Element{
    Output(Vec<Token>, String),
    Tag(Vec<Token>, String),
    Raw(String)
}

fn split_blocks(text: &str) -> Vec<&str>{
    let mut tokens = vec![];
    let mut current = 0;
    for (begin, end) in MARKUP.find_iter(text) {
        match text.slice(current, begin){
            "" => {}
            t => tokens.push(t)
        };
        tokens.push(text.slice(begin, end));
        current = end;
    }
    match text.slice(current, text.len()){
        "" => {}
        t => tokens.push(t)
    };
    tokens
}

pub fn tokenize(text: &str) -> Vec<Element> {
    split_blocks(text).iter().map(|block| {
        if TAG.is_match(*block) {
            let caps = TAG.captures(*block).unwrap();
            Tag(granularize(caps.at(1)), block.to_string())
        }else if OUTPUT.is_match(*block) {
            let caps = OUTPUT.captures(*block).unwrap();
            Output(granularize(caps.at(1)), block.to_string())
        }else{
            Raw(block.to_string())
        }
    }).collect()
}

fn granularize(block: &str) -> Vec<Token>{
    WHITESPACE.split(block).map(|el|{
        match el {
            "|" => Pipe,
            "." => Dot,
            ":" => Colon,
            "," => Comma,
            "[" => OpenSquare,
            "]" => CloseSquare,
            "(" => OpenRound,
            ")" => CloseRound,
            "?" => Question,
            "-" => Dash,

            "=="       => Comparison(Equals),
            "!="       => Comparison(NotEquals),
            "<="       => Comparison(LessThanEquals),
            ">="       => Comparison(GreaterThanEquals),
            "<"        => Comparison(LessThan),
            ">"        => Comparison(GreaterThan),
            "contains" => Comparison(Contains),

            x if DOTDOT.is_match(x) => DotDot,
            x if SINGLE_STRING_LITERAL.is_match(x) => StringLiteral(x.to_string()),
            x if DOUBLE_STRING_LITERAL.is_match(x) => StringLiteral(x.to_string()),
            x if NUMBER_LITERAL.is_match(x) => NumberLiteral(from_str::<f32>(x).unwrap()),
            x if IDENTIFIER.is_match(x) => Identifier(x.to_string()),
            x => panic!("{} is not a valid identifier", x)
        }
    }).collect()
}

#[test]
fn test_split_blocks() {
    assert_eq!(split_blocks("asdlkjfn\n{{askdljfbalkjsdbf}} asdjlfb"),
                vec!["asdlkjfn\n", "{{askdljfbalkjsdbf}}", " asdjlfb"]);
    assert_eq!(split_blocks("asdlkjfn\n{%askdljfbalkjsdbf%} asdjlfb"),
                vec!["asdlkjfn\n", "{%askdljfbalkjsdbf%}", " asdjlfb"]);
}

#[test]
fn test_tokenize() {
    assert_eq!(tokenize("wat\n{{hello 'world'}} test"), vec![
               Raw("wat\n".to_string()), Output(vec![Identifier("hello".to_string()), StringLiteral("'world'".to_string())], "{{hello 'world'}}".to_string()), Raw(" test".to_string())
               ]);
}

#[test]
fn test_granularize() {
}

<commit_msg>Improve string literal handling<commit_after>use self::Token::*;
use self::Element::*;
use self::ComparisonOperator::*;
use regex::Regex;

static MARKUP     : Regex = regex!("\\{%.*?%\\}|\\{\\{.*?\\}\\}");
static TAG        : Regex = regex!("\\{%(.*?)%\\}");
static OUTPUT     : Regex = regex!("\\{\\{(.*?)\\}\\}");
static WHITESPACE : Regex = regex!(r"\s+");

static IDENTIFIER            : Regex = regex!(r"[a-zA-Z_][\w-]*\??");
static SINGLE_STRING_LITERAL : Regex = regex!(r"'[^']*'");
static DOUBLE_STRING_LITERAL : Regex = regex!("\"[^\"]*\"");
static NUMBER_LITERAL        : Regex = regex!(r"-?\d+(\.\d+)?");
static DOTDOT                : Regex = regex!(r"\.\.");

#[deriving(Clone, Show, PartialEq)]
pub enum ComparisonOperator{
    Equals, NotEquals,
    LessThan, GreaterThan,
    LessThanEquals, GreaterThanEquals,
    Contains
}

#[deriving(Clone, Show, PartialEq)]
pub enum Token {
    Pipe,
    Dot,
    Colon,
    Comma,
    OpenSquare,
    CloseSquare,
    OpenRound,
    CloseRound,
    Question,
    Dash,

    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f32),
    DotDot,
    Comparison(ComparisonOperator)
}

#[deriving(Clone, Show, PartialEq)]
pub enum Element{
    Output(Vec<Token>, String),
    Tag(Vec<Token>, String),
    Raw(String)
}

fn split_blocks(text: &str) -> Vec<&str>{
    let mut tokens = vec![];
    let mut current = 0;
    for (begin, end) in MARKUP.find_iter(text) {
        match text.slice(current, begin){
            "" => {}
            t => tokens.push(t)
        };
        tokens.push(text.slice(begin, end));
        current = end;
    }
    match text.slice(current, text.len()){
        "" => {}
        t => tokens.push(t)
    };
    tokens
}

pub fn tokenize(text: &str) -> Vec<Element> {
    split_blocks(text).iter().map(|block| {
        if TAG.is_match(*block) {
            let caps = TAG.captures(*block).unwrap();
            Tag(granularize(caps.at(1)), block.to_string())
        }else if OUTPUT.is_match(*block) {
            let caps = OUTPUT.captures(*block).unwrap();
            Output(granularize(caps.at(1)), block.to_string())
        }else{
            Raw(block.to_string())
        }
    }).collect()
}

fn granularize(block: &str) -> Vec<Token>{
    WHITESPACE.split(block).map(|el|{
        match el {
            "|" => Pipe,
            "." => Dot,
            ":" => Colon,
            "," => Comma,
            "[" => OpenSquare,
            "]" => CloseSquare,
            "(" => OpenRound,
            ")" => CloseRound,
            "?" => Question,
            "-" => Dash,

            "=="       => Comparison(Equals),
            "!="       => Comparison(NotEquals),
            "<="       => Comparison(LessThanEquals),
            ">="       => Comparison(GreaterThanEquals),
            "<"        => Comparison(LessThan),
            ">"        => Comparison(GreaterThan),
            "contains" => Comparison(Contains),

            x if DOTDOT.is_match(x) => DotDot,
            x if SINGLE_STRING_LITERAL.is_match(x) => StringLiteral(x[1..x.len() -1].to_string()),
            x if DOUBLE_STRING_LITERAL.is_match(x) => StringLiteral(x[1..x.len() -1].to_string()),
            x if NUMBER_LITERAL.is_match(x) => NumberLiteral(from_str::<f32>(x).unwrap()),
            x if IDENTIFIER.is_match(x) => Identifier(x.to_string()),
            x => panic!("{} is not a valid identifier", x)
        }
    }).collect()
}

#[test]
fn test_split_blocks() {
    assert_eq!(split_blocks("asdlkjfn\n{{askdljfbalkjsdbf}} asdjlfb"),
                vec!["asdlkjfn\n", "{{askdljfbalkjsdbf}}", " asdjlfb"]);
    assert_eq!(split_blocks("asdlkjfn\n{%askdljfbalkjsdbf%} asdjlfb"),
                vec!["asdlkjfn\n", "{%askdljfbalkjsdbf%}", " asdjlfb"]);
}

#[test]
fn test_tokenize() {
    assert_eq!(tokenize("wat\n{{hello 'world'}} test"), vec![
               Raw("wat\n".to_string()), Output(vec![Identifier("hello".to_string()), StringLiteral("world".to_string())], "{{hello 'world'}}".to_string()), Raw(" test".to_string())
               ]);
}

#[test]
fn test_granularize() {
    assert_eq!(granularize("test me"), vec![Identifier("test".to_string()), Identifier("me".to_string())]);
    assert_eq!(granularize("test == me"), vec![Identifier("test".to_string()), Comparison(Equals), Identifier("me".to_string())]);
    assert_eq!(granularize("'test' == \"me\""), vec![StringLiteral("test".to_string()), Comparison(Equals), StringLiteral("me".to_string())]);
}

<|endoftext|>


<commit_before>//! ELF Linker/Loader

use crate::architecture::X86;
use crate::loader::*;
use crate::memory::backing::Memory;
use crate::memory::MemoryPermissions;
use std::fs::File;
use std::io::Read;
use std::path::Path;

/// Loader for a single ELf file.
#[derive(Debug)]
pub struct Pe {
    bytes: Vec<u8>,
    architecture: Box<dyn Architecture>,
}

impl Pe {
    /// Create a new Elf from the given bytes. This Elf will be rebased to the given
    /// base address.
    pub fn new(bytes: Vec<u8>) -> Result<Pe> {
        let architecture = {
            let pe = goblin::pe::PE::parse(&bytes).map_err(|_| "Not a valid PE")?;

            if pe.header.coff_header.machine == goblin::pe::header::COFF_MACHINE_X86 {
                Box::new(X86::new())
            } else {
                bail!("Unsupported Architecture");
            }
        };

        Ok(Pe {
            bytes,
            architecture,
        })
    }

    /// Load an elf from a file and use the base address of 0.
    pub fn from_file(filename: &Path) -> Result<Pe> {
        let mut file = match File::open(filename) {
            Ok(file) => file,
            Err(e) => {
                return Err(format!("Error opening {}: {}", filename.to_str().unwrap(), e).into())
            }
        };
        let mut buf = Vec::new();
        file.read_to_end(&mut buf)?;
        Pe::new(buf)
    }

    /// Return the goblin::elf::Elf for this elf.
    fn pe(&self) -> goblin::pe::PE {
        goblin::pe::PE::parse(&self.bytes).unwrap()
    }
}

impl Loader for Pe {
    fn memory(&self) -> Result<Memory> {
        let mut memory = Memory::new(self.architecture().endian());

        let pe = self.pe();
        for section in pe.sections {
            let file_offset = section.pointer_to_raw_data as usize;
            let file_size = section.size_of_raw_data as usize;
            let file_bytes = self
                .bytes
                .get(file_offset..(file_offset + file_size))
                .expect("Malformed PE")
                .to_vec();

            let address = section.virtual_address as u64 + pe.image_base as u64;

            let mut permissions = memory::MemoryPermissions::NONE;
            if section.characteristics & goblin::pe::section_table::IMAGE_SCN_MEM_READ != 0 {
                permissions |= MemoryPermissions::READ;
            }
            if section.characteristics & goblin::pe::section_table::IMAGE_SCN_MEM_WRITE != 0 {
                permissions |= MemoryPermissions::WRITE;
            }
            if section.characteristics & goblin::pe::section_table::IMAGE_SCN_MEM_EXECUTE != 0 {
                permissions |= MemoryPermissions::EXECUTE;
            }

            memory.set_memory(address, file_bytes, permissions);
        }

        Ok(memory)
    }

    fn function_entries(&self) -> Result<Vec<FunctionEntry>> {
        let pe = self.pe();

        let mut function_entries = Vec::new();

        for symbol in pe.exports {
            let function_entry = FunctionEntry::new(
                (symbol.rva + pe.image_base) as u64,
                symbol.name.map(|s| s.to_string()),
            );
            function_entries.push(function_entry);
        }

        let entry = pe.entry as u64;

        if !function_entries.iter().any(|fe| fe.address() == entry) {
            function_entries.push(FunctionEntry::new((pe.entry + pe.image_base) as u64, None));
        }

        Ok(function_entries)
    }

    fn program_entry(&self) -> u64 {
        (self.pe().entry + self.pe().image_base) as u64
    }

    fn architecture(&self) -> &dyn Architecture {
        self.architecture.as_ref()
    }

    fn as_any(&self) -> &dyn Any {
        self
    }

    fn symbols(&self) -> Vec<Symbol> {
        let pe = self.pe();
        let mut symbols = Vec::new();
        for export in pe.exports {
            if let Some(name) = export.name {
                symbols.push(Symbol::new(name.to_string(), export.offset as u64));
            }
        }
        symbols
    }
}
<commit_msg>Add AMD64 and MIPS architectures for PE loader (#110)<commit_after>//! PE Linker/Loader

use crate::architecture::{Amd64, Mips, X86};
use crate::loader::*;
use crate::memory::backing::Memory;
use crate::memory::MemoryPermissions;
use std::fs::File;
use std::io::Read;
use std::path::Path;

/// Loader for a single PE file.
#[derive(Debug)]
pub struct Pe {
    bytes: Vec<u8>,
    architecture: Box<dyn Architecture>,
}

impl Pe {
    /// Create a new PE from the given bytes. This PE will be rebased to the given
    /// base address.
    pub fn new(bytes: Vec<u8>) -> Result<Pe> {
        let architecture: Box<dyn Architecture> = {
            let pe = goblin::pe::PE::parse(&bytes).map_err(|_| "Not a valid PE")?;

            if pe.header.coff_header.machine == goblin::pe::header::COFF_MACHINE_X86 {
                Box::new(X86::new())
            } else if pe.header.coff_header.machine == goblin::pe::header::COFF_MACHINE_X86_64 {
                Box::new(Amd64::new())
            } else if pe.header.coff_header.machine == goblin::pe::header::COFF_MACHINE_R4000 {
                Box::new(Mips::new())
            } else {
                bail!("Unsupported Architecture");
            }
        };

        Ok(Pe {
            bytes,
            architecture,
        })
    }

    /// Load an PE from a file and use the base address of 0.
    pub fn from_file(filename: &Path) -> Result<Pe> {
        let mut file = match File::open(filename) {
            Ok(file) => file,
            Err(e) => {
                return Err(format!("Error opening {}: {}", filename.to_str().unwrap(), e).into())
            }
        };
        let mut buf = Vec::new();
        file.read_to_end(&mut buf)?;
        Pe::new(buf)
    }

    /// Return the goblin::pe::PE for this PE.
    fn pe(&self) -> goblin::pe::PE {
        goblin::pe::PE::parse(&self.bytes).unwrap()
    }
}

impl Loader for Pe {
    fn memory(&self) -> Result<Memory> {
        let mut memory = Memory::new(self.architecture().endian());

        let pe = self.pe();
        for section in pe.sections {
            let file_offset = section.pointer_to_raw_data as usize;
            let file_size = section.size_of_raw_data as usize;
            let file_bytes = self
                .bytes
                .get(file_offset..(file_offset + file_size))
                .expect("Malformed PE")
                .to_vec();

            let address = section.virtual_address as u64 + pe.image_base as u64;

            let mut permissions = memory::MemoryPermissions::NONE;
            if section.characteristics & goblin::pe::section_table::IMAGE_SCN_MEM_READ != 0 {
                permissions |= MemoryPermissions::READ;
            }
            if section.characteristics & goblin::pe::section_table::IMAGE_SCN_MEM_WRITE != 0 {
                permissions |= MemoryPermissions::WRITE;
            }
            if section.characteristics & goblin::pe::section_table::IMAGE_SCN_MEM_EXECUTE != 0 {
                permissions |= MemoryPermissions::EXECUTE;
            }

            memory.set_memory(address, file_bytes, permissions);
        }

        Ok(memory)
    }

    fn function_entries(&self) -> Result<Vec<FunctionEntry>> {
        let pe = self.pe();

        let mut function_entries = Vec::new();

        for symbol in pe.exports {
            let function_entry = FunctionEntry::new(
                (symbol.rva + pe.image_base) as u64,
                symbol.name.map(|s| s.to_string()),
            );
            function_entries.push(function_entry);
        }

        let entry = pe.entry as u64;

        if !function_entries.iter().any(|fe| fe.address() == entry) {
            function_entries.push(FunctionEntry::new((pe.entry + pe.image_base) as u64, None));
        }

        Ok(function_entries)
    }

    fn program_entry(&self) -> u64 {
        (self.pe().entry + self.pe().image_base) as u64
    }

    fn architecture(&self) -> &dyn Architecture {
        self.architecture.as_ref()
    }

    fn as_any(&self) -> &dyn Any {
        self
    }

    fn symbols(&self) -> Vec<Symbol> {
        let pe = self.pe();
        let mut symbols = Vec::new();
        for export in pe.exports {
            if let Some(name) = export.name {
                symbols.push(Symbol::new(name.to_string(), export.offset as u64));
            }
        }
        symbols
    }
}
<|endoftext|>


<commit_before>pub mod search;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::TranspositionTable;

// use rand;
// use rand::distributions::{Sample, Range};
// let mut rng = rand::thread_rng();
// let mut between = Range::new(0, 10);
// let x = between.sample(&mut rng);

const VERSION: &'static str = "0.1";

/// Implements `UciEngine` trait.
pub struct Engine {
    position: Position,
    pondering_is_allowed: bool,
    multi_pv: usize,
    is_thinking: bool,
    is_pondering: bool,
    replies: Vec<EngineReply>,
    infinite: bool,
    tt: Arc<TranspositionTable>,
    commands: Sender<search::Command>,
    reports: Receiver<search::Report>,
    started_thinking_at: SystemTime,
    curr_depth: u8,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            pondering_is_allowed: false,
            multi_pv: 1,
            is_thinking: false,
            is_pondering: false,
            replies: vec![],
            infinite: false,
            tt: tt,
            commands: commands_tx,
            reports: reports_rx,
            started_thinking_at: SystemTime::now(),
            curr_depth: 0,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            // We do not support re-sizing of the transposition table
            // once the engine had started, so we do nothing.
            "Hash" => (),

            // Tells the engine that it will be allowed to ponder.
            // This option is needed because the engine might change
            // its time management algorithm when pondering is
            // allowed.
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // Tells the engine to output multiple best lines.
            // the default value is `1`.)
            "MultiPV" => {
                self.multi_pv = value.parse::<usize>().ok().unwrap_or(1);
            }

            // An invalid option.
            _ => {
                self.replies.push(EngineReply::Info(vec![("string".to_string(),
                                                          format!("Invalid option \"{}\"", name))]));
            }
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            self.commands
                .send(search::Command::Search {
                    search_id: 0,
                    position: self.position.clone(),
                    depth: 127,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
            self.is_thinking = true;
            self.is_pondering = ponder;
            self.infinite = infinite;
            self.started_thinking_at = SystemTime::now();
            self.curr_depth = 0;
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();
            let best_move = self.get_best_move();
            self.replies.push(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // TODO: implement real time management here.
        if self.is_thinking && !self.is_pondering && !self.infinite &&
           self.started_thinking_at.elapsed().unwrap().as_secs() > 3 {
            self.stop();
        }

        // Empty the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            // let rep_type = match report {
            //     search::Report::Progress { searched_nodes, .. } => format!("progress {}", searched_nodes),
            //     search::Report::Done { .. } => "done".to_string(),
            // };
            // self.replies.push(EngineReply::Info(vec![
            //     ("string".to_string(), rep_type),
            // ]));
            if self.is_thinking {
                match report {
                    search::Report::Progress { searched_nodes, depth, .. } => {
                        if self.curr_depth < depth {
                            self.curr_depth = depth;
                            let mut p = self.position.clone();
                            let mut v = Vec::with_capacity(128);
                            let mut pv = String::from("");
                            let mut value = None;
                            for _ in 0..depth {
                                let m = match self.tt.probe(p.hash()) {
                                    Some(entry) => {
                                        if value.is_none() {
                                            value = Some(entry.value());
                                        }
                                        entry.move16()
                                    }
                                    None => 0,
                                };
                                if m != 0 {
                                    self.position.generate_moves(&mut v);
                                    while let Some(x) = v.pop() {
                                        if x.move16() == m && p.do_move(x) {
                                            pv.push_str(&x.notation());
                                            pv.push(' ');
                                            v.clear();
                                            break;
                                        }
                                    }
                                }
                            }
                            let duration = self.started_thinking_at.elapsed().unwrap();
                            let elapsed_time_milis = 1000 * duration.as_secs() +
                                                     (duration.subsec_nanos() / 1000000) as u64;
                            self.replies.push(EngineReply::Info(vec![
                            ("multipv".to_string(), "1".to_string()),
                            ("depth".to_string(), format!("{}", depth)),
                            ("score".to_string(), format!("cp {}", value.unwrap_or(666))),
                            ("nodes".to_string(), format!("{}", searched_nodes)),
                            ("time".to_string(), format!("{}", elapsed_time_milis)),
                            ("pv".to_string(), format!("{}", pv)),
                        ]));
                        }
                    }
                    _ => (),
                }
            }
        }

        if self.replies.len() > 0 {
            Some(self.replies.remove(0))
        } else {
            None
        }
    }
}

impl Engine {
    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::from_u32(0);
            let mut v = Vec::with_capacity(128);
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.move16();
        }
        if m != 0 {
            let move_type = ((m & 0b1100000000000000) >> 14) as MoveType;
            let orig_square = ((m & 0b0011111100000000) >> 8) as Square;
            let dest_square = ((m & 0b0000000011111100) >> 2) as Square;
            let promoted_piece = match m & 0b11 {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 32, default: 1 }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}
<commit_msg>fixed stupid bug<commit_after>pub mod search;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::TranspositionTable;

// use rand;
// use rand::distributions::{Sample, Range};
// let mut rng = rand::thread_rng();
// let mut between = Range::new(0, 10);
// let x = between.sample(&mut rng);

const VERSION: &'static str = "0.1";

/// Implements `UciEngine` trait.
pub struct Engine {
    position: Position,
    pondering_is_allowed: bool,
    multi_pv: usize,
    is_thinking: bool,
    is_pondering: bool,
    replies: Vec<EngineReply>,
    infinite: bool,
    tt: Arc<TranspositionTable>,
    commands: Sender<search::Command>,
    reports: Receiver<search::Report>,
    started_thinking_at: SystemTime,
    curr_depth: u8,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            pondering_is_allowed: false,
            multi_pv: 1,
            is_thinking: false,
            is_pondering: false,
            replies: vec![],
            infinite: false,
            tt: tt,
            commands: commands_tx,
            reports: reports_rx,
            started_thinking_at: SystemTime::now(),
            curr_depth: 0,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            // We do not support re-sizing of the transposition table
            // once the engine had started, so we do nothing.
            "Hash" => (),

            // Tells the engine that it will be allowed to ponder.
            // This option is needed because the engine might change
            // its time management algorithm when pondering is
            // allowed.
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // Tells the engine to output multiple best lines.
            // the default value is `1`.)
            "MultiPV" => {
                self.multi_pv = value.parse::<usize>().ok().unwrap_or(1);
            }

            // An invalid option.
            _ => {
                self.replies.push(EngineReply::Info(vec![("string".to_string(),
                                                          format!("Invalid option \"{}\"", name))]));
            }
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            self.commands
                .send(search::Command::Search {
                    search_id: 0,
                    position: self.position.clone(),
                    depth: 127,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
            self.is_thinking = true;
            self.is_pondering = ponder;
            self.infinite = infinite;
            self.started_thinking_at = SystemTime::now();
            self.curr_depth = 0;
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();
            let best_move = self.get_best_move();
            self.replies.push(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // TODO: implement real time management here.
        if self.is_thinking && !self.is_pondering && !self.infinite &&
           self.started_thinking_at.elapsed().unwrap().as_secs() > 3 {
            self.stop();
        }

        // Empty the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            // let rep_type = match report {
            //     search::Report::Progress { searched_nodes, .. } => format!("progress {}", searched_nodes),
            //     search::Report::Done { .. } => "done".to_string(),
            // };
            // self.replies.push(EngineReply::Info(vec![
            //     ("string".to_string(), rep_type),
            // ]));
            if self.is_thinking {
                match report {
                    search::Report::Progress { searched_nodes, depth, .. } => {
                        if self.curr_depth < depth {
                            self.curr_depth = depth;
                            let mut p = self.position.clone();
                            let mut v = Vec::with_capacity(128);
                            let mut pv = String::from("");
                            let mut value = None;
                            'depthloop: for _ in 0..depth {
                                let m = match self.tt.probe(p.hash()) {
                                    Some(entry) => {
                                        if value.is_none() {
                                            value = Some(entry.value());
                                        }
                                        entry.move16()
                                    }
                                    None => 0,
                                };
                                if m != 0 {
                                    p.generate_moves(&mut v);
                                    while let Some(x) = v.pop() {
                                        if x.move16() == m && p.do_move(x) {
                                            pv.push_str(&x.notation());
                                            pv.push(' ');
                                            v.clear();
                                            continue 'depthloop;
                                        }
                                    }
                                }
                                break;
                            }
                            let duration = self.started_thinking_at.elapsed().unwrap();
                            let elapsed_time_milis = 1000 * duration.as_secs() +
                                                     (duration.subsec_nanos() / 1000000) as u64;
                            self.replies.push(EngineReply::Info(vec![
                            ("multipv".to_string(), "1".to_string()),
                            ("depth".to_string(), format!("{}", depth)),
                            ("score".to_string(), format!("cp {}", value.unwrap_or(666))),
                            ("nodes".to_string(), format!("{}", searched_nodes)),
                            ("time".to_string(), format!("{}", elapsed_time_milis)),
                            ("pv".to_string(), format!("{}", pv)),
                        ]));
                        }
                    }
                    _ => (),
                }
            }
        }

        if self.replies.len() > 0 {
            Some(self.replies.remove(0))
        } else {
            None
        }
    }
}

impl Engine {
    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::from_u32(0);
            let mut v = Vec::with_capacity(128);
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.move16();
        }
        if m != 0 {
            let move_type = ((m & 0b1100000000000000) >> 14) as MoveType;
            let orig_square = ((m & 0b0011111100000000) >> 8) as Square;
            let dest_square = ((m & 0b0000000011111100) >> 2) as Square;
            let promoted_piece = match m & 0b11 {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 32, default: 1 }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}
<|endoftext|>


<commit_before>use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use stack::Stack;
use operate::Operate;

#[derive(Debug, Copy, Clone)]
pub enum Arithm<T, O: Operate<T>> {
    Operand(T),
    Operator(O),
}

#[derive(Debug)]
pub struct Expression<T, O: Operate<T>>(Vec<Arithm<T, O>>);

impl<T: Copy, O: Operate<T> + Copy> Expression<T, O> {
    pub fn operate(&self) -> Result<T, O::Err> {
        let mut stack = Stack::new();
        for arithm in &self.0 {
            match *arithm {
                Arithm::Operand(operand) => stack.push(operand),
                Arithm::Operator(operator) => operator.operate(&mut stack)?,
            }
        }
        Ok(stack.pop().unwrap())
    }
}

#[derive(Debug, PartialEq)]
pub enum ExprResult<A, B> {
    TooManyOperands,
    NotEnoughOperand,
    InvalidToken(A, B),
}

use self::ExprResult::*;

impl<'a, T, O> TryFrom<&'a str> for Expression<T, O>
    where T: FromStr,
          O: Operate<T> + TryFrom<&'a str>
{
    type Err = ExprResult<<T as FromStr>::Err, <O as TryFrom<&'a str>>::Err>;
    fn try_from(expr: &'a str) -> Result<Self, Self::Err> {
        let mut expression = Vec::new();
        let mut num_operands: usize = 0;
        for token in expr.split_whitespace() {
            let arithm = match token.parse() {
                Ok(operand) => {
                    num_operands += 1;
                    Arithm::Operand(operand)
                }
                Err(operand_err) => {
                    match TryInto::<O>::try_into(token) {
                        Ok(operator) => {
                            let needed = operator.operands_needed();
                            num_operands = num_operands.checked_sub(needed)
                                .ok_or(NotEnoughOperand)?;
                            num_operands += operator.operands_generated();
                            Arithm::Operator(operator)
                        }
                        Err(operator_err) => return Err(InvalidToken(operand_err, operator_err)),
                    }
                }
            };
            expression.push(arithm);
        }
        match num_operands {
            0 => Err(NotEnoughOperand),
            1 => Ok(Expression(expression)),
            _ => Err(TooManyOperands),
        }
    }
}
<commit_msg>expression: Add conversion form Vec<T, O: Operate><commit_after>use std::convert::{From, TryFrom, TryInto};
use std::str::FromStr;
use stack::Stack;
use operate::Operate;

#[derive(Debug, Copy, Clone)]
pub enum Arithm<T, O: Operate<T>> {
    Operand(T),
    Operator(O),
}

#[derive(Debug)]
pub struct Expression<T, O: Operate<T>>(Vec<Arithm<T, O>>);

impl<T: Copy, O: Operate<T> + Copy> Expression<T, O> {
    pub fn operate(&self) -> Result<T, O::Err> {
        let mut stack = Stack::new();
        for arithm in &self.0 {
            match *arithm {
                Arithm::Operand(operand) => stack.push(operand),
                Arithm::Operator(operator) => operator.operate(&mut stack)?,
            }
        }
        Ok(stack.pop().unwrap())
    }
}

#[derive(Debug, PartialEq)]
pub enum ExprResult<A, B> {
    TooManyOperands,
    NotEnoughOperand,
    InvalidToken(A, B),
}

use self::ExprResult::*;

impl<'a, T, O> TryFrom<&'a str> for Expression<T, O>
    where T: FromStr,
          O: Operate<T> + TryFrom<&'a str>
{
    type Err = ExprResult<<T as FromStr>::Err, <O as TryFrom<&'a str>>::Err>;
    fn try_from(expr: &'a str) -> Result<Self, Self::Err> {
        let mut expression = Vec::new();
        let mut num_operands: usize = 0;
        for token in expr.split_whitespace() {
            let arithm = match token.parse() {
                Ok(operand) => {
                    num_operands += 1;
                    Arithm::Operand(operand)
                }
                Err(operand_err) => {
                    match TryInto::<O>::try_into(token) {
                        Ok(operator) => {
                            let needed = operator.operands_needed();
                            num_operands = num_operands.checked_sub(needed)
                                .ok_or(NotEnoughOperand)?;
                            num_operands += operator.operands_generated();
                            Arithm::Operator(operator)
                        }
                        Err(operator_err) => return Err(InvalidToken(operand_err, operator_err)),
                    }
                }
            };
            expression.push(arithm);
        }
        match num_operands {
            0 => Err(NotEnoughOperand),
            1 => Ok(Expression(expression)),
            _ => Err(TooManyOperands),
        }
    }
}

impl<T, O: Operate<T>> From<Vec<Arithm<T, O>>> for Expression<T, O> {
    fn from(expr: Vec<Arithm<T, O>>) -> Self {
        Expression(expr)
    }
}
<|endoftext|>


<commit_before>//! Defines types for operating with floating point and 8 bit RGB colors

use std::num::Float;
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};

use linalg;

/// Colorf is a floating point RGBA color type
/// `a` is typically used to store the weight of a color eg. in the
/// render target for multisampling we need to track the weight to
/// normalize in the end and is always initialized to 0
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Colorf {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

impl Colorf {
    /// Create an RGB color
    pub fn new(r: f32, g: f32, b: f32) -> Colorf {
        Colorf { r: r, g: g, b: b, a: 1.0 }
    }
    /// Create an RGB color using the same value for all channels
    pub fn broadcast(r: f32) -> Colorf {
        Colorf { r: r, g: r, b: r, a: r }
    }
    /// Clamp the color values between [0, 1]
    pub fn clamp(&self) -> Colorf {
        Colorf { r: linalg::clamp(self.r, 0.0, 1.0),
                 g: linalg::clamp(self.g, 0.0, 1.0),
                 b: linalg::clamp(self.b, 0.0, 1.0),
                 a: linalg::clamp(self.a, 0.0, 1.0) }
    }
    /// Compute the luminance of the color
    pub fn luminance(&self) -> f32 {
        0.2126 * self.r + 0.7152 * self.g + 0.0722 * self.b
    }
    /// Check if the color is black
    pub fn is_black(&self) -> bool {
        self.r == 0f32 && self.g == 0f32 && self.b == 0f32
    }
    /// Check if any of the color channels are NaN
    pub fn has_nans(&self) -> bool {
        Float::is_nan(self.r) || Float::is_nan(self.g) || Float::is_nan(self.b) || Float::is_nan(self.a)
    }
    /// Convert the linear RGB color to sRGB
    pub fn to_srgb(&self) -> Colorf {
        let a = 0.055f32;
        let b = 1f32 / 2.4;
        let mut srgb = Colorf::broadcast(0.0);
        for i in 0..3us {
            if self[i] <= 0.0031308 {
                srgb[i] = 12.92 * self[i];
            } else {
                srgb[i] = (1.0 + a) * Float::powf(self[i], b) - a;
            }
        }
        srgb
    }
    /// Return the color with values { e^r, e^g, e^b }
    pub fn exp(&self) -> Colorf {
        Colorf { r: Float::exp(self.r), g: Float::exp(self.g),
                 b: Float::exp(self.b), a: Float::exp(self.a) }
    }
}

impl Add for Colorf {
    type Output = Colorf;
    /// Add two colors together
    fn add(self, rhs: Colorf) -> Colorf {
        Colorf { r: self.r + rhs.r, g: self.g + rhs.g, b: self.b + rhs.b, a: self.a + rhs.a }
    }
}

impl Sub for Colorf {
    type Output = Colorf;
    /// Subtract the two colors
    fn sub(self, rhs: Colorf) -> Colorf {
        Colorf { r: self.r - rhs.r, g: self.g - rhs.g, b: self.b - rhs.b, a: self.a - rhs.a }
    }
}

impl Mul for Colorf {
    type Output = Colorf;
    /// Multiply the two colors
    fn mul(self, rhs: Colorf) -> Colorf {
        Colorf { r: self.r * rhs.r, g: self.g * rhs.g, b: self.b * rhs.b, a: self.a * rhs.a }
    }
}

impl Mul<f32> for Colorf {
    type Output = Colorf;
    /// Scale the color by the float
    fn mul(self, rhs: f32) -> Colorf {
        Colorf { r: self.r * rhs, g: self.g * rhs, b: self.b * rhs, a: self.a * rhs }
    }
}

impl Div for Colorf {
    type Output = Colorf;
    /// Divide the channels of one color by another
    fn div(self, rhs: Colorf) -> Colorf {
        Colorf { r: self.r / rhs.r, g: self.g / rhs.g, b: self.b / rhs.b, a: self.a / rhs.a }
    }
}

impl Div<f32> for Colorf {
    type Output = Colorf;
    /// Divide the channels of the color by the float
    fn div(self, rhs: f32) -> Colorf {
        Colorf { r: self.r / rhs, g: self.g / rhs, b: self.b / rhs, a: self.a / rhs }
    }
}

impl Neg for Colorf {
    type Output = Colorf;
    /// Negate the color channels
    fn neg(self) -> Colorf {
        Colorf { r: -self.r, g: -self.g, b: -self.b, a: -self.a }
    }
}

impl Index<usize> for Colorf {
    type Output = f32;
    /// Access the channels by index
    ///
    /// - 0 = r
    /// - 1 = g
    /// - 2 = b
    /// - 3 = a
    fn index(&self, i: &usize) -> &f32 {
        match *i {
            0 => &self.r,
            1 => &self.g,
            2 => &self.b,
            3 => &self.a,
            _ => panic!("Invalid index into color"),
        }
    }
}

impl IndexMut<usize> for Colorf {
    type Output = f32;
    /// Access the channels by index
    ///
    /// - 0 = r
    /// - 1 = g
    /// - 2 = b
    /// - 3 = a
    fn index_mut(&mut self, i: &usize) -> &mut f32 {
        match *i {
            0 => &mut self.r,
            1 => &mut self.g,
            2 => &mut self.b,
            3 => &mut self.a,
            _ => panic!("Invalid index into color"),
        }
    }
}

<commit_msg>Add black color function<commit_after>//! Defines types for operating with floating point and 8 bit RGB colors

use std::num::Float;
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};

use linalg;

/// Colorf is a floating point RGBA color type
/// `a` is typically used to store the weight of a color eg. in the
/// render target for multisampling we need to track the weight to
/// normalize in the end and is always initialized to 0
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Colorf {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

impl Colorf {
    /// Create an RGB color
    pub fn new(r: f32, g: f32, b: f32) -> Colorf {
        Colorf { r: r, g: g, b: b, a: 1.0 }
    }
    /// Create an RGB color using the same value for all channels
    pub fn broadcast(r: f32) -> Colorf {
        Colorf { r: r, g: r, b: r, a: r }
    }
    /// Create a black color
    pub fn black() -> Colorf { Colorf::broadcast(0.0) }
    /// Clamp the color values between [0, 1]
    pub fn clamp(&self) -> Colorf {
        Colorf { r: linalg::clamp(self.r, 0.0, 1.0),
                 g: linalg::clamp(self.g, 0.0, 1.0),
                 b: linalg::clamp(self.b, 0.0, 1.0),
                 a: linalg::clamp(self.a, 0.0, 1.0) }
    }
    /// Compute the luminance of the color
    pub fn luminance(&self) -> f32 {
        0.2126 * self.r + 0.7152 * self.g + 0.0722 * self.b
    }
    /// Check if the color is black
    pub fn is_black(&self) -> bool {
        self.r == 0f32 && self.g == 0f32 && self.b == 0f32
    }
    /// Check if any of the color channels are NaN
    pub fn has_nans(&self) -> bool {
        Float::is_nan(self.r) || Float::is_nan(self.g) || Float::is_nan(self.b) || Float::is_nan(self.a)
    }
    /// Convert the linear RGB color to sRGB
    pub fn to_srgb(&self) -> Colorf {
        let a = 0.055f32;
        let b = 1f32 / 2.4;
        let mut srgb = Colorf::broadcast(0.0);
        for i in 0..3us {
            if self[i] <= 0.0031308 {
                srgb[i] = 12.92 * self[i];
            } else {
                srgb[i] = (1.0 + a) * Float::powf(self[i], b) - a;
            }
        }
        srgb
    }
    /// Return the color with values { e^r, e^g, e^b }
    pub fn exp(&self) -> Colorf {
        Colorf { r: Float::exp(self.r), g: Float::exp(self.g),
                 b: Float::exp(self.b), a: Float::exp(self.a) }
    }
}

impl Add for Colorf {
    type Output = Colorf;
    /// Add two colors together
    fn add(self, rhs: Colorf) -> Colorf {
        Colorf { r: self.r + rhs.r, g: self.g + rhs.g, b: self.b + rhs.b, a: self.a + rhs.a }
    }
}

impl Sub for Colorf {
    type Output = Colorf;
    /// Subtract the two colors
    fn sub(self, rhs: Colorf) -> Colorf {
        Colorf { r: self.r - rhs.r, g: self.g - rhs.g, b: self.b - rhs.b, a: self.a - rhs.a }
    }
}

impl Mul for Colorf {
    type Output = Colorf;
    /// Multiply the two colors
    fn mul(self, rhs: Colorf) -> Colorf {
        Colorf { r: self.r * rhs.r, g: self.g * rhs.g, b: self.b * rhs.b, a: self.a * rhs.a }
    }
}

impl Mul<f32> for Colorf {
    type Output = Colorf;
    /// Scale the color by the float
    fn mul(self, rhs: f32) -> Colorf {
        Colorf { r: self.r * rhs, g: self.g * rhs, b: self.b * rhs, a: self.a * rhs }
    }
}

impl Div for Colorf {
    type Output = Colorf;
    /// Divide the channels of one color by another
    fn div(self, rhs: Colorf) -> Colorf {
        Colorf { r: self.r / rhs.r, g: self.g / rhs.g, b: self.b / rhs.b, a: self.a / rhs.a }
    }
}

impl Div<f32> for Colorf {
    type Output = Colorf;
    /// Divide the channels of the color by the float
    fn div(self, rhs: f32) -> Colorf {
        Colorf { r: self.r / rhs, g: self.g / rhs, b: self.b / rhs, a: self.a / rhs }
    }
}

impl Neg for Colorf {
    type Output = Colorf;
    /// Negate the color channels
    fn neg(self) -> Colorf {
        Colorf { r: -self.r, g: -self.g, b: -self.b, a: -self.a }
    }
}

impl Index<usize> for Colorf {
    type Output = f32;
    /// Access the channels by index
    ///
    /// - 0 = r
    /// - 1 = g
    /// - 2 = b
    /// - 3 = a
    fn index(&self, i: &usize) -> &f32 {
        match *i {
            0 => &self.r,
            1 => &self.g,
            2 => &self.b,
            3 => &self.a,
            _ => panic!("Invalid index into color"),
        }
    }
}

impl IndexMut<usize> for Colorf {
    type Output = f32;
    /// Access the channels by index
    ///
    /// - 0 = r
    /// - 1 = g
    /// - 2 = b
    /// - 3 = a
    fn index_mut(&mut self, i: &usize) -> &mut f32 {
        match *i {
            0 => &mut self.r,
            1 => &mut self.g,
            2 => &mut self.b,
            3 => &mut self.a,
            _ => panic!("Invalid index into color"),
        }
    }
}

<|endoftext|>


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

#![allow(dead_code)]

use libc::{c_int, c_ulong, c_void, ioctl, lseek, read, SEEK_END};
use std::fs::{File, OpenOptions};
use std::io;
use std::mem::size_of;
use std::os::unix::io::AsRawFd;
use std::time::Duration;

use gpio::epoll::{epoll_event, Epoll, EPOLLIN, EPOLLPRI};
use gpio::{Error, Level, Result, Trigger};

fn parse_retval(retval: c_int) -> Result<i32> {
    if retval == -1 {
        Err(Error::Io(io::Error::last_os_error()))
    } else {
        Ok(retval)
    }
}

const NRBITS: u8 = 8;
const TYPEBITS: u8 = 8;
const SIZEBITS: u8 = 14;
const DIRBITS: u8 = 2;

const NRSHIFT: u8 = 0;
const TYPESHIFT: u8 = (NRSHIFT + NRBITS);
const SIZESHIFT: u8 = (TYPESHIFT + TYPEBITS);
const DIRSHIFT: u8 = (SIZESHIFT + SIZEBITS);

const NR_GET_CHIP_INFO: c_ulong = 0x01 << NRSHIFT;
const NR_GET_LINE_INFO: c_ulong = 0x02 << NRSHIFT;
const NR_GET_LINE_HANDLE: c_ulong = 0x03 << NRSHIFT;
const NR_GET_LINE_EVENT: c_ulong = 0x04 << NRSHIFT;
const NR_GET_LINE_VALUES: c_ulong = 0x08 << NRSHIFT;
const NR_SET_LINE_VALUES: c_ulong = 0x09 << NRSHIFT;

const TYPE_GPIO: c_ulong = (0xB4 as c_ulong) << TYPESHIFT;

const SIZE_CHIP_INFO: c_ulong = (size_of::<ChipInfo>() as c_ulong) << SIZESHIFT;
const SIZE_LINE_INFO: c_ulong = (size_of::<LineInfo>() as c_ulong) << SIZESHIFT;
const SIZE_HANDLE_REQUEST: c_ulong = (size_of::<HandleRequest>() as c_ulong) << SIZESHIFT;
const SIZE_EVENT_REQUEST: c_ulong = (size_of::<EventRequest>() as c_ulong) << SIZESHIFT;
const SIZE_HANDLE_DATA: c_ulong = (size_of::<HandleData>() as c_ulong) << SIZESHIFT;

const DIR_NONE: c_ulong = 0;
const DIR_WRITE: c_ulong = 1 << DIRSHIFT;
const DIR_READ: c_ulong = 2 << DIRSHIFT;
const DIR_READ_WRITE: c_ulong = DIR_READ | DIR_WRITE;

const REQ_GET_CHIP_INFO: c_ulong = DIR_READ | TYPE_GPIO | NR_GET_CHIP_INFO | SIZE_CHIP_INFO;
const REQ_GET_LINE_INFO: c_ulong = DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_INFO | SIZE_LINE_INFO;
const REQ_GET_LINE_HANDLE: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_HANDLE | SIZE_HANDLE_REQUEST;
const REQ_GET_LINE_EVENT: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_EVENT | SIZE_EVENT_REQUEST;
const REQ_GET_LINE_VALUES: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_VALUES | SIZE_HANDLE_DATA;
const REQ_SET_LINE_VALUES: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_SET_LINE_VALUES | SIZE_HANDLE_DATA;

const NAME_BUFSIZE: usize = 32;
const LABEL_BUFSIZE: usize = 32;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct ChipInfo {
    pub name: [u8; NAME_BUFSIZE],
    pub label: [u8; LABEL_BUFSIZE],
    pub lines: u32,
}

impl ChipInfo {
    pub fn new(cdev_fd: c_int) -> Result<ChipInfo> {
        let mut chip_info = ChipInfo {
            name: [0u8; NAME_BUFSIZE],
            label: [0u8; LABEL_BUFSIZE],
            lines: 0,
        };

        parse_retval(unsafe { ioctl(cdev_fd, REQ_GET_CHIP_INFO, &mut chip_info) })?;

        Ok(chip_info)
    }
}

const LINE_FLAG_KERNEL: u32 = 0x01;
const LINE_FLAG_IS_OUT: u32 = 0x02;
const LINE_FLAG_ACTIVE_LOW: u32 = 0x04;
const LINE_FLAG_OPEN_DRAIN: u32 = 0x08;
const LINE_FLAG_OPEN_SOURCE: u32 = 0x10;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct LineInfo {
    pub line_offset: u32,
    pub flags: u32,
    pub name: [u8; NAME_BUFSIZE],
    pub consumer: [u8; LABEL_BUFSIZE],
}

impl LineInfo {
    pub fn new() -> LineInfo {
        LineInfo {
            line_offset: 0,
            flags: 0,
            name: [0u8; NAME_BUFSIZE],
            consumer: [0u8; LABEL_BUFSIZE],
        }
    }
}

const HANDLES_MAX: usize = 64;
const HANDLE_FLAG_INPUT: u32 = 0x01;
const HANDLE_FLAG_OUTPUT: u32 = 0x02;
const HANDLE_FLAG_ACTIVE_LOW: u32 = 0x04;
const HANDLE_FLAG_OPEN_DRAIN: u32 = 0x08;
const HANDLE_FLAG_OPEN_SOURCE: u32 = 0x10;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct HandleRequest {
    pub line_offsets: [u32; HANDLES_MAX],
    pub flags: u32,
    pub default_values: [u8; HANDLES_MAX],
    pub consumer_label: [u8; LABEL_BUFSIZE],
    pub lines: u32,
    pub fd: c_int,
}

impl HandleRequest {
    pub fn new(cdev_fd: c_int, pins: &[u8]) -> Result<HandleRequest> {
        let mut handle_request = HandleRequest {
            line_offsets: [0u32; HANDLES_MAX],
            flags: 0,
            default_values: [0u8; HANDLES_MAX],
            consumer_label: [0u8; LABEL_BUFSIZE],
            lines: 0,
            fd: 0,
        };

        let pins: &[u8] = if pins.len() > HANDLES_MAX {
            handle_request.lines = HANDLES_MAX as u32;
            &pins[0..HANDLES_MAX]
        } else {
            handle_request.lines = pins.len() as u32;
            pins
        };

        for (idx, pin) in pins.iter().enumerate() {
            handle_request.line_offsets[idx] = u32::from(*pin);
        }

        parse_retval(unsafe { ioctl(cdev_fd, REQ_GET_LINE_HANDLE, &mut handle_request) })?;

        Ok(handle_request)
    }

    pub fn levels(&self) -> Result<HandleData> {
        let mut handle_data = HandleData::new();

        parse_retval(unsafe { ioctl(self.fd, REQ_GET_LINE_VALUES, &mut handle_data) })?;

        Ok(handle_data)
    }

    pub fn set_levels(&mut self, levels: &[Level]) -> Result<()> {
        let mut handle_data = HandleData::new();
        let levels: &[Level] = if levels.len() > HANDLES_MAX {
            &levels[0..HANDLES_MAX]
        } else {
            levels
        };

        for (idx, level) in levels.iter().enumerate() {
            handle_data.values[idx] = *level as u8;
        }

        parse_retval(unsafe { ioctl(self.fd, REQ_SET_LINE_VALUES, &mut handle_data) })?;

        Ok(())
    }
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct HandleData {
    pub values: [u8; HANDLES_MAX],
}

impl HandleData {
    pub fn new() -> HandleData {
        HandleData {
            values: [0u8; HANDLES_MAX],
        }
    }
}

const EVENT_FLAG_RISING_EDGE: u32 = 0x01;
const EVENT_FLAG_FALLING_EDGE: u32 = 0x02;
const EVENT_FLAG_BOTH_EDGES: u32 = EVENT_FLAG_RISING_EDGE | EVENT_FLAG_FALLING_EDGE;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct EventRequest {
    pub line_offset: u32,
    pub handle_flags: u32,
    pub event_flags: u32,
    pub consumer_label: [u8; LABEL_BUFSIZE],
    pub fd: c_int,
}

impl EventRequest {
    pub fn new(cdev_fd: c_int, pin: u8, trigger: Trigger) -> Result<EventRequest> {
        let mut event_request = EventRequest {
            line_offset: u32::from(pin),
            handle_flags: HANDLE_FLAG_INPUT,
            event_flags: trigger as u32,
            consumer_label: [0u8; LABEL_BUFSIZE],
            fd: 0,
        };

        parse_retval(unsafe { ioctl(cdev_fd, REQ_GET_LINE_EVENT, &mut event_request) })?;

        Ok(event_request)
    }
}

const EVENT_TYPE_RISING_EDGE: u32 = 0x01;
const EVENT_TYPE_FALLING_EDGE: u32 = 0x02;

#[derive(Copy, Clone)]
#[repr(C)]
struct EventData {
    timestamp: u64,
    id: u32,
}

impl EventData {
    fn new(event_fd: c_int) -> Result<Option<EventData>> {
        let mut event_data = EventData {
            timestamp: 0,
            id: 0,
        };

        let bytes_read = parse_retval(unsafe {
            read(
                event_fd,
                &mut event_data as *mut EventData as *mut c_void,
                size_of::<EventData>(),
            ) as i32
        })?;

        if bytes_read != size_of::<EventData>() as i32 {
            Ok(None)
        } else {
            Ok(Some(event_data))
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Event {
    pub trigger: Trigger,
    pub timestamp: Duration,
}

impl Event {
    fn from_event_data(event_data: EventData) -> Event {
        Event {
            trigger: if event_data.id == EVENT_TYPE_RISING_EDGE {
                Trigger::RisingEdge
            } else {
                Trigger::FallingEdge
            },
            timestamp: Duration::from_nanos(event_data.timestamp),
        }
    }
}

// Read interrupt event
pub fn get_event(event_fd: c_int) -> Result<Option<Event>> {
    if let Some(event_data) = EventData::new(event_fd)? {
        Ok(Some(Event::from_event_data(event_data)))
    } else {
        Ok(None)
    }
}

// Flush any pending interrupt events
pub fn flush_events(event_fd: c_int) {
    unsafe {
        lseek(event_fd, 0, SEEK_END);
    }
}

// Find the correct gpiochip device based on its label
pub unsafe fn find_driver() -> Result<File> {
    let driver_name = b"pinctrl-bcm2835\0";

    for idx in 0..=255 {
        let gpiochip = OpenOptions::new()
            .read(true)
            .write(true)
            .open(format!("/dev/gpiochip{}", idx))?;

        let chip_info = ChipInfo::new(gpiochip.as_raw_fd())?;
        if chip_info.label[0..driver_name.len()] == driver_name[..] {
            return Ok(gpiochip);
        }
    }

    Err(Error::Io(io::Error::from_raw_os_error(2)))
}

pub fn get_level(cdev_fd: c_int, pin: u8) -> Result<Level> {
    let chip_info = ChipInfo::new(cdev_fd)?;

    if u32::from(pin) > chip_info.lines {
        return Err(Error::InvalidPin(pin));
    }

    match HandleRequest::new(cdev_fd, &[pin])?.levels()?.values[0] {
        1 => Ok(Level::High),
        _ => Ok(Level::Low),
    }
}

pub fn poll_interrupt(cdev_fd: c_int, pin: u8, trigger: Trigger) -> Result<Level> {
    let chip_info = ChipInfo::new(cdev_fd)?;

    if u32::from(pin) > chip_info.lines {
        return Err(Error::InvalidPin(pin));
    }

    let event_request = EventRequest::new(cdev_fd, pin, trigger)?;

    let poll = Epoll::new()?;
    poll.add(
        event_request.fd,
        event_request.fd as u64,
        EPOLLIN | EPOLLPRI,
    )?;

    let mut events = [epoll_event { events: 0, u64: 0 }; 1];
    loop {
        let num_events = poll.wait(&mut events, None)?;
        if num_events > 0 {
            for event in &events[0..num_events] {
                if event.u64 as c_int == event_request.fd {
                    if let Some(int_event) = get_event(event_request.fd)? {
                        match int_event.trigger {
                            Trigger::RisingEdge => return Ok(Level::High),
                            _ => return Ok(Level::Low),
                        }
                    } else {
                        return get_level(cdev_fd, pin);
                    }
                }
            }
        }
    }
}
<commit_msg>Remove flush_events<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use libc::{c_int, c_ulong, c_void, ioctl, read};
use std::fs::{File, OpenOptions};
use std::io;
use std::mem::size_of;
use std::os::unix::io::AsRawFd;
use std::time::Duration;

use gpio::epoll::{epoll_event, Epoll, EPOLLIN, EPOLLPRI};
use gpio::{Error, Level, Result, Trigger};

fn parse_retval(retval: c_int) -> Result<i32> {
    if retval == -1 {
        Err(Error::Io(io::Error::last_os_error()))
    } else {
        Ok(retval)
    }
}

const NRBITS: u8 = 8;
const TYPEBITS: u8 = 8;
const SIZEBITS: u8 = 14;
const DIRBITS: u8 = 2;

const NRSHIFT: u8 = 0;
const TYPESHIFT: u8 = (NRSHIFT + NRBITS);
const SIZESHIFT: u8 = (TYPESHIFT + TYPEBITS);
const DIRSHIFT: u8 = (SIZESHIFT + SIZEBITS);

const NR_GET_CHIP_INFO: c_ulong = 0x01 << NRSHIFT;
const NR_GET_LINE_INFO: c_ulong = 0x02 << NRSHIFT;
const NR_GET_LINE_HANDLE: c_ulong = 0x03 << NRSHIFT;
const NR_GET_LINE_EVENT: c_ulong = 0x04 << NRSHIFT;
const NR_GET_LINE_VALUES: c_ulong = 0x08 << NRSHIFT;
const NR_SET_LINE_VALUES: c_ulong = 0x09 << NRSHIFT;

const TYPE_GPIO: c_ulong = (0xB4 as c_ulong) << TYPESHIFT;

const SIZE_CHIP_INFO: c_ulong = (size_of::<ChipInfo>() as c_ulong) << SIZESHIFT;
const SIZE_LINE_INFO: c_ulong = (size_of::<LineInfo>() as c_ulong) << SIZESHIFT;
const SIZE_HANDLE_REQUEST: c_ulong = (size_of::<HandleRequest>() as c_ulong) << SIZESHIFT;
const SIZE_EVENT_REQUEST: c_ulong = (size_of::<EventRequest>() as c_ulong) << SIZESHIFT;
const SIZE_HANDLE_DATA: c_ulong = (size_of::<HandleData>() as c_ulong) << SIZESHIFT;

const DIR_NONE: c_ulong = 0;
const DIR_WRITE: c_ulong = 1 << DIRSHIFT;
const DIR_READ: c_ulong = 2 << DIRSHIFT;
const DIR_READ_WRITE: c_ulong = DIR_READ | DIR_WRITE;

const REQ_GET_CHIP_INFO: c_ulong = DIR_READ | TYPE_GPIO | NR_GET_CHIP_INFO | SIZE_CHIP_INFO;
const REQ_GET_LINE_INFO: c_ulong = DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_INFO | SIZE_LINE_INFO;
const REQ_GET_LINE_HANDLE: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_HANDLE | SIZE_HANDLE_REQUEST;
const REQ_GET_LINE_EVENT: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_EVENT | SIZE_EVENT_REQUEST;
const REQ_GET_LINE_VALUES: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_VALUES | SIZE_HANDLE_DATA;
const REQ_SET_LINE_VALUES: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_SET_LINE_VALUES | SIZE_HANDLE_DATA;

const NAME_BUFSIZE: usize = 32;
const LABEL_BUFSIZE: usize = 32;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct ChipInfo {
    pub name: [u8; NAME_BUFSIZE],
    pub label: [u8; LABEL_BUFSIZE],
    pub lines: u32,
}

impl ChipInfo {
    pub fn new(cdev_fd: c_int) -> Result<ChipInfo> {
        let mut chip_info = ChipInfo {
            name: [0u8; NAME_BUFSIZE],
            label: [0u8; LABEL_BUFSIZE],
            lines: 0,
        };

        parse_retval(unsafe { ioctl(cdev_fd, REQ_GET_CHIP_INFO, &mut chip_info) })?;

        Ok(chip_info)
    }
}

const LINE_FLAG_KERNEL: u32 = 0x01;
const LINE_FLAG_IS_OUT: u32 = 0x02;
const LINE_FLAG_ACTIVE_LOW: u32 = 0x04;
const LINE_FLAG_OPEN_DRAIN: u32 = 0x08;
const LINE_FLAG_OPEN_SOURCE: u32 = 0x10;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct LineInfo {
    pub line_offset: u32,
    pub flags: u32,
    pub name: [u8; NAME_BUFSIZE],
    pub consumer: [u8; LABEL_BUFSIZE],
}

impl LineInfo {
    pub fn new() -> LineInfo {
        LineInfo {
            line_offset: 0,
            flags: 0,
            name: [0u8; NAME_BUFSIZE],
            consumer: [0u8; LABEL_BUFSIZE],
        }
    }
}

const HANDLES_MAX: usize = 64;
const HANDLE_FLAG_INPUT: u32 = 0x01;
const HANDLE_FLAG_OUTPUT: u32 = 0x02;
const HANDLE_FLAG_ACTIVE_LOW: u32 = 0x04;
const HANDLE_FLAG_OPEN_DRAIN: u32 = 0x08;
const HANDLE_FLAG_OPEN_SOURCE: u32 = 0x10;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct HandleRequest {
    pub line_offsets: [u32; HANDLES_MAX],
    pub flags: u32,
    pub default_values: [u8; HANDLES_MAX],
    pub consumer_label: [u8; LABEL_BUFSIZE],
    pub lines: u32,
    pub fd: c_int,
}

impl HandleRequest {
    pub fn new(cdev_fd: c_int, pins: &[u8]) -> Result<HandleRequest> {
        let mut handle_request = HandleRequest {
            line_offsets: [0u32; HANDLES_MAX],
            flags: 0,
            default_values: [0u8; HANDLES_MAX],
            consumer_label: [0u8; LABEL_BUFSIZE],
            lines: 0,
            fd: 0,
        };

        let pins: &[u8] = if pins.len() > HANDLES_MAX {
            handle_request.lines = HANDLES_MAX as u32;
            &pins[0..HANDLES_MAX]
        } else {
            handle_request.lines = pins.len() as u32;
            pins
        };

        for (idx, pin) in pins.iter().enumerate() {
            handle_request.line_offsets[idx] = u32::from(*pin);
        }

        parse_retval(unsafe { ioctl(cdev_fd, REQ_GET_LINE_HANDLE, &mut handle_request) })?;

        Ok(handle_request)
    }

    pub fn levels(&self) -> Result<HandleData> {
        let mut handle_data = HandleData::new();

        parse_retval(unsafe { ioctl(self.fd, REQ_GET_LINE_VALUES, &mut handle_data) })?;

        Ok(handle_data)
    }

    pub fn set_levels(&mut self, levels: &[Level]) -> Result<()> {
        let mut handle_data = HandleData::new();
        let levels: &[Level] = if levels.len() > HANDLES_MAX {
            &levels[0..HANDLES_MAX]
        } else {
            levels
        };

        for (idx, level) in levels.iter().enumerate() {
            handle_data.values[idx] = *level as u8;
        }

        parse_retval(unsafe { ioctl(self.fd, REQ_SET_LINE_VALUES, &mut handle_data) })?;

        Ok(())
    }
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct HandleData {
    pub values: [u8; HANDLES_MAX],
}

impl HandleData {
    pub fn new() -> HandleData {
        HandleData {
            values: [0u8; HANDLES_MAX],
        }
    }
}

const EVENT_FLAG_RISING_EDGE: u32 = 0x01;
const EVENT_FLAG_FALLING_EDGE: u32 = 0x02;
const EVENT_FLAG_BOTH_EDGES: u32 = EVENT_FLAG_RISING_EDGE | EVENT_FLAG_FALLING_EDGE;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct EventRequest {
    pub line_offset: u32,
    pub handle_flags: u32,
    pub event_flags: u32,
    pub consumer_label: [u8; LABEL_BUFSIZE],
    pub fd: c_int,
}

impl EventRequest {
    pub fn new(cdev_fd: c_int, pin: u8, trigger: Trigger) -> Result<EventRequest> {
        let mut event_request = EventRequest {
            line_offset: u32::from(pin),
            handle_flags: HANDLE_FLAG_INPUT,
            event_flags: trigger as u32,
            consumer_label: [0u8; LABEL_BUFSIZE],
            fd: 0,
        };

        parse_retval(unsafe { ioctl(cdev_fd, REQ_GET_LINE_EVENT, &mut event_request) })?;

        Ok(event_request)
    }
}

const EVENT_TYPE_RISING_EDGE: u32 = 0x01;
const EVENT_TYPE_FALLING_EDGE: u32 = 0x02;

#[derive(Copy, Clone)]
#[repr(C)]
struct EventData {
    timestamp: u64,
    id: u32,
}

impl EventData {
    fn new(event_fd: c_int) -> Result<Option<EventData>> {
        let mut event_data = EventData {
            timestamp: 0,
            id: 0,
        };

        let bytes_read = parse_retval(unsafe {
            read(
                event_fd,
                &mut event_data as *mut EventData as *mut c_void,
                size_of::<EventData>(),
            ) as i32
        })?;

        if bytes_read != size_of::<EventData>() as i32 {
            Ok(None)
        } else {
            Ok(Some(event_data))
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Event {
    pub trigger: Trigger,
    pub timestamp: Duration,
}

impl Event {
    fn from_event_data(event_data: EventData) -> Event {
        Event {
            trigger: if event_data.id == EVENT_TYPE_RISING_EDGE {
                Trigger::RisingEdge
            } else {
                Trigger::FallingEdge
            },
            timestamp: Duration::from_nanos(event_data.timestamp),
        }
    }
}

// Read interrupt event
pub fn get_event(event_fd: c_int) -> Result<Option<Event>> {
    if let Some(event_data) = EventData::new(event_fd)? {
        Ok(Some(Event::from_event_data(event_data)))
    } else {
        Ok(None)
    }
}

// Find the correct gpiochip device based on its label
pub unsafe fn find_driver() -> Result<File> {
    let driver_name = b"pinctrl-bcm2835\0";

    for idx in 0..=255 {
        let gpiochip = OpenOptions::new()
            .read(true)
            .write(true)
            .open(format!("/dev/gpiochip{}", idx))?;

        let chip_info = ChipInfo::new(gpiochip.as_raw_fd())?;
        if chip_info.label[0..driver_name.len()] == driver_name[..] {
            return Ok(gpiochip);
        }
    }

    Err(Error::Io(io::Error::from_raw_os_error(2)))
}

pub fn get_level(cdev_fd: c_int, pin: u8) -> Result<Level> {
    let chip_info = ChipInfo::new(cdev_fd)?;

    if u32::from(pin) > chip_info.lines {
        return Err(Error::InvalidPin(pin));
    }

    match HandleRequest::new(cdev_fd, &[pin])?.levels()?.values[0] {
        1 => Ok(Level::High),
        _ => Ok(Level::Low),
    }
}

pub fn poll_interrupt(cdev_fd: c_int, pin: u8, trigger: Trigger) -> Result<Level> {
    let chip_info = ChipInfo::new(cdev_fd)?;

    if u32::from(pin) > chip_info.lines {
        return Err(Error::InvalidPin(pin));
    }

    let event_request = EventRequest::new(cdev_fd, pin, trigger)?;

    let poll = Epoll::new()?;
    poll.add(
        event_request.fd,
        event_request.fd as u64,
        EPOLLIN | EPOLLPRI,
    )?;

    let mut events = [epoll_event { events: 0, u64: 0 }; 1];
    loop {
        let num_events = poll.wait(&mut events, None)?;
        if num_events > 0 {
            for event in &events[0..num_events] {
                if event.u64 as c_int == event_request.fd {
                    if let Some(int_event) = get_event(event_request.fd)? {
                        match int_event.trigger {
                            Trigger::RisingEdge => return Ok(Level::High),
                            _ => return Ok(Level::Low),
                        }
                    } else {
                        return get_level(cdev_fd, pin);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::convert::{Convert};
use std::hash::{Hasher};
use const_random::const_random;

///These constants come from splitmix64 which is derived from Java's SplitableRandom, which is based on DotMix and MurmurHash3.
const MULTIPLES: [u64; 2] = [0xBF58476D1CE4E5B9, 0x94D049BB133111EB];
const INCREMENT: u64 = 0x9e3779b97f4a7c15;

const DEFAULT_KEYS: [u64; 2] = [const_random!(u64), const_random!(u64)];

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: u64,
    key: u64,
}

/// Provides a [Hasher] is typically used (e.g. by [HashMap]) to create
/// [AHasher]s for each key such that they are hashed independently of one
/// another, since [AHasher]s contain state.
///
/// Constructs a new [AHasher] with compile time generated constants keys.
/// So the key will be the same from one instance to another,
/// but different from build to the next. So if it is possible for a potential
/// attacker to have access to your compiled binary it would be better
/// to specify keys generated at runtime.
///
/// # Examples
///
/// ```
/// use ahash::AHasher;
/// use std::hash::Hasher;
///
/// let mut hasher_1 = AHasher::default();
/// let mut hasher_2 = AHasher::default();
///
/// hasher_1.write_u32(8128);
/// hasher_2.write_u32(8128);
///
/// assert_eq!(hasher_1.finish(), hasher_2.finish());
/// ```
/// [Hasher]: std::hash::Hasher
/// [HashMap]: std::collections::HashMap
impl Default for AHasher {
    #[inline]
    fn default() -> AHasher {
        AHasher {buffer: DEFAULT_KEYS[0], key: DEFAULT_KEYS[1]}
    }
}
impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    #[inline]
    pub fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: key0, key: key1 }
    }

    #[inline(always)]
    fn update(&mut self, new_data: u64) {
        let value = new_data ^ self.key;
        self.buffer ^= ((value >> 30) ^ value).wrapping_mul(MULTIPLES[0]);
        self.key = self.key.wrapping_add(INCREMENT);
    }
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {

    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.update(i as u64);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.update(i as u64);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.update(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.update(i as u64);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        let data: [u64;2] = i.convert();
        self.update(data[0]);
        self.update(data[1]);
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        self.key ^= length;
        while data.len() >= 8 {
            let (block, rest) = data.split_at(8);
            let val: u64 = as_array!(block, 8).convert();
            self.update(val);
            data = rest;
        }
        if data.len() >= 4 {
            let (block, rest) = data.split_at(4);
            let val: u32 = as_array!(block, 4).convert();
            self.update(val as u64);
            data = rest;
        }
        if data.len() >= 2 {
            let (block, rest) = data.split_at(2);
            let val: u16 = as_array!(block, 2).convert();
            self.update(val as u64);
            data = rest;
        }
        if data.len() >= 1 {
            self.update(data[0] as u64);
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result = self.buffer ^ self.key;
        let result = (result ^ (result >> 27)).wrapping_mul(MULTIPLES[1]);
        result ^ (result >> 31)
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::hash::{BuildHasherDefault};
    use crate::convert::Convert;
    use crate::fallback_hash::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer);
        assert_ne!(0, hasher_a.key);
        assert_ne!(hasher_a.buffer, hasher_a.key);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer, hasher_b.buffer);
        assert_eq!(hasher_a.key, hasher_b.key);
    }

    #[test]
    fn test_hash() {
        let mut hasher = AHasher::new_with_keys(0,0);
        let value: u64 = 1 << 32;
        hasher.update(value);
        let result = hasher.buffer;
        let mut hasher = AHasher::new_with_keys(0,0);
        let value2: u64 = 1;
        hasher.update(value2);
        let result2 = hasher.buffer;
        let result: [u8; 8] = result.convert();
        let result2: [u8; 8] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}<commit_msg>Add comment explaining logic<commit_after>use crate::convert::{Convert};
use std::hash::{Hasher};
use const_random::const_random;

///These constants come from splitmix64 which is derived from Java's SplitableRandom, which is based on DotMix and MurmurHash3.
const MULTIPLES: [u64; 2] = [0xBF58476D1CE4E5B9, 0x94D049BB133111EB];
const INCREMENT: u64 = 0x9e3779b97f4a7c15;

const DEFAULT_KEYS: [u64; 2] = [const_random!(u64), const_random!(u64)];

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: u64,
    key: u64,
}

/// Provides a [Hasher] is typically used (e.g. by [HashMap]) to create
/// [AHasher]s for each key such that they are hashed independently of one
/// another, since [AHasher]s contain state.
///
/// Constructs a new [AHasher] with compile time generated constants keys.
/// So the key will be the same from one instance to another,
/// but different from build to the next. So if it is possible for a potential
/// attacker to have access to your compiled binary it would be better
/// to specify keys generated at runtime.
///
/// # Examples
///
/// ```
/// use ahash::AHasher;
/// use std::hash::Hasher;
///
/// let mut hasher_1 = AHasher::default();
/// let mut hasher_2 = AHasher::default();
///
/// hasher_1.write_u32(8128);
/// hasher_2.write_u32(8128);
///
/// assert_eq!(hasher_1.finish(), hasher_2.finish());
/// ```
/// [Hasher]: std::hash::Hasher
/// [HashMap]: std::collections::HashMap
impl Default for AHasher {
    #[inline]
    fn default() -> AHasher {
        AHasher {buffer: DEFAULT_KEYS[0], key: DEFAULT_KEYS[1]}
    }
}
impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    #[inline]
    pub fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: key0, key: key1 }
    }

    /// This update function has the goal of updating the buffer with a single multiply
    /// FxHash does this but is venerable to attack. To avoid this two changes need to
    /// happen before the multiply. The input needs to be masked to with an unpredictable value.
    /// However other hashes such as murmurhash have taken that approach but were found venerable to attack.
    /// The attack was based on the idea of reversing the pre-mixing (Which is necessarily reversible otherwise
    /// bits would be lost) then placing a difference in the highest bit before the multiply. Because a multiply
    /// can never affect the bits to the right of it. This version avoids this vulnerability by masking first,
    /// then performing a rotate an zor. This makes it not possible for an attacker from placing a single bit
    /// difference between two at the high bit.
    /// It is also intentionally structured so that the buffer is only xored into at the end. Because the method
    /// is configured to be inlined, the compiler will unroll any loop this gets placed in and the loop can be
    /// automatically vectorized and the rotates, xors, and multiplies can be paralleled.
    /// The adding of the increment is moved to the bottom rather than the top. This allows one less add to be
    /// performed overall, but more importantly, it follows the multiply, which is expensive. So the CPU can
    /// run another operation afterwords if does not depend on the output of the multiply operation.
    #[inline(always)]
    fn update(&mut self, new_data: u64) {
        let value = new_data ^ self.key;
        self.buffer ^= ((value >> 30) ^ value).wrapping_mul(MULTIPLES[0]);
        self.key = self.key.wrapping_add(INCREMENT);
    }
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {

    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.update(i as u64);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.update(i as u64);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.update(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.update(i as u64);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        let data: [u64;2] = i.convert();
        self.update(data[0]);
        self.update(data[1]);
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        self.key ^= length;
        while data.len() >= 8 {
            let (block, rest) = data.split_at(8);
            let val: u64 = as_array!(block, 8).convert();
            self.update(val);
            data = rest;
        }
        if data.len() >= 4 {
            let (block, rest) = data.split_at(4);
            let val: u32 = as_array!(block, 4).convert();
            self.update(val as u64);
            data = rest;
        }
        if data.len() >= 2 {
            let (block, rest) = data.split_at(2);
            let val: u16 = as_array!(block, 2).convert();
            self.update(val as u64);
            data = rest;
        }
        if data.len() >= 1 {
            self.update(data[0] as u64);
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result = self.buffer ^ self.key;
        let result = (result ^ (result >> 27)).wrapping_mul(MULTIPLES[1]);
        result ^ (result >> 31)
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::hash::{BuildHasherDefault};
    use crate::convert::Convert;
    use crate::fallback_hash::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer);
        assert_ne!(0, hasher_a.key);
        assert_ne!(hasher_a.buffer, hasher_a.key);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer, hasher_b.buffer);
        assert_eq!(hasher_a.key, hasher_b.key);
    }

    #[test]
    fn test_hash() {
        let mut hasher = AHasher::new_with_keys(0,0);
        let value: u64 = 1 << 32;
        hasher.update(value);
        let result = hasher.buffer;
        let mut hasher = AHasher::new_with_keys(0,0);
        let value2: u64 = 1;
        hasher.update(value2);
        let result2 = hasher.buffer;
        let result: [u8; 8] = result.convert();
        let result2: [u8; 8] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}<|endoftext|>