<commit_before>use std::str::Chars;
use std::iter::Peekable;
use std::iter::Enumerate;
use std::io::Read;
use std::path::Path;
use std::fs::File;

#[derive(Debug)]
pub enum Token {
    Ident(String),

    OpenBrace,
    CloseBrace,
    OpenParen,
    CloseParen,
    OpenSquare,
    CloseSquare,

    Newline,
    Whitespace,

    Underscore,
    Dash,

    SingleQuote,
    DoubleQuote,
    Comma,
    SemiColon,
    Colon,
    ForwardSlash,
    Pipe,
    Dot,
    Equal,
    Bang,
    Greater,
    Less,
    Hash,
    Dollar,
    Amp,
    Asterisk,
    SingleLineComment(String),
    Attribute(String),
    String(String),
}

impl Token {
    pub fn as_char(&self) -> Option<char> {
        match *self {
            Token::OpenBrace => Some('{'),
            Token::CloseBrace => Some('}'),
            Token::OpenParen => Some('('),
            Token::CloseParen => Some(')'),
            Token::OpenSquare => Some('['),
            Token::CloseSquare => Some(']'),
            Token::Newline => Some('\n'),
            Token::Whitespace => Some(' '),
            Token::Underscore => Some('_'),
            Token::Dash => Some('-'),
            Token::SingleQuote => Some('\''),
            Token::DoubleQuote => Some('"'),
            Token::Comma => Some(','),
            Token::SemiColon => Some(';'),
            Token::Colon => Some(':'),
            Token::ForwardSlash => Some('/'),
            Token::Pipe => Some('|'),
            Token::Dot => Some('.'),
            Token::Equal => Some('='),
            Token::Bang => Some('!'),
            Token::Greater => Some('>'),
            Token::Less => Some('<'),
            Token::Hash => Some('#'),
            Token::Dollar => Some('$'),
            Token::Amp => Some('&'),
            Token::Asterisk => Some('*'),

            _ => None,
        }
    }
}

pub trait Tokenizer {
    fn get_stream(&self, input: &str) -> Vec<Span>;
    fn handle_ident(&self, ch: char, iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span;
}

#[derive(Debug)]
pub struct Span {
    pub start: usize,
    pub end: usize,
    pub token: Token,
    pub y_pos: usize,
}

pub struct SyntaxInstance {
    pub lexer: Box<Tokenizer>,
    pub file_extensions: Vec<String>,
    pub keywords: Vec<String>,
}

impl SyntaxInstance {
    pub fn rust() -> SyntaxInstance {
        let keywords = vec!(
            "".into()
            );

        SyntaxInstance {
            lexer: Box::new(RustSyntax),
            file_extensions: vec!("rs".into()),
            keywords: keywords,
        }
    }

    pub fn get_stream(&self, text: &str) -> Vec<Span> {
        self.lexer.get_stream(text)
    }
}

fn next_is(iter: &mut Peekable<Enumerate<Chars>>, ch: char) -> bool {
    if let Some(&(_, c)) = iter.peek() {
        if c == ch { true } else { false }
    } else { false }
}

pub struct RustSyntax;

impl Tokenizer for RustSyntax {
    fn get_stream(&self, input: &str) -> Vec<Span> {
        let mut tokens = Vec::new();
        let mut y_pos = 0;

        let mut chars = input.chars().enumerate().peekable();
        while let Some((idx, c)) = chars.next() {
            match c {
                ' ' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Whitespace}),
                '\n' => {
                    y_pos += 1;
                    tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Newline})
                }
                '{' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::OpenBrace}),
                '}' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::CloseBrace}),
                '(' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::OpenParen}),
                ')' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::CloseParen}),
                '[' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::OpenSquare}),
                ']' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::CloseSquare}),
                '\'' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::SingleQuote}),
                '"' => {
                    let st = idx;
                    let mut end = idx;
                    let mut s = String::from("\"");
                    while let Some(&(e, c)) = chars.peek() {
                        end = e;
                        s.push(chars.next().unwrap().1);
                        if c == '"' {
                             break;
                        }
                    }
                    tokens.push(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::String(s),
                    });
                }
                ',' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Comma}),
                ';' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::SemiColon}),
                ':' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Colon}),
                '/' => {
                    let st = idx;
                    let mut end = idx;
                    if next_is(&mut chars, '/') {
                        let mut s = String::from("/");
                        while let Some(&(e, c)) = chars.peek() {
                            if c == '\n' { break }
                            end = e;
                            s.push(chars.next().unwrap().1)
                        }
                        //tokens.push(Token::SingleLineComment(s));
                        tokens.push(Span {
                            y_pos: y_pos,
                            start: st,
                            end: end,
                            token: Token::SingleLineComment(s),
                        });
                        continue;
                    }
                    tokens.push(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::ForwardSlash,
                    });
                }
                '|' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Pipe}),
                '.' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Dot}),
                '=' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Equal}),
                '!' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Bang}),
                '>' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Greater}),
                '<' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Less}),
                '-' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Dash}),
                '#' => {
                    let st = idx;
                    let mut end = idx;
                    if next_is(&mut chars, '!') || next_is(&mut chars, '[') {
                        let mut s = String::new();
                        while let Some(&(e, c)) = chars.peek() {
                            if c == '\n' { break }
                            end = e;
                            s.push(chars.next().unwrap().1)
                        }
                        tokens.push(Span {
                            y_pos: y_pos,
                            start: st,
                            end: end,
                            token: Token::Attribute(s),
                        });
                        continue;
                    }
                    tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash})
                }
                '$' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Dollar}),
                '&' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Amp}),
                '*' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Asterisk}),
                _ => {
                    let ident = self.handle_ident(c, &mut chars, y_pos);
                    tokens.push(ident);
                }
            };

        }

        tokens
    }

    fn handle_ident(&self, ch: char, iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span {
        let mut ident = String::new();
        ident.push(ch);
        let start = iter.peek().unwrap().0 - 1;

        while self.is_ident(iter.peek()) {
            ident.push(iter.next().unwrap().1)
        }

        Span {
            y_pos: y_pos,
            start: start,
            end: start + ident.len() - 1,
            token: Token::Ident(ident),
        }
    }

}

impl RustSyntax {
    fn is_ident(&self, ch: Option<&(usize, char)>) -> bool {
        if let Some(&(idx, c)) = ch {
            c.is_alphabetic() || c == '_'
        } else {
            false
        }
    }
}

fn main() {
    let rs = RustSyntax;

    let mut data = String::new();
    let mut f = File::open(Path::new("/home/gchp/src/github.com/gchp/iota/input.rs")).unwrap();
    let _ = f.read_to_string(&mut data);

    let tokens = rs.get_stream(&*data);

    for t in &tokens {
        println!("{:?}", t);
    }

}
<commit_msg>Allow Tokenizer impls to handle chars<commit_after>use std::str::Chars;
use std::iter::Peekable;
use std::iter::Enumerate;
use std::io::Read;
use std::path::Path;
use std::fs::File;

#[derive(Debug)]
pub enum Token {
    Ident(String),

    OpenBrace,
    CloseBrace,
    OpenParen,
    CloseParen,
    OpenSquare,
    CloseSquare,

    Newline,
    Whitespace,

    Underscore,
    Dash,

    SingleQuote,
    DoubleQuote,
    Comma,
    SemiColon,
    Colon,
    ForwardSlash,
    Pipe,
    Dot,
    Equal,
    Bang,
    Greater,
    Less,
    Hash,
    Dollar,
    Amp,
    Asterisk,
    SingleLineComment(String),
    Attribute(String),
    String(String),
}

impl Token {
    pub fn as_char(&self) -> Option<char> {
        match *self {
            Token::OpenBrace => Some('{'),
            Token::CloseBrace => Some('}'),
            Token::OpenParen => Some('('),
            Token::CloseParen => Some(')'),
            Token::OpenSquare => Some('['),
            Token::CloseSquare => Some(']'),
            Token::Newline => Some('\n'),
            Token::Whitespace => Some(' '),
            Token::Underscore => Some('_'),
            Token::Dash => Some('-'),
            Token::SingleQuote => Some('\''),
            Token::DoubleQuote => Some('"'),
            Token::Comma => Some(','),
            Token::SemiColon => Some(';'),
            Token::Colon => Some(':'),
            Token::ForwardSlash => Some('/'),
            Token::Pipe => Some('|'),
            Token::Dot => Some('.'),
            Token::Equal => Some('='),
            Token::Bang => Some('!'),
            Token::Greater => Some('>'),
            Token::Less => Some('<'),
            Token::Hash => Some('#'),
            Token::Dollar => Some('$'),
            Token::Amp => Some('&'),
            Token::Asterisk => Some('*'),

            _ => None,
        }
    }
}

pub trait Tokenizer {
    fn handle_ident(&self, ch: char, iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span;
    fn handle_char(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize, idx: usize) -> Option<Span>;

    fn get_stream(&self, input: &str) -> Vec<Span> {
        let mut tokens = Vec::new();
        let mut y_pos = 0;

        let mut chars = input.chars().enumerate().peekable();
        while let Some((idx, c)) = chars.next() {
            match self.handle_char(c, &mut chars, y_pos, idx) {
                Some(span) => tokens.push(span),
                None => {
                    match c {
                        ' ' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Whitespace}),
                        '\n' => {
                            y_pos += 1;
                            tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Newline})
                        }
                        '{' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::OpenBrace}),
                        '}' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::CloseBrace}),
                        '(' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::OpenParen}),
                        ')' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::CloseParen}),
                        '[' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::OpenSquare}),
                        ']' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::CloseSquare}),
                        '\'' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::SingleQuote}),
                        '"' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::DoubleQuote}),
                        ',' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Comma}),
                        ';' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::SemiColon}),
                        ':' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Colon}),
                        '/' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::ForwardSlash}),
                        '|' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Pipe}),
                        '.' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Dot}),
                        '=' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Equal}),
                        '!' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Bang}),
                        '>' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Greater}),
                        '<' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Less}),
                        '-' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Dash}),
                        '#' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash}),
                        '$' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Dollar}),
                        '&' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Amp}),
                        '*' => tokens.push(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Asterisk}),
                        _ => {
                            let ident = self.handle_ident(c, &mut chars, y_pos);
                            tokens.push(ident);
                        }
                    }
                }
            }
        }

        tokens
    }
}

#[derive(Debug)]
pub struct Span {
    pub start: usize,
    pub end: usize,
    pub token: Token,
    pub y_pos: usize,
}

pub struct SyntaxInstance {
    pub lexer: Box<Tokenizer>,
    pub file_extensions: Vec<String>,
    pub keywords: Vec<String>,
}

impl SyntaxInstance {
    pub fn rust() -> SyntaxInstance {
        let keywords = vec!(
            "".into()
            );

        SyntaxInstance {
            lexer: Box::new(RustSyntax),
            file_extensions: vec!("rs".into()),
            keywords: keywords,
        }
    }

    pub fn get_stream(&self, text: &str) -> Vec<Span> {
        self.lexer.get_stream(text)
    }
}

fn next_is(iter: &mut Peekable<Enumerate<Chars>>, ch: char) -> bool {
    if let Some(&(_, c)) = iter.peek() {
        if c == ch { true } else { false }
    } else { false }
}

pub struct RustSyntax;

impl Tokenizer for RustSyntax {
    fn handle_char(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize, idx: usize) -> Option<Span> {
        match ch {
            '#' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '!') || next_is(&mut iter, '[') {
                    let mut s = String::new();
                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Attribute(s),
                    });
                }
                return Some(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash})
            }

            '/' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '/') {
                    let mut s = String::from("/");
                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }
                    //tokens.push(Token::SingleLineComment(s));
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::SingleLineComment(s),
                    });
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::ForwardSlash,
                });
            }

            '"' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\"");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '"' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::String(s),
                });
            }

            _ => None,
        }

    }

    fn handle_ident(&self, ch: char, iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span {
        let mut ident = String::new();
        ident.push(ch);
        let start = iter.peek().unwrap().0 - 1;

        while self.is_ident(iter.peek()) {
            ident.push(iter.next().unwrap().1)
        }

        Span {
            y_pos: y_pos,
            start: start,
            end: start + ident.len() - 1,
            token: Token::Ident(ident),
        }
    }

}

impl RustSyntax {
    fn is_ident(&self, ch: Option<&(usize, char)>) -> bool {
        if let Some(&(idx, c)) = ch {
            c.is_alphabetic() || c == '_'
        } else {
            false
        }
    }
}

fn main() {
    let rs = RustSyntax;

    let mut data = String::new();
    let mut f = File::open(Path::new("/home/gchp/src/github.com/gchp/iota/input.rs")).unwrap();
    let _ = f.read_to_string(&mut data);

    let tokens = rs.get_stream(&*data);

    for t in &tokens {
        println!("{:?}", t);
    }

}
<|endoftext|>


<commit_before>// Copyright 2015 Copyright (c) 2015 Benoît Labaere (benoit.labaere@gmail.com)
//
// Licensed under the MIT license LICENSE or <http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according to those terms.

use std::rc::Rc;
use std::sync::mpsc::Sender;
use std::collections::HashMap;
use std::io;
use std::boxed::FnBox;

use mio;

use byteorder::{ BigEndian, WriteBytesExt, ReadBytesExt };

use super::Protocol;
use pipe::*;
use endpoint::*;
use global::*;
use event_loop_msg::SocketEvt;
use EventLoop;
use EventLoopAction;
use Message;

pub struct Rep {
    pipes: HashMap<mio::Token, Pipe>,
    evt_sender: Rc<Sender<SocketEvt>>,
    cancel_send_timeout: Option<EventLoopAction>,
    cancel_recv_timeout: Option<EventLoopAction>,
    pending_send: Option<Rc<Message>>,
    pending_recv: bool,
    backtrace: Vec<u8>,
    ttl: u8
}

impl Rep {
    pub fn new(evt_sender: Rc<Sender<SocketEvt>>) -> Rep {
        Rep {
            pipes: HashMap::new(),
            evt_sender: evt_sender,
            cancel_send_timeout: None,
            cancel_recv_timeout: None,
            pending_send: None,
            pending_recv: false,
            backtrace: Vec::with_capacity(64),
            ttl: 8
        }
    }

    fn on_msg_send_finished(&mut self, event_loop: &mut EventLoop, evt: SocketEvt) {
        let _ = self.evt_sender.send(evt);
        let timeout = self.cancel_send_timeout.take();

        timeout.map(|cancel_timeout| cancel_timeout.call_box((event_loop,)));

        self.pending_send = None;
        self.backtrace.clear();
    }

    fn on_msg_send_finished_ok(&mut self, event_loop: &mut EventLoop) {
        self.on_msg_send_finished(event_loop, SocketEvt::MsgSent);
        for (_, pipe) in self.pipes.iter_mut() {
            pipe.finish_send();
        }
    }

    fn on_msg_send_finished_err(&mut self, event_loop: &mut EventLoop, err: io::Error) {
        self.on_msg_send_finished(event_loop, SocketEvt::MsgNotSent(err));
        for (_, pipe) in self.pipes.iter_mut() {
            pipe.cancel_send();
        }
    }

    fn on_msg_send_started(&mut self, token: mio::Token) {
        self.pending_send = None;
        for (_, pipe) in self.pipes.iter_mut() {
            if pipe.token() == token {
                continue;
            } else {
                pipe.discard_send();
            }
        }
    }

    fn process_send_result(&mut self, event_loop: &mut EventLoop, sent: bool, sending: Option<mio::Token>) {
        if sent {
            self.on_msg_send_finished_ok(event_loop);
        } else if let Some(token) = sending {
            self.on_msg_send_started(token);
        }
    }

    fn save_received_header_to_backtrace(&mut self, msg: &Message) {
        self.backtrace.clear();
        self.backtrace.push_all(msg.get_header());
    }

    fn raw_msg_to_msg(&mut self, pipe_token: mio::Token, raw_msg: Message) -> io::Result<Option<Message>> {
        let (mut header, mut body) = raw_msg.explode();
        let pipe_id = pipe_token.as_usize() as u32;

        header.reserve(4);
        try!(header.write_u32::<BigEndian>(pipe_id));

        let mut hops = 0;
        loop {
            if hops >= self.ttl {
                return Ok(None);
            }

            hops += 1;

            if body.len() < 4 {
                return Ok(None);
            }

            let tail = body.split_off(4);
            header.push_all(&body);

            let position = header.len() - 4;
            if header[position] & 0x80 != 0 {
                let msg = Message::with_header_and_body(header, tail);

                return Ok(Some(msg));
            }
            body = tail;
        }
    }

    fn msg_to_raw_msg(&mut self, msg: Message) -> io::Result<(Message, mio::Token)> {
        let (header, body) = msg.explode();
        let pipe_token = try!(self.restore_pipe_id_from_backtrace());
        let header = try!(self.restore_header_from_backtrace(header));

        Ok((Message::with_header_and_body(header, body), pipe_token))
    }

    fn restore_pipe_id_from_backtrace(&self) -> io::Result<mio::Token> {
        if self.backtrace.len() < 4 {
            return Err(other_io_error("no backtrace from received message"));
        }
        let pipe_id_bytes = vec!(
            self.backtrace[0],
            self.backtrace[1],
            self.backtrace[2],
            self.backtrace[3]
        );
        let mut pipe_id_reader = io::Cursor::new(pipe_id_bytes);
        let pipe_id = try!(pipe_id_reader.read_u32::<BigEndian>());
        let pipe_token = mio::Token(pipe_id as usize);

        Ok(pipe_token)
    }

    fn restore_header_from_backtrace(&self, mut header: Vec<u8>) -> io::Result<Vec<u8>> {
        if self.backtrace.len() < 8 {
            return Err(other_io_error("no header in backtrace from received message"));
        }

        let backtrace = &self.backtrace[4..];

        header.reserve(backtrace.len());
        header.push_all(backtrace);

        Ok(header)
    }

    fn on_msg_recv_finished(&mut self, event_loop: &mut EventLoop, evt: SocketEvt) {
        let _ = self.evt_sender.send(evt);
        let timeout = self.cancel_recv_timeout.take();

        timeout.map(|cancel_timeout| cancel_timeout.call_box((event_loop,)));

        self.pending_recv = false;
    }

    fn on_msg_recv_finished_ok(&mut self, event_loop: &mut EventLoop, msg: Message) {
        self.save_received_header_to_backtrace(&msg);
        self.on_msg_recv_finished(event_loop, SocketEvt::MsgRecv(msg));

        for (_, pipe) in self.pipes.iter_mut() {
            pipe.finish_recv();
        }
    }

    fn on_msg_recv_finished_err(&mut self, event_loop: &mut EventLoop, err: io::Error) {
        self.on_msg_recv_finished(event_loop, SocketEvt::MsgNotRecv(err));

        for (_, pipe) in self.pipes.iter_mut() {
            pipe.cancel_recv();
        }
    }

    fn on_msg_recv_started(&mut self, token: mio::Token) {
        self.pending_recv = false;
        for (_, pipe) in self.pipes.iter_mut() {
            if pipe.token() == token {
                continue;
            } else {
                pipe.discard_recv();
            }
        }
    }

    fn on_raw_msg_recv_from(&mut self, event_loop: &mut EventLoop, raw_msg: Message, token: mio::Token) {
        match self.raw_msg_to_msg(token, raw_msg) {
            Ok(None)      => {}
            Ok(Some(msg)) => self.on_msg_recv_finished_ok(event_loop, msg),
            Err(e)        => self.on_msg_recv_finished_err(event_loop, e)
        }
    }

    fn process_recv_result(
        &mut self,
        event_loop: &mut EventLoop,
        received: Option<(Message, mio::Token)>,
        receiving: Option<mio::Token>) {

        if let Some((raw_msg, from)) = received {
            self.on_raw_msg_recv_from(event_loop, raw_msg, from);
        }
        else if let Some(token) = receiving {
            self.on_msg_recv_started(token);
        }
    }
}

impl Protocol for Rep {
    fn id(&self) -> u16 {
        SocketType::Rep.id()
    }

    fn peer_id(&self) -> u16 {
        SocketType::Req.id()
    }

    fn add_endpoint(&mut self, token: mio::Token, endpoint: Endpoint) {
        self.pipes.insert(token, Pipe::new(token, endpoint));
    }

    fn remove_endpoint(&mut self, token: mio::Token) -> Option<Endpoint> {
        self.pipes.remove(&token).map(|p| p.remove())
    }

    fn send(&mut self, event_loop: &mut EventLoop, msg: Message, cancel_timeout: EventLoopAction) {
        self.cancel_send_timeout = Some(cancel_timeout);

        let (raw_msg, token) = match self.msg_to_raw_msg(msg) {
            Err(e) => return self.on_msg_send_finished_err(event_loop, e),
            Ok((raw_msg, token)) => (raw_msg, token)
        };

        let mut sent = false;
        let mut sending = None;
        let msg = Rc::new(raw_msg);

        if let Some(pipe) = self.pipes.get_mut(&token) {
            match pipe.send(msg.clone()) {
                Ok(SendStatus::Completed)  => sent = true,
                Ok(SendStatus::InProgress) => sending = Some(pipe.token()),
                _ => {}
            }
        }

        self.pending_send = Some(msg);
        self.process_send_result(event_loop, sent, sending);
    }

    fn on_send_timeout(&mut self, event_loop: &mut EventLoop) {
        let err = io::Error::new(io::ErrorKind::TimedOut, "send timeout reached");

        self.on_msg_send_finished_err(event_loop, err);
    }

    fn recv(&mut self, event_loop: &mut EventLoop, cancel_timeout: EventLoopAction) {
        self.cancel_recv_timeout = Some(cancel_timeout);

        let mut received = None;
        let mut receiving = None;
        for (_, pipe) in self.pipes.iter_mut() {
            match pipe.recv() {
                Ok(RecvStatus::Completed(msg)) => received = Some((msg, pipe.token())),
                Ok(RecvStatus::InProgress)     => receiving = Some(pipe.token()),
                _ => continue
            }
            break;
        }

        self.pending_recv = true;
        self.process_recv_result(event_loop, received, receiving);
    }

    fn on_recv_timeout(&mut self, event_loop: &mut EventLoop) {
        let err = io::Error::new(io::ErrorKind::TimedOut, "recv timeout reached");

        self.on_msg_recv_finished_err(event_loop, err);
    }

    fn ready(&mut self, event_loop: &mut EventLoop, token: mio::Token, events: mio::EventSet) -> io::Result<()> {
        let mut sent = false;
        let mut sending = None;
        let mut received = None;
        let mut receiving = None;

        if let Some(pipe) = self.pipes.get_mut(&token) {
            let has_pending_send = self.pending_send.is_some();
            let has_pending_recv = self.pending_recv;

            let (s, r) = try!(pipe.ready(event_loop, events));
            sent = s;
            received = r.map(|msg| (msg, pipe.token()));

            if has_pending_send && !sent && pipe.can_resume_send() {
                let msg = self.pending_send.as_ref().unwrap();

                match try!(pipe.send(msg.clone())) {
                    SendStatus::Completed  => sent = true,
                    SendStatus::InProgress => sending = Some(pipe.token()),
                    _ => {}
                }
            }

            if has_pending_recv && received.is_none() && pipe.can_resume_recv() {
                match try!(pipe.recv()) {
                    RecvStatus::Completed(msg) => received = Some((msg, pipe.token())),
                    RecvStatus::InProgress     => receiving = Some(pipe.token()),
                    _ => {}
                }
            }
        }

        self.process_send_result(event_loop, sent, sending);
        self.process_recv_result(event_loop, received, receiving);

        Ok(())
    }
}
<commit_msg>Moves backtrace saving from event notificatio to message conversion<commit_after>// Copyright 2015 Copyright (c) 2015 Benoît Labaere (benoit.labaere@gmail.com)
//
// Licensed under the MIT license LICENSE or <http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according to those terms.

use std::rc::Rc;
use std::sync::mpsc::Sender;
use std::collections::HashMap;
use std::io;
use std::boxed::FnBox;

use mio;

use byteorder::{ BigEndian, WriteBytesExt, ReadBytesExt };

use super::Protocol;
use pipe::*;
use endpoint::*;
use global::*;
use event_loop_msg::SocketEvt;
use EventLoop;
use EventLoopAction;
use Message;

pub struct Rep {
    pipes: HashMap<mio::Token, Pipe>,
    evt_sender: Rc<Sender<SocketEvt>>,
    cancel_send_timeout: Option<EventLoopAction>,
    cancel_recv_timeout: Option<EventLoopAction>,
    pending_send: Option<Rc<Message>>,
    pending_recv: bool,
    backtrace: Vec<u8>,
    ttl: u8
}

impl Rep {
    pub fn new(evt_sender: Rc<Sender<SocketEvt>>) -> Rep {
        Rep {
            pipes: HashMap::new(),
            evt_sender: evt_sender,
            cancel_send_timeout: None,
            cancel_recv_timeout: None,
            pending_send: None,
            pending_recv: false,
            backtrace: Vec::with_capacity(64),
            ttl: 8
        }
    }

    fn on_msg_send_finished(&mut self, event_loop: &mut EventLoop, evt: SocketEvt) {
        let _ = self.evt_sender.send(evt);
        let timeout = self.cancel_send_timeout.take();

        timeout.map(|cancel_timeout| cancel_timeout.call_box((event_loop,)));

        self.pending_send = None;
        self.backtrace.clear();
    }

    fn on_msg_send_finished_ok(&mut self, event_loop: &mut EventLoop) {
        self.on_msg_send_finished(event_loop, SocketEvt::MsgSent);
        for (_, pipe) in self.pipes.iter_mut() {
            pipe.finish_send();
        }
    }

    fn on_msg_send_finished_err(&mut self, event_loop: &mut EventLoop, err: io::Error) {
        self.on_msg_send_finished(event_loop, SocketEvt::MsgNotSent(err));
        for (_, pipe) in self.pipes.iter_mut() {
            pipe.cancel_send();
        }
    }

    fn on_msg_send_started(&mut self, token: mio::Token) {
        self.pending_send = None;
        for (_, pipe) in self.pipes.iter_mut() {
            if pipe.token() == token {
                continue;
            } else {
                pipe.discard_send();
            }
        }
    }

    fn process_send_result(&mut self, event_loop: &mut EventLoop, sent: bool, sending: Option<mio::Token>) {
        if sent {
            self.on_msg_send_finished_ok(event_loop);
        } else if let Some(token) = sending {
            self.on_msg_send_started(token);
        }
    }

    fn save_received_header_to_backtrace(&mut self, msg: &Message) {
        self.backtrace.clear();
        self.backtrace.push_all(msg.get_header());
    }

    fn raw_msg_to_msg(&mut self, pipe_token: mio::Token, raw_msg: Message) -> io::Result<Option<Message>> {
        let (mut header, mut body) = raw_msg.explode();
        let pipe_id = pipe_token.as_usize() as u32;

        header.reserve(4);
        try!(header.write_u32::<BigEndian>(pipe_id));

        let mut hops = 0;
        loop {
            if hops >= self.ttl {
                return Ok(None);
            }

            hops += 1;

            if body.len() < 4 {
                return Ok(None);
            }

            let tail = body.split_off(4);
            header.push_all(&body);

            let position = header.len() - 4;
            if header[position] & 0x80 != 0 {
                let msg = Message::with_header_and_body(header, tail);

                self.save_received_header_to_backtrace(&msg);
                return Ok(Some(msg));
            }
            body = tail;
        }
    }

    fn msg_to_raw_msg(&mut self, msg: Message) -> io::Result<(Message, mio::Token)> {
        let (header, body) = msg.explode();
        let pipe_token = try!(self.restore_pipe_id_from_backtrace());
        let header = try!(self.restore_header_from_backtrace(header));

        Ok((Message::with_header_and_body(header, body), pipe_token))
    }

    fn restore_pipe_id_from_backtrace(&self) -> io::Result<mio::Token> {
        if self.backtrace.len() < 4 {
            return Err(other_io_error("no backtrace from received message"));
        }
        let pipe_id_bytes = vec!(
            self.backtrace[0],
            self.backtrace[1],
            self.backtrace[2],
            self.backtrace[3]
        );
        let mut pipe_id_reader = io::Cursor::new(pipe_id_bytes);
        let pipe_id = try!(pipe_id_reader.read_u32::<BigEndian>());
        let pipe_token = mio::Token(pipe_id as usize);

        Ok(pipe_token)
    }

    fn restore_header_from_backtrace(&self, mut header: Vec<u8>) -> io::Result<Vec<u8>> {
        if self.backtrace.len() < 8 {
            return Err(other_io_error("no header in backtrace from received message"));
        }

        let backtrace = &self.backtrace[4..];

        header.reserve(backtrace.len());
        header.push_all(backtrace);

        Ok(header)
    }

    fn on_msg_recv_finished(&mut self, event_loop: &mut EventLoop, evt: SocketEvt) {
        let _ = self.evt_sender.send(evt);
        let timeout = self.cancel_recv_timeout.take();

        timeout.map(|cancel_timeout| cancel_timeout.call_box((event_loop,)));

        self.pending_recv = false;
    }

    fn on_msg_recv_finished_ok(&mut self, event_loop: &mut EventLoop, msg: Message) {
        self.on_msg_recv_finished(event_loop, SocketEvt::MsgRecv(msg));

        for (_, pipe) in self.pipes.iter_mut() {
            pipe.finish_recv();
        }
    }

    fn on_msg_recv_finished_err(&mut self, event_loop: &mut EventLoop, err: io::Error) {
        self.on_msg_recv_finished(event_loop, SocketEvt::MsgNotRecv(err));

        for (_, pipe) in self.pipes.iter_mut() {
            pipe.cancel_recv();
        }
    }

    fn on_msg_recv_started(&mut self, token: mio::Token) {
        self.pending_recv = false;
        for (_, pipe) in self.pipes.iter_mut() {
            if pipe.token() == token {
                continue;
            } else {
                pipe.discard_recv();
            }
        }
    }

    fn on_raw_msg_recv_from(&mut self, event_loop: &mut EventLoop, raw_msg: Message, token: mio::Token) {
        match self.raw_msg_to_msg(token, raw_msg) {
            Ok(None)      => {}
            Ok(Some(msg)) => self.on_msg_recv_finished_ok(event_loop, msg),
            Err(e)        => self.on_msg_recv_finished_err(event_loop, e)
        }
    }

    fn process_recv_result(
        &mut self,
        event_loop: &mut EventLoop,
        received: Option<(Message, mio::Token)>,
        receiving: Option<mio::Token>) {

        if let Some((raw_msg, from)) = received {
            self.on_raw_msg_recv_from(event_loop, raw_msg, from);
        }
        else if let Some(token) = receiving {
            self.on_msg_recv_started(token);
        }
    }
}

impl Protocol for Rep {
    fn id(&self) -> u16 {
        SocketType::Rep.id()
    }

    fn peer_id(&self) -> u16 {
        SocketType::Req.id()
    }

    fn add_endpoint(&mut self, token: mio::Token, endpoint: Endpoint) {
        self.pipes.insert(token, Pipe::new(token, endpoint));
    }

    fn remove_endpoint(&mut self, token: mio::Token) -> Option<Endpoint> {
        self.pipes.remove(&token).map(|p| p.remove())
    }

    fn send(&mut self, event_loop: &mut EventLoop, msg: Message, cancel_timeout: EventLoopAction) {
        self.cancel_send_timeout = Some(cancel_timeout);

        let (raw_msg, token) = match self.msg_to_raw_msg(msg) {
            Err(e) => return self.on_msg_send_finished_err(event_loop, e),
            Ok((raw_msg, token)) => (raw_msg, token)
        };

        let mut sent = false;
        let mut sending = None;
        let msg = Rc::new(raw_msg);

        if let Some(pipe) = self.pipes.get_mut(&token) {
            match pipe.send(msg.clone()) {
                Ok(SendStatus::Completed)  => sent = true,
                Ok(SendStatus::InProgress) => sending = Some(pipe.token()),
                _ => {}
            }
        }

        self.pending_send = Some(msg);
        self.process_send_result(event_loop, sent, sending);
    }

    fn on_send_timeout(&mut self, event_loop: &mut EventLoop) {
        let err = io::Error::new(io::ErrorKind::TimedOut, "send timeout reached");

        self.on_msg_send_finished_err(event_loop, err);
    }

    fn recv(&mut self, event_loop: &mut EventLoop, cancel_timeout: EventLoopAction) {
        self.cancel_recv_timeout = Some(cancel_timeout);

        let mut received = None;
        let mut receiving = None;
        for (_, pipe) in self.pipes.iter_mut() {
            match pipe.recv() {
                Ok(RecvStatus::Completed(msg)) => received = Some((msg, pipe.token())),
                Ok(RecvStatus::InProgress)     => receiving = Some(pipe.token()),
                _ => continue
            }
            break;
        }

        self.pending_recv = true;
        self.process_recv_result(event_loop, received, receiving);
    }

    fn on_recv_timeout(&mut self, event_loop: &mut EventLoop) {
        let err = io::Error::new(io::ErrorKind::TimedOut, "recv timeout reached");

        self.on_msg_recv_finished_err(event_loop, err);
    }

    fn ready(&mut self, event_loop: &mut EventLoop, token: mio::Token, events: mio::EventSet) -> io::Result<()> {
        let mut sent = false;
        let mut sending = None;
        let mut received = None;
        let mut receiving = None;

        if let Some(pipe) = self.pipes.get_mut(&token) {
            let has_pending_send = self.pending_send.is_some();
            let has_pending_recv = self.pending_recv;

            let (s, r) = try!(pipe.ready(event_loop, events));
            sent = s;
            received = r.map(|msg| (msg, pipe.token()));

            if has_pending_send && !sent && pipe.can_resume_send() {
                let msg = self.pending_send.as_ref().unwrap();

                match try!(pipe.send(msg.clone())) {
                    SendStatus::Completed  => sent = true,
                    SendStatus::InProgress => sending = Some(pipe.token()),
                    _ => {}
                }
            }

            if has_pending_recv && received.is_none() && pipe.can_resume_recv() {
                match try!(pipe.recv()) {
                    RecvStatus::Completed(msg) => received = Some((msg, pipe.token())),
                    RecvStatus::InProgress     => receiving = Some(pipe.token()),
                    _ => {}
                }
            }
        }

        self.process_send_result(event_loop, sent, sending);
        self.process_recv_result(event_loop, received, receiving);

        Ok(())
    }
}
<|endoftext|>


<commit_before>use l1::ast::{Addr, Atom, CompiledFact, CompiledQuery,
              FactInstruction, Heap, HeapCellValue, QueryInstruction,
              Registers};

use std::collections::HashMap;
use std::vec::Vec;

#[derive(Clone, Copy)]
enum MachineMode {
    Read,
    Write
}

pub struct Machine {
    h : usize,
    s : usize,
    p : usize,
    code : CompiledFact,
    code_dir : HashMap<(Atom, usize), usize>,
    fail : bool,
    heap : Heap,
    mode : MachineMode,
    registers : Registers
}

impl Machine {
    pub fn new() -> Machine {
        Machine { h : 0,
                  s : 0,
                  p : 0,
                  code : Vec::new(),
                  code_dir : HashMap::new(),
                  fail : false,
                  heap : Vec::with_capacity(256),
                  mode : MachineMode::Write,
                  registers : vec![HeapCellValue::Ref(0); 32] }
    }

    pub fn add_fact(&mut self, mut fact: CompiledFact, name: Atom, arity: usize)
    {
        let index = self.code.len();

        self.code.append(&mut fact);
        self.code_dir.insert((name, arity), index);
    }

    pub fn failed(&self) -> bool {
        self.fail
    }

    fn lookup(&self, a: Addr) -> &HeapCellValue {
        match a {
            Addr::HeapCell(hc) => &self.heap[hc],
            Addr::RegNum(reg)  => &self.registers[reg]
        }
    }

    fn deref(&self, a: Addr) -> Addr {
        let mut a = a;

        loop {
            if let &HeapCellValue::Ref(value) = self.lookup(a) {
                if let Addr::HeapCell(av) = a {
                    if value != av {
                        a = Addr::HeapCell(value);
                        continue;
                    }
                } else {
                    a = Addr::HeapCell(value);
                    continue;
                }
            }

            return a;
        };
    }

    fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
        match hc {
            &HeapCellValue::Ref(r) => r == index,
            _ => false
        }
    }

    //TODO: try to compress this function.
    fn bind(&mut self, a: Addr, val: usize) {
        let mut a = a;

        loop {
            match a {
                Addr::RegNum(reg) => {
                    if let HeapCellValue::Ref(hc) = self.registers[reg] {
                        a = Addr::HeapCell(hc);
                    } else if Machine::is_unbound(&self.heap[val], val) {
                        self.heap[val] = self.registers[reg].clone();
                        break;
                    } else {
                        self.fail = true;
                        break;
                    }
                },
                Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
                    self.heap[hc] = HeapCellValue::Ref(val);
                    break;
                },
                Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
                    self.heap[val] = HeapCellValue::Ref(hc);
                    break;
                },
                _ => {
                    self.fail = true;
                    break;
                }
            };
        }
    }

    fn unify(&mut self, a1: Addr, a2: Addr) {
        let mut pdl = vec![a1, a2];

        self.fail = false;

        while !(pdl.is_empty() || self.fail) {
            let d1 = self.deref(pdl.pop().unwrap());
            let d2 = self.deref(pdl.pop().unwrap());

            if d1 != d2 {
                match (self.lookup(d1), self.lookup(d2)) {
                    (&HeapCellValue::Ref(hc), _) =>
                        self.bind(d2, hc),
                    (_, &HeapCellValue::Ref(hc)) =>
                        self.bind(d1, hc),
                    (&HeapCellValue::Str(a1), &HeapCellValue::Str(a2)) => {
                        let r1 = &self.heap[a1];
                        let r2 = &self.heap[a2];

                        if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
                            if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
                                if n1 == n2 && *f1 == *f2 {
                                    for i in 1 .. n1 {
                                        pdl.push(Addr::HeapCell(a1 + i));
                                        pdl.push(Addr::HeapCell(a2 + i));
                                    }

                                    continue;
                                }
                            }
                        }

                        self.fail = true;
                    },
                    _ => self.fail = true,
                };
            }
        }
    }

    pub fn execute_fact(&mut self) {
        loop {
            if let &FactInstruction::Proceed = &self.code[self.p] {
                break;
            } else if self.fail {
                break;
            }

            let fact_instr = self.code[self.p].clone();
            self.execute_fact_instr(fact_instr);
        }
    }

    pub fn execute_query(&mut self, query: &CompiledQuery) {
        for instr in query {
            self.execute_query_instr(instr);

            if self.fail {
                break;
            }
        }
    }

    fn execute_query_instr<'a, 'b: 'a>(&'a mut self, instr: &'b QueryInstruction) {
        match instr {
            &QueryInstruction::Call(ref name, arity) => {
                // why is Option<&T> not Deref?!?!?
                let compiled_fact_index =
                    self.code_dir.get(&(name.clone(), arity))
                        .map(|index| *index);

                match compiled_fact_index {
                    Some(compiled_fact_index) => {
                        self.p = compiled_fact_index;
                        self.execute_fact();
                    },
                    None => self.fail = true,
                };
            }
            &QueryInstruction::PutStructure(_, ref name, arity, reg) => {
                self.heap.push(HeapCellValue::Str(self.h + 1));
                self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));

                self.registers[reg] = self.heap[self.h].clone();

                self.h += 2;
            },
            &QueryInstruction::PutValue(arg, norm) =>
                self.registers[arg] = self.registers[norm].clone(),
            &QueryInstruction::PutVariable(arg, norm) => {
                self.heap.push(HeapCellValue::Ref(self.h));

                self.registers[norm] = self.heap[self.h].clone();
                self.registers[arg]  = self.heap[self.h].clone();

                self.h += 1;
            },
            &QueryInstruction::SetVariable(reg) => {
                self.heap.push(HeapCellValue::Ref(self.h));
                self.registers[reg] = self.heap[self.h].clone();

                self.h += 1;
            },
            &QueryInstruction::SetValue(reg) => {
                self.heap.push(self.registers[reg].clone());
                self.h += 1;
            },
        }
    }

    fn execute_fact_instr(&mut self, instr: FactInstruction) {
        match instr {
            FactInstruction::Proceed => return,
            FactInstruction::GetStructure(_, name, arity, reg) => {
                let addr = self.deref(Addr::RegNum(reg));

                match self.lookup(addr) {
                    &HeapCellValue::Str(a) => {
                        let result = &self.heap[a];

                        if let &HeapCellValue::NamedStr(named_arity, ref named_str) = result {
                            if arity == named_arity && *name == *named_str {
                                self.s = a + 1;
                                self.mode = MachineMode::Read;
                            } else {
                                self.fail = true;
                            }
                        }
                    },
                    &HeapCellValue::Ref(r) => {
                        self.heap.push(HeapCellValue::Str(self.h + 1));
                        self.heap.push(HeapCellValue::NamedStr(arity, name));

                        let h = self.h;

                        self.bind(Addr::HeapCell(r), h);

                        self.h += 2;
                        self.mode = MachineMode::Write;
                    },
                    _ => {
                        self.fail = true;
                    }
                };
            },
            FactInstruction::GetVariable(arg, norm) =>
                self.registers[norm] = self.registers[arg].clone(),
            FactInstruction::GetValue(arg, norm) =>
                self.unify(Addr::RegNum(norm), Addr::RegNum(arg)),
            FactInstruction::UnifyVariable(reg) => {
                match self.mode {
                    MachineMode::Read  => self.registers[reg] = self.heap[self.s].clone(),
                    MachineMode::Write => {
                        self.heap.push(HeapCellValue::Ref(self.h));
                        self.registers[reg] = self.heap[self.h].clone();
                        self.h += 1;
                    }
                };

                self.s += 1;
            },
            FactInstruction::UnifyValue(reg) => {
                let s = self.s;

                match self.mode {
                    MachineMode::Read  => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
                    MachineMode::Write => {
                        self.heap.push(self.registers[reg].clone());
                        self.h += 1;
                    }
                };

                self.s += 1;
            }
        }

        self.p += 1;
    }

    pub fn reset_machine_state(&mut self) {
        self.h = 0;
        self.s = 0;
        self.p = 0;

        self.fail = false;
        self.heap = Vec::with_capacity(256);
        self.mode = MachineMode::Write;
        self.registers = vec![HeapCellValue::Ref(0); 32];
    }
}
<commit_msg>add dumb comments<commit_after>use l1::ast::{Addr, Atom, CompiledFact, CompiledQuery,
              FactInstruction, Heap, HeapCellValue, QueryInstruction,
              Registers};

use std::collections::HashMap;
use std::vec::Vec;

#[derive(Clone, Copy)]
enum MachineMode {
    Read,
    Write
}

pub struct Machine {
    h : usize,
    s : usize,
    p : usize,
    code : CompiledFact,
    code_dir : HashMap<(Atom, usize), usize>,
    fail : bool,
    heap : Heap,
    mode : MachineMode,
    registers : Registers
}

impl Machine {
    pub fn new() -> Machine {
        Machine { h : 0,
                  s : 0,
                  p : 0,
                  code : Vec::new(),
                  code_dir : HashMap::new(),
                  fail : false,
                  heap : Vec::with_capacity(256),
                  mode : MachineMode::Write,
                  registers : vec![HeapCellValue::Ref(0); 32] }
    }

    pub fn add_fact(&mut self, mut fact: CompiledFact, name: Atom, arity: usize)
    {
        let index = self.code.len();

        self.code.append(&mut fact);
        self.code_dir.insert((name, arity), index);
    }

    pub fn failed(&self) -> bool {
        self.fail
    }

    fn lookup(&self, a: Addr) -> &HeapCellValue {
        match a {
            Addr::HeapCell(hc) => &self.heap[hc],
            Addr::RegNum(reg)  => &self.registers[reg]
        }
    }

    fn deref(&self, a: Addr) -> Addr {
        let mut a = a;

        loop {
            if let &HeapCellValue::Ref(value) = self.lookup(a) {
                if let Addr::HeapCell(av) = a {
                    if value != av {
                        a = Addr::HeapCell(value);
                        continue;
                    }
                } else {
                    a = Addr::HeapCell(value);
                    continue;
                }
            }

            return a;
        };
    }

    fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
        match hc {
            &HeapCellValue::Ref(r) => r == index,
            _ => false
        }
    }

    //TODO: try to compress this function.
    fn bind(&mut self, a: Addr, val: usize) {
        let mut a = a;

        loop {
            match a {
                Addr::RegNum(reg) => {
                    if let HeapCellValue::Ref(hc) = self.registers[reg] {
                        a = Addr::HeapCell(hc);
                    } else if Machine::is_unbound(&self.heap[val], val) {
                        self.heap[val] = self.registers[reg].clone();
                        break;
                    } else {
                        self.fail = true;
                        break;
                    }
                },
                Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
                    self.heap[hc] = HeapCellValue::Ref(val);
                    break;
                },
                Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
                    self.heap[val] = HeapCellValue::Ref(hc);
                    break;
                },
                _ => {
                    self.fail = true;
                    break;
                }
            };
        }
    }

    fn unify(&mut self, a1: Addr, a2: Addr) {
        let mut pdl = vec![a1, a2];

        self.fail = false;

        while !(pdl.is_empty() || self.fail) {
            let d1 = self.deref(pdl.pop().unwrap());
            let d2 = self.deref(pdl.pop().unwrap());

            if d1 != d2 {
                match (self.lookup(d1), self.lookup(d2)) {
                    (&HeapCellValue::Ref(hc), _) =>
                        self.bind(d2, hc),
                    (_, &HeapCellValue::Ref(hc)) =>
                        self.bind(d1, hc),
                    (&HeapCellValue::Str(a1), &HeapCellValue::Str(a2)) => {
                        let r1 = &self.heap[a1];
                        let r2 = &self.heap[a2];

                        if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
                            if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
                                if n1 == n2 && *f1 == *f2 {
                                    for i in 1 .. n1 {
                                        pdl.push(Addr::HeapCell(a1 + i));
                                        pdl.push(Addr::HeapCell(a2 + i));
                                    }

                                    continue;
                                }
                            }
                        }

                        self.fail = true;
                    },
                    _ => self.fail = true,
                };
            }
        }
    }

    pub fn execute_fact(&mut self) {
        loop {
            if let &FactInstruction::Proceed = &self.code[self.p] {
                break;
            } else if self.fail {
                break;
            }

            let fact_instr = self.code[self.p].clone();
            self.execute_fact_instr(fact_instr);
        }
    }

    pub fn execute_query(&mut self, query: &CompiledQuery) {
        for instr in query {
            self.execute_query_instr(instr);

            if self.fail {
                break;
            }
        }
    }

    fn execute_query_instr<'a, 'b: 'a>(&'a mut self, instr: &'b QueryInstruction) {
        match instr {
            &QueryInstruction::Call(ref name, arity) => {
                // why is Option<&T> not Deref?!?!?
                // is it because if the value is None, there's nothing to
                // dereference?
                let compiled_fact_index =
                    self.code_dir.get(&(name.clone(), arity))
                        .map(|index| *index);

                match compiled_fact_index {
                    Some(compiled_fact_index) => {
                        self.p = compiled_fact_index;
                        self.execute_fact();
                    },
                    None => self.fail = true,
                };
            }
            &QueryInstruction::PutStructure(_, ref name, arity, reg) => {
                self.heap.push(HeapCellValue::Str(self.h + 1));
                self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));

                self.registers[reg] = self.heap[self.h].clone();

                self.h += 2;
            },
            &QueryInstruction::PutValue(arg, norm) =>
                self.registers[arg] = self.registers[norm].clone(),
            &QueryInstruction::PutVariable(arg, norm) => {
                self.heap.push(HeapCellValue::Ref(self.h));

                self.registers[norm] = self.heap[self.h].clone();
                self.registers[arg]  = self.heap[self.h].clone();

                self.h += 1;
            },
            &QueryInstruction::SetVariable(reg) => {
                self.heap.push(HeapCellValue::Ref(self.h));
                self.registers[reg] = self.heap[self.h].clone();

                self.h += 1;
            },
            &QueryInstruction::SetValue(reg) => {
                self.heap.push(self.registers[reg].clone());
                self.h += 1;
            },
        }
    }

    fn execute_fact_instr(&mut self, instr: FactInstruction) {
        match instr {
            FactInstruction::Proceed => return,
            FactInstruction::GetStructure(_, name, arity, reg) => {
                let addr = self.deref(Addr::RegNum(reg));

                match self.lookup(addr) {
                    &HeapCellValue::Str(a) => {
                        let result = &self.heap[a];

                        if let &HeapCellValue::NamedStr(named_arity, ref named_str) = result {
                            if arity == named_arity && *name == *named_str {
                                self.s = a + 1;
                                self.mode = MachineMode::Read;
                            } else {
                                self.fail = true;
                            }
                        }
                    },
                    &HeapCellValue::Ref(r) => {
                        self.heap.push(HeapCellValue::Str(self.h + 1));
                        self.heap.push(HeapCellValue::NamedStr(arity, name));

                        let h = self.h;

                        self.bind(Addr::HeapCell(r), h);

                        self.h += 2;
                        self.mode = MachineMode::Write;
                    },
                    _ => {
                        self.fail = true;
                    }
                };
            },
            FactInstruction::GetVariable(arg, norm) =>
                self.registers[norm] = self.registers[arg].clone(),
            FactInstruction::GetValue(arg, norm) =>
                self.unify(Addr::RegNum(norm), Addr::RegNum(arg)),
            FactInstruction::UnifyVariable(reg) => {
                match self.mode {
                    MachineMode::Read  => self.registers[reg] = self.heap[self.s].clone(),
                    MachineMode::Write => {
                        self.heap.push(HeapCellValue::Ref(self.h));
                        self.registers[reg] = self.heap[self.h].clone();
                        self.h += 1;
                    }
                };

                self.s += 1;
            },
            FactInstruction::UnifyValue(reg) => {
                let s = self.s;

                match self.mode {
                    MachineMode::Read  => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
                    MachineMode::Write => {
                        self.heap.push(self.registers[reg].clone());
                        self.h += 1;
                    }
                };

                self.s += 1;
            }
        }

        self.p += 1;
    }

    pub fn reset_machine_state(&mut self) {
        self.h = 0;
        self.s = 0;
        self.p = 0;

        self.fail = false;
        self.heap = Vec::with_capacity(256);
        self.mode = MachineMode::Write;
        self.registers = vec![HeapCellValue::Ref(0); 32];
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Rendering front-end

use std::mem::size_of;
use device;
use device::BoxBlobCast;
use device::draw::CommandBuffer;
use device::shade::{ProgramInfo, UniformValue, ShaderSource,
    Vertex, Fragment, CreateShaderError};
use device::attrib::{U8, U16, U32};
use batch::Batch;
use mesh;
use shade;
use state;
use target;

/// An error with an invalid texture or uniform block.
//TODO: use slices when Rust allows
#[deriving(Show)]
pub enum ParameterError {
    /// Error from a uniform value
    ErrorParamUniform(String),
    /// Error from a uniform block.
    ErrorParamBlock(String),
    /// Error from a texture.
    ErrorParamTexture(String),
    /// Error from a sampler
    ErrorParamSampler(String),
}

/// An error with a defined Mesh.
#[deriving(Show)]
pub enum MeshError {
    /// A required attribute was missing.
    ErrorAttributeMissing(String),
    /// An attribute's type from the vertex format differed from the type used in the shader.
    ErrorAttributeType,
}

/// An error that can happen when trying to draw.
#[deriving(Show)]
pub enum DrawError {
    /// Error with a program.
    ErrorProgram,
    /// Error with the program shell.
    ErrorParameter(ParameterError),
    /// Error with the mesh.
    ErrorMesh(MeshError),
    /// Error with the mesh slice
    ErrorSlice,
}

/// Program linking error
#[deriving(Clone, PartialEq, Show)]
pub enum ProgramError {
    /// Unable to compile the vertex shader
    ErrorVertex(CreateShaderError),
    /// Unable to compile the fragment shader
    ErrorFragment(CreateShaderError),
    /// Unable to link
    ErrorLink(()),
}

/// Graphics state
#[allow(dead_code)]
// This is going to be used to do minimal state transfers between draw calls. Not yet implemented!
struct State {
    frame: target::Frame,
    draw_state: state::DrawState,
}

/// Backend extension trait for convenience methods
pub trait DeviceHelper {
    /// Create a new renderer
    fn create_renderer(&mut self) -> Renderer;
    /// Create a new mesh from the given vertex data.
    /// Convenience function around `create_buffer` and `Mesh::from`.
    fn create_mesh<T: mesh::VertexFormat + Send>(&mut self, data: Vec<T>) -> mesh::Mesh;
    /// Create a simple program given a vertex shader with a fragment one.
    fn link_program(&mut self, vs_src: ShaderSource, fs_src: ShaderSource)
                    -> Result<device::ProgramHandle, ProgramError>;
}

impl<D: device::Device> DeviceHelper for D {
    fn create_renderer(&mut self) -> Renderer {
        Renderer {
            buf: CommandBuffer::new(),
            common_array_buffer: self.create_array_buffer(),
            common_frame_buffer: self.create_frame_buffer(),
            default_frame_buffer: device::get_main_frame_buffer(),
            //TODO: make sure this is HW default
            state: State {
                frame: target::Frame::new(0,0),
                draw_state: state::DrawState::new(),
            },
        }
    }

    fn create_mesh<T: mesh::VertexFormat + Send>(&mut self, data: Vec<T>) -> mesh::Mesh {
        let nv = data.len();
        debug_assert!(nv < {
            use std::num::Bounded;
            let val: device::VertexCount = Bounded::max_value();
            val as uint
        });
        let buf = self.create_buffer_static(&data);
        mesh::Mesh::from::<T>(buf, nv as device::VertexCount)
    }

    fn link_program(&mut self, vs_src: ShaderSource, fs_src: ShaderSource)
                    -> Result<device::ProgramHandle, ProgramError> {
        let vs = match self.create_shader(Vertex, vs_src) {
            Ok(s) => s,
            Err(e) => return Err(ErrorVertex(e)),
        };
        let fs = match self.create_shader(Fragment, fs_src) {
            Ok(s) => s,
            Err(e) => return Err(ErrorFragment(e)),
        };
        self.create_program([vs, fs]).map_err(|e| ErrorLink(e))
    }
}

/// Renderer front-end
pub struct Renderer {
    buf: device::ActualCommandBuffer,
    common_array_buffer: Result<device::ArrayBufferHandle, ()>,
    common_frame_buffer: device::FrameBufferHandle,
    default_frame_buffer: device::FrameBufferHandle,
    state: State,
}

impl Renderer {
    /// Reset all commands for the command buffer re-usal.
    pub fn reset(&mut self) {
        self.buf.clear();
    }

    /// Get a command buffer to be submitted
    pub fn as_buffer(&self) -> &device::ActualCommandBuffer {
        &self.buf
    }

    /// Clone the renderer shared data but ignore the commands
    pub fn clone_empty(&self) -> Renderer {
        Renderer {
            buf: CommandBuffer::new(),
            common_array_buffer: self.common_array_buffer,
            common_frame_buffer: self.common_frame_buffer,
            default_frame_buffer: self.default_frame_buffer,
            state: State {
                frame: target::Frame::new(0,0),
                draw_state: state::DrawState::new(),
            },
        }
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: device::target::ClearData, frame: &target::Frame) {
        self.bind_frame(frame);
        self.buf.call_clear(data);
    }

    /// Draw a `batch` into the specified `frame`
    pub fn draw<B: Batch>(&mut self, batch: B, frame: &target::Frame) {
        self.bind_frame(frame);
        let (mesh, slice, program, state) = batch.get_data();
        self.bind_program(&batch, program);
        self.bind_state(state);
        self.bind_mesh(mesh, program.get_info()).unwrap();  //TODO: mesh link
        self.draw_slice(slice, None);
    }

    /// Draw a `batch` multiple times using instancing
    pub fn draw_instanced<B: Batch>(&mut self, batch: B,
                          count: device::InstanceCount, frame: &target::Frame) {
        self.bind_frame(frame);
        let (mesh, slice, program, state) = batch.get_data();
        self.bind_program(&batch, program);
        self.bind_state(state);
        self.bind_mesh(mesh, program.get_info()).unwrap();  //TODO: mesh link
        self.draw_slice(slice, Some(count));
    }

    /// Update a buffer with data from a vector.
    pub fn update_buffer_vec<T: Send>(&mut self, buf: device::BufferHandle<T>,
                             data: Vec<T>, offset_elements: uint) {
        let esize = size_of::<T>();
        let offset_bytes = esize * offset_elements;
        debug_assert!(data.len() * esize + offset_bytes <= buf.get_info().size);
        self.buf.update_buffer(
            buf.get_name(),
            ((box data) as Box<device::Blob<T> + Send>).cast(),
            offset_bytes
        );
    }

    /// Update a buffer with data from a single type.
    pub fn update_buffer_struct<U, T: device::Blob<U>+Send>(&mut self,
                                buf: device::BufferHandle<U>, data: T) {
        debug_assert!(size_of::<T>() <= buf.get_info().size);
        self.buf.update_buffer(
            buf.get_name(),
            ((box data) as Box<device::Blob<U> + Send>).cast(),
            0
        );
    }

    /// Update the contents of a texture.
    pub fn update_texture<T: Send>(&mut self, tex: device::TextureHandle,
                                   img: device::tex::ImageInfo, data: Vec<T>) {
        debug_assert!(tex.get_info().contains(&img));
        self.buf.update_texture(
            tex.get_info().kind,
            tex.get_name(),
            img,
            ((box data) as Box<device::Blob<T> + Send>).cast()
        );
    }

    fn bind_target(buf: &mut device::ActualCommandBuffer,
                   to: device::target::Target, plane: target::Plane) {
        match plane {
            target::PlaneEmpty =>
                buf.unbind_target(to),
            target::PlaneSurface(suf) =>
                buf.bind_target_surface(to, suf),
            target::PlaneTexture(tex, level, layer) =>
                buf.bind_target_texture(to, tex, level, layer),
        }
    }

    fn bind_frame(&mut self, frame: &target::Frame) {
        self.buf.set_viewport(device::target::Rect {
            x: 0,
            y: 0,
            w: frame.width,
            h: frame.height,
        });
        if frame.is_default() {
            // binding the default FBO, not touching our common one
            self.buf.bind_frame_buffer(self.default_frame_buffer.get_name());
        } else {
            self.buf.bind_frame_buffer(self.common_frame_buffer.get_name());
            for (i, (cur, new)) in self.state.frame.colors.iter().zip(frame.colors.iter()).enumerate() {
                if *cur != *new {
                    Renderer::bind_target(&mut self.buf, device::target::TargetColor(i as u8), *new);
                }
            }
            if self.state.frame.depth != frame.depth {
                Renderer::bind_target(&mut self.buf, device::target::TargetDepth, frame.depth);
            }
            if self.state.frame.stencil != frame.stencil {
                Renderer::bind_target(&mut self.buf, device::target::TargetStencil, frame.stencil);
            }
            self.state.frame = *frame;
        }
    }

    fn bind_state(&mut self, state: &state::DrawState) {
        self.buf.set_primitive(state.primitive);
        self.buf.set_scissor(state.scissor);
        self.buf.set_depth_stencil(state.depth, state.stencil,
            state.primitive.get_cull_mode());
        self.buf.set_blend(state.blend);
        self.buf.set_color_mask(state.color_mask);
    }

    fn bind_program<B: Batch>(&mut self, batch: &B, program: &device::ProgramHandle) {
        self.buf.bind_program(program.get_name());
        let pinfo = program.get_info();
        let mut uniforms = Vec::from_elem(pinfo.uniforms.len(), None);
        let mut blocks   = Vec::from_elem(pinfo.blocks  .len(), None);
        let mut textures = Vec::from_elem(pinfo.textures.len(), None);
        batch.fill_params(shade::ParamValues {
            uniforms: uniforms.as_mut_slice(),
            blocks: blocks.as_mut_slice(),
            textures: textures.as_mut_slice(),
        });
        self.upload_parameters(program, uniforms, blocks, textures).unwrap();
    }

    fn upload_parameters(&mut self, program: &device::ProgramHandle,
                         uniforms: Vec<Option<UniformValue>>,
                         blocks: Vec<Option<device::RawBufferHandle>>,
                         textures: Vec<Option<shade::TextureParam>>)
                         -> Result<(), ParameterError> {
        // bind uniforms
        for (var, option) in program.get_info().uniforms.iter()
            .zip(uniforms.move_iter()) {
            match option {
                Some(v) => self.buf.bind_uniform(var.location, v),
                None => return Err(ErrorParamUniform(var.name.clone())),
            }
        }
        // bind uniform blocks
        for (i, (var, option)) in program.get_info().blocks.iter()
            .zip(blocks.move_iter()).enumerate() {
            match option {
                Some(buf) => self.buf.bind_uniform_block(
                    program.get_name(),
                    i as device::UniformBufferSlot,
                    i as device::UniformBlockIndex,
                    buf.get_name()
                ),
                None => return Err(ErrorParamBlock(var.name.clone())),
            }
        }
        // bind textures and samplers
        for (i, (var, option)) in program.get_info().textures.iter()
            .zip(textures.move_iter()).enumerate() {
            match option {
                Some((tex, sampler)) => {
                    self.buf.bind_uniform(var.location, device::shade::ValueI32(i as i32));
                    self.buf.bind_texture(i as device::TextureSlot,
                        tex.get_info().kind, tex.get_name(), sampler);
                },
                None => return Err(ErrorParamTexture(var.name.clone())),
            }
        }
        Ok(())
    }

    fn bind_mesh(&mut self, mesh: &mesh::Mesh, info: &ProgramInfo)
                 -> Result<(), MeshError> {
        // It's Ok the array buffer is not supported. If so we just ignore it.
        self.common_array_buffer.map(|ab| self.buf.bind_array_buffer(ab.get_name())).is_ok();
        for sat in info.attributes.iter() {
            match mesh.attributes.iter().find(|a| a.name.as_slice() == sat.name.as_slice()) {
                Some(vat) => match vat.elem_type.is_compatible(sat.base_type) {
                    Ok(_) => {
                        self.buf.bind_attribute(
                            sat.location as device::AttributeSlot,
                            vat.buffer.get_name(), vat.elem_count, vat.elem_type,
                            vat.stride, vat.offset, vat.instance_rate);
                    },
                    Err(_) => return Err(ErrorAttributeType)
                },
                None => return Err(ErrorAttributeMissing(sat.name.clone()))
            }
        }
        Ok(())
    }

    fn draw_slice(&mut self, slice: mesh::Slice,
                  instances: Option<device::InstanceCount>) {
        match slice {
            mesh::VertexSlice(prim_type, start, end) => {
                self.buf.call_draw(prim_type, start, end, instances);
            },
            mesh::IndexSlice8(prim_type, buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(prim_type, U8, start, end, instances);
            },
            mesh::IndexSlice16(prim_type, buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(prim_type, U16, start, end, instances);
            },
            mesh::IndexSlice32(prim_type, buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(prim_type, U32, start, end, instances);
            },
        }
    }
}
<commit_msg>Fixed parameter allocations in the front-end<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Rendering front-end

use std::mem::size_of;
use device;
use device::BoxBlobCast;
use device::draw::CommandBuffer;
use device::shade::{ProgramInfo, UniformValue, ShaderSource,
    Vertex, Fragment, CreateShaderError};
use device::attrib::{U8, U16, U32};
use batch::Batch;
use mesh;
use shade;
use state;
use target;

/// An error with an invalid texture or uniform block.
//TODO: use slices when Rust allows
#[deriving(Show)]
pub enum ParameterError {
    /// Error from a uniform value
    ErrorParamUniform(String),
    /// Error from a uniform block.
    ErrorParamBlock(String),
    /// Error from a texture.
    ErrorParamTexture(String),
    /// Error from a sampler
    ErrorParamSampler(String),
}

/// An error with a defined Mesh.
#[deriving(Show)]
pub enum MeshError {
    /// A required attribute was missing.
    ErrorAttributeMissing(String),
    /// An attribute's type from the vertex format differed from the type used in the shader.
    ErrorAttributeType,
}

/// An error that can happen when trying to draw.
#[deriving(Show)]
pub enum DrawError {
    /// Error with a program.
    ErrorProgram,
    /// Error with the program shell.
    ErrorParameter(ParameterError),
    /// Error with the mesh.
    ErrorMesh(MeshError),
    /// Error with the mesh slice
    ErrorSlice,
}

/// Program linking error
#[deriving(Clone, PartialEq, Show)]
pub enum ProgramError {
    /// Unable to compile the vertex shader
    ErrorVertex(CreateShaderError),
    /// Unable to compile the fragment shader
    ErrorFragment(CreateShaderError),
    /// Unable to link
    ErrorLink(()),
}

/// Graphics state
#[allow(dead_code)]
// This is going to be used to do minimal state transfers between draw calls. Not yet implemented!
struct State {
    frame: target::Frame,
    draw_state: state::DrawState,
}

struct ParamStorage {
    uniforms: Vec<Option<UniformValue>>,
    blocks  : Vec<Option<device::RawBufferHandle>>,
    textures: Vec<Option<shade::TextureParam>>,
}

impl ParamStorage{
    fn new() -> ParamStorage {
        ParamStorage {
            uniforms: Vec::new(),
            blocks: Vec::new(),
            textures: Vec::new(),
        }
    }

    fn resize(&mut self, nu: uint, nb: uint, nt: uint) {
        self.uniforms.truncate(0);
        self.uniforms.grow(nu, &None);
        self.blocks.truncate(0);
        self.blocks.grow(nb, &None);
        self.textures.truncate(0);
        self.textures.grow(nt, &None);
    }

    fn as_mut_slice(&mut self) -> shade::ParamValues {
        shade::ParamValues {
            uniforms: self.uniforms.as_mut_slice(),
            blocks: self.blocks.as_mut_slice(),
            textures: self.textures.as_mut_slice(),
        }
    }
}

/// Renderer front-end
pub struct Renderer {
    buf: device::ActualCommandBuffer,
    common_array_buffer: Result<device::ArrayBufferHandle, ()>,
    common_frame_buffer: device::FrameBufferHandle,
    default_frame_buffer: device::FrameBufferHandle,
    state: State,
    parameters: ParamStorage,
}

impl Renderer {
    /// Reset all commands for the command buffer re-usal.
    pub fn reset(&mut self) {
        self.buf.clear();
    }

    /// Get a command buffer to be submitted
    pub fn as_buffer(&self) -> &device::ActualCommandBuffer {
        &self.buf
    }

    /// Clone the renderer shared data but ignore the commands
    pub fn clone_empty(&self) -> Renderer {
        Renderer {
            buf: CommandBuffer::new(),
            common_array_buffer: self.common_array_buffer,
            common_frame_buffer: self.common_frame_buffer,
            default_frame_buffer: self.default_frame_buffer,
            state: State {
                frame: target::Frame::new(0,0),
                draw_state: state::DrawState::new(),
            },
            parameters: ParamStorage::new(),
        }
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: device::target::ClearData, frame: &target::Frame) {
        self.bind_frame(frame);
        self.buf.call_clear(data);
    }

    /// Draw a `batch` into the specified `frame`
    pub fn draw<B: Batch>(&mut self, batch: B, frame: &target::Frame) {
        self.bind_frame(frame);
        let (mesh, slice, program, state) = batch.get_data();
        self.bind_program(&batch, program);
        self.bind_state(state);
        self.bind_mesh(mesh, program.get_info()).unwrap();  //TODO: mesh link
        self.draw_slice(slice, None);
    }

    /// Draw a `batch` multiple times using instancing
    pub fn draw_instanced<B: Batch>(&mut self, batch: B,
                          count: device::InstanceCount, frame: &target::Frame) {
        self.bind_frame(frame);
        let (mesh, slice, program, state) = batch.get_data();
        self.bind_program(&batch, program);
        self.bind_state(state);
        self.bind_mesh(mesh, program.get_info()).unwrap();  //TODO: mesh link
        self.draw_slice(slice, Some(count));
    }

    /// Update a buffer with data from a vector.
    pub fn update_buffer_vec<T: Send>(&mut self, buf: device::BufferHandle<T>,
                             data: Vec<T>, offset_elements: uint) {
        let esize = size_of::<T>();
        let offset_bytes = esize * offset_elements;
        debug_assert!(data.len() * esize + offset_bytes <= buf.get_info().size);
        self.buf.update_buffer(
            buf.get_name(),
            ((box data) as Box<device::Blob<T> + Send>).cast(),
            offset_bytes
        );
    }

    /// Update a buffer with data from a single type.
    pub fn update_buffer_struct<U, T: device::Blob<U>+Send>(&mut self,
                                buf: device::BufferHandle<U>, data: T) {
        debug_assert!(size_of::<T>() <= buf.get_info().size);
        self.buf.update_buffer(
            buf.get_name(),
            ((box data) as Box<device::Blob<U> + Send>).cast(),
            0
        );
    }

    /// Update the contents of a texture.
    pub fn update_texture<T: Send>(&mut self, tex: device::TextureHandle,
                                   img: device::tex::ImageInfo, data: Vec<T>) {
        debug_assert!(tex.get_info().contains(&img));
        self.buf.update_texture(
            tex.get_info().kind,
            tex.get_name(),
            img,
            ((box data) as Box<device::Blob<T> + Send>).cast()
        );
    }

    fn bind_target(buf: &mut device::ActualCommandBuffer,
                   to: device::target::Target, plane: target::Plane) {
        match plane {
            target::PlaneEmpty =>
                buf.unbind_target(to),
            target::PlaneSurface(suf) =>
                buf.bind_target_surface(to, suf),
            target::PlaneTexture(tex, level, layer) =>
                buf.bind_target_texture(to, tex, level, layer),
        }
    }

    fn bind_frame(&mut self, frame: &target::Frame) {
        self.buf.set_viewport(device::target::Rect {
            x: 0,
            y: 0,
            w: frame.width,
            h: frame.height,
        });
        if frame.is_default() {
            // binding the default FBO, not touching our common one
            self.buf.bind_frame_buffer(self.default_frame_buffer.get_name());
        } else {
            self.buf.bind_frame_buffer(self.common_frame_buffer.get_name());
            for (i, (cur, new)) in self.state.frame.colors.iter().zip(frame.colors.iter()).enumerate() {
                if *cur != *new {
                    Renderer::bind_target(&mut self.buf, device::target::TargetColor(i as u8), *new);
                }
            }
            if self.state.frame.depth != frame.depth {
                Renderer::bind_target(&mut self.buf, device::target::TargetDepth, frame.depth);
            }
            if self.state.frame.stencil != frame.stencil {
                Renderer::bind_target(&mut self.buf, device::target::TargetStencil, frame.stencil);
            }
            self.state.frame = *frame;
        }
    }

    fn bind_state(&mut self, state: &state::DrawState) {
        self.buf.set_primitive(state.primitive);
        self.buf.set_scissor(state.scissor);
        self.buf.set_depth_stencil(state.depth, state.stencil,
            state.primitive.get_cull_mode());
        self.buf.set_blend(state.blend);
        self.buf.set_color_mask(state.color_mask);
    }

    fn bind_program<B: Batch>(&mut self, batch: &B, program: &device::ProgramHandle) {
        self.buf.bind_program(program.get_name());
        let pinfo = program.get_info();
        self.parameters.resize(pinfo.uniforms.len(), pinfo.blocks.len(),
            pinfo.textures.len());
        batch.fill_params(self.parameters.as_mut_slice());
        self.upload_parameters(program).unwrap();
    }

    fn upload_parameters(&mut self, program: &device::ProgramHandle) -> Result<(), ParameterError> {
        // bind uniforms
        for (var, &option) in program.get_info().uniforms.iter()
            .zip(self.parameters.uniforms.iter()) {
            match option {
                Some(v) => self.buf.bind_uniform(var.location, v),
                None => return Err(ErrorParamUniform(var.name.clone())),
            }
        }
        // bind uniform blocks
        for (i, (var, &option)) in program.get_info().blocks.iter()
            .zip(self.parameters.blocks.iter()).enumerate() {
            match option {
                Some(buf) => self.buf.bind_uniform_block(
                    program.get_name(),
                    i as device::UniformBufferSlot,
                    i as device::UniformBlockIndex,
                    buf.get_name()
                ),
                None => return Err(ErrorParamBlock(var.name.clone())),
            }
        }
        // bind textures and samplers
        for (i, (var, &option)) in program.get_info().textures.iter()
            .zip(self.parameters.textures.iter()).enumerate() {
            match option {
                Some((tex, sampler)) => {
                    self.buf.bind_uniform(var.location, device::shade::ValueI32(i as i32));
                    self.buf.bind_texture(i as device::TextureSlot,
                        tex.get_info().kind, tex.get_name(), sampler);
                },
                None => return Err(ErrorParamTexture(var.name.clone())),
            }
        }
        Ok(())
    }

    fn bind_mesh(&mut self, mesh: &mesh::Mesh, info: &ProgramInfo)
                 -> Result<(), MeshError> {
        // It's Ok the array buffer is not supported. If so we just ignore it.
        self.common_array_buffer.map(|ab| self.buf.bind_array_buffer(ab.get_name())).is_ok();
        for sat in info.attributes.iter() {
            match mesh.attributes.iter().find(|a| a.name.as_slice() == sat.name.as_slice()) {
                Some(vat) => match vat.elem_type.is_compatible(sat.base_type) {
                    Ok(_) => {
                        self.buf.bind_attribute(
                            sat.location as device::AttributeSlot,
                            vat.buffer.get_name(), vat.elem_count, vat.elem_type,
                            vat.stride, vat.offset, vat.instance_rate);
                    },
                    Err(_) => return Err(ErrorAttributeType)
                },
                None => return Err(ErrorAttributeMissing(sat.name.clone()))
            }
        }
        Ok(())
    }

    fn draw_slice(&mut self, slice: mesh::Slice,
                  instances: Option<device::InstanceCount>) {
        match slice {
            mesh::VertexSlice(prim_type, start, end) => {
                self.buf.call_draw(prim_type, start, end, instances);
            },
            mesh::IndexSlice8(prim_type, buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(prim_type, U8, start, end, instances);
            },
            mesh::IndexSlice16(prim_type, buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(prim_type, U16, start, end, instances);
            },
            mesh::IndexSlice32(prim_type, buf, start, end) => {
                self.buf.bind_index(buf.get_name());
                self.buf.call_draw_indexed(prim_type, U32, start, end, instances);
            },
        }
    }
}

/// Backend extension trait for convenience methods
pub trait DeviceHelper {
    /// Create a new renderer
    fn create_renderer(&mut self) -> Renderer;
    /// Create a new mesh from the given vertex data.
    /// Convenience function around `create_buffer` and `Mesh::from`.
    fn create_mesh<T: mesh::VertexFormat + Send>(&mut self, data: Vec<T>) -> mesh::Mesh;
    /// Create a simple program given a vertex shader with a fragment one.
    fn link_program(&mut self, vs_src: ShaderSource, fs_src: ShaderSource)
                    -> Result<device::ProgramHandle, ProgramError>;
}

impl<D: device::Device> DeviceHelper for D {
    fn create_renderer(&mut self) -> Renderer {
        Renderer {
            buf: CommandBuffer::new(),
            common_array_buffer: self.create_array_buffer(),
            common_frame_buffer: self.create_frame_buffer(),
            default_frame_buffer: device::get_main_frame_buffer(),
            //TODO: make sure this is HW default
            state: State {
                frame: target::Frame::new(0,0),
                draw_state: state::DrawState::new(),
            },
            parameters: ParamStorage::new(),
        }
    }

    fn create_mesh<T: mesh::VertexFormat + Send>(&mut self, data: Vec<T>) -> mesh::Mesh {
        let nv = data.len();
        debug_assert!(nv < {
            use std::num::Bounded;
            let val: device::VertexCount = Bounded::max_value();
            val as uint
        });
        let buf = self.create_buffer_static(&data);
        mesh::Mesh::from::<T>(buf, nv as device::VertexCount)
    }

    fn link_program(&mut self, vs_src: ShaderSource, fs_src: ShaderSource)
                    -> Result<device::ProgramHandle, ProgramError> {
        let vs = match self.create_shader(Vertex, vs_src) {
            Ok(s) => s,
            Err(e) => return Err(ErrorVertex(e)),
        };
        let fs = match self.create_shader(Fragment, fs_src) {
            Ok(s) => s,
            Err(e) => return Err(ErrorFragment(e)),
        };
        self.create_program([vs, fs]).map_err(|e| ErrorLink(e))
    }
}
<|endoftext|>


<commit_before>use bindings::*;
use compilable::Compilable;
use context::Context;
use function::Function;
use util::NativeRef;
use std::str::raw::from_c_str;
/// An ELF binary reader
native_ref!(ReadElf, _reader, jit_readelf_t)
impl ReadElf {
	/// Open a new ELF binary
	pub fn new(filename:&str) -> ReadElf {
		unsafe {
			let this:ReadElf = NativeRef::from_ptr(RawPtr::null());
			jit_readelf_open(&mut this.as_ptr(), filename.to_c_str().unwrap(), 0);
			this
		}
	}
	#[inline]
	/// Get the name of this ELF binary
	pub fn get_name(&self) -> String {
		unsafe {
			from_c_str(jit_readelf_get_name(self.as_ptr()))
		}
	}
	#[inline]
	pub fn add_to_context(&self, ctx:&Context) {
		unsafe {
			jit_readelf_add_to_context(self.as_ptr(), ctx.as_ptr())
		}
	}
	#[inline]
	/// Get a simple in the ELF binary
	pub unsafe fn get_symbol<T>(&self, symbol:&str) -> *T {
		jit_readelf_get_symbol(self.as_ptr(), symbol.to_c_str().unwrap()) as *T
	}
}
impl Drop for ReadElf {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_readelf_close(self.as_ptr())
		}
	}
}

/// An ELF binary reader
native_ref!(WriteElf, _writer, jit_writeelf_t)
impl WriteElf {
	#[inline]
	/// Create a new ELF binary reader
	pub fn new(lib_name:&str) -> WriteElf {
		unsafe {
			NativeRef::from_ptr(jit_writeelf_create(lib_name.to_c_str().unwrap()))
		}
	}
	#[inline]
	/// Write to the filename given
	pub fn write(&self, filename:&str) -> bool {
		unsafe {
			jit_writeelf_write(self.as_ptr(), filename.to_c_str().unwrap()) != 0
		}
	}
	#[inline]
	/// Add a function to the ELF
	pub fn add_function(&self, func:&Function, name:&str) -> bool {
		unsafe {
			jit_writeelf_add_function(self.as_ptr(), func.as_ptr(), name.to_c_str().unwrap()) != 0
		}
	}
	#[inline]
	/// Add a dependency to the ELF
	pub fn add_needed(&self, lib_name:&str) -> bool {
		unsafe  {
			jit_writeelf_add_needed(self.as_ptr(), lib_name.to_c_str().unwrap()) != 0
		}
	}
}
impl Drop for WriteElf {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_writeelf_destroy(self.as_ptr())
		}
	}
}<commit_msg>Add `ReadElf` and `WriteElf` structs for reading from and writing to an ELF, respectively<commit_after>use bindings::*;
use context::Context;
use function::Function;
use util::NativeRef;
use std::str::raw::from_c_str;
/// An ELF binary reader
native_ref!(ReadElf, _reader, jit_readelf_t)
impl ReadElf {
	/// Open a new ELF binary
	pub fn new(filename:&str) -> ReadElf {
		unsafe {
			let mut this = RawPtr::null();
			let code = jit_readelf_open(&mut this, filename.to_c_str().unwrap(), 0);
			if this.is_null() {
				fail!("'{}' couldn't be opened due to {}", filename, code);
			} else {
				NativeRef::from_ptr(this)
			}
		}
	}
	#[inline]
	/// Get the name of this ELF binary
	pub fn get_name(&self) -> String {
		unsafe {
			from_c_str(jit_readelf_get_name(self.as_ptr()))
		}
	}
	#[inline]
	pub fn add_to_context(&self, ctx:&Context) {
		unsafe {
			jit_readelf_add_to_context(self.as_ptr(), ctx.as_ptr())
		}
	}
	#[inline]
	/// Get a simple in the ELF binary
	pub unsafe fn get_symbol<T>(&self, symbol:&str) -> *T {
		jit_readelf_get_symbol(self.as_ptr(), symbol.to_c_str().unwrap()) as *T
	}
}
impl Drop for ReadElf {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_readelf_close(self.as_ptr())
		}
	}
}

/// An ELF binary reader
native_ref!(WriteElf, _writer, jit_writeelf_t)
impl WriteElf {
	#[inline]
	/// Create a new ELF binary reader
	pub fn new(lib_name:&str) -> WriteElf {
		unsafe {
			NativeRef::from_ptr(jit_writeelf_create(lib_name.to_c_str().unwrap()))
		}
	}
	#[inline]
	/// Write to the filename given (not implemented by LibJIT yet)
	pub fn write(&self, filename:&str) -> bool {
		unsafe {
			jit_writeelf_write(self.as_ptr(), filename.to_c_str().unwrap()) != 0
		}
	}
	#[inline]
	/// Add a function to the ELF
	pub fn add_function(&self, func:&Function, name:&str) -> bool {
		unsafe {
			jit_writeelf_add_function(self.as_ptr(), func.as_ptr(), name.to_c_str().unwrap()) != 0
		}
	}
	#[inline]
	/// Add a dependency to the ELF
	pub fn add_needed(&self, lib_name:&str) -> bool {
		unsafe  {
			jit_writeelf_add_needed(self.as_ptr(), lib_name.to_c_str().unwrap()) != 0
		}
	}
}
impl Drop for WriteElf {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_writeelf_destroy(self.as_ptr())
		}
	}
}
#[test]
fn test_elf() {
	let elf = ReadElf::new("/usr/lib/libjit.so.0");
	assert_eq!(elf.get_name().as_slice(), "libjit.so.0");
}<|endoftext|>