<commit_before>use std::io::Read;
use std::collections::HashMap;
use std::cell::RefCell;

use url;
use reqwest;
use serde_json;

use super::error::{TvdbError, TvdbResult};
use super::api::RequestClient;
use super::api::DefaultHttpClient;

/// Main interface
#[derive(Debug, Clone)]
pub struct Tvdb<'a> {
    /// Your API key from TheTVDB.com
    pub key: String,
    http_client: Option<&'a RequestClient>,
    jwt_token: RefCell<Option<String>>,
    default_client: Rc<RequestClient>,

}

/// https://api.thetvdb.com/swagger#/Authentication
#[derive(Deserialize, Debug)]
struct LoginResponse {
    token: String,
}

/// List of `SeriesSearchData`, returned from a search
#[derive(Deserialize, Debug)]
pub struct SeriesSearchResult {
    data: Vec<SeriesSearchData>,
}

/// Info for a single series, as returned from search query
#[derive(Deserialize, Debug)]
pub struct SeriesSearchData {
    aliases: Option<Vec<String>>,
    banner: Option<String>,
    firstAired: Option<String>,
    id: Option<i64>,
    network: Option<String>,
    overview: Option<String>,
    seriesName: Option<String>,
    status: Option<String>,
}

impl<'a> Tvdb<'a> {
    /// Initalise API with the given API key. A key can be aquired via
    /// the [API Key Registration page](http://thetvdb.com/?tab=apiregister)
    pub fn new<S>(key: S) -> Tvdb<'a>
        where S: Into<String>,
    {
        Tvdb {
            key: key.into(),
            http_client: None,
            jwt_token: RefCell::new(None),
            default_client: Rc::new(DefaultHttpClient {}),
        }
    }

    /// Set the JWT session token
    fn set_token(&self, token: String) {
        let mut j = self.jwt_token.borrow_mut();
        *j = Some(token);
    }
    fn get_token(&self) -> Option<String> {
        let j = self.jwt_token.borrow();
        match *j {
            None => None,
            Some(ref t) => Some(format!("{}", *t)),
        }
    }

    /// Authenticate with TheTVDB, storing the JWT token internally for use by
    /// other methods.
    pub fn login(&self) -> TvdbResult<bool> {
        let mut map = HashMap::new();
        map.insert("apikey", &self.key);

        let c = reqwest::Client::new().unwrap();
        let mut resp = c.post("https://api.thetvdb.com/login")
            .json(&map)
            .send()
            .map_err(|x| {
                TvdbError::CommunicationError { reason: format!("{}", x) }
            })?;
        let mut result = String::new();
        resp.read_to_string(&mut result).map_err(|x| {
            TvdbError::CommunicationError { reason: format!("Error reading response: {}", x) }
        })?;

        let deserialized: serde_json::Value = serde_json::from_str(&result).unwrap();
        let tok: String = deserialized["token"].as_str().unwrap().into();
        self.set_token(tok);

        Ok(true)
    }

    /// Sets a custom client (implementation of `RequestClient`) used to
    /// perform HTTP requests
    pub fn set_http_client(&mut self, client: &'a RequestClient) {
        self.http_client = Some::<&'a RequestClient>(client);
    }

    pub fn search(&self, name: &str) -> TvdbResult<SeriesSearchResult> {
        let mut map = HashMap::new();
        map.insert("name", name);
        //map.insert("imdbId", "json");

        let search_url = "https://api.thetvdb.com/search/series";
        let url: String = url::Url::parse_with_params(search_url, map)
            .unwrap()
            .as_str()
            .into();

        let dc = self.default_client.as_ref();
        let c = self.http_client.unwrap_or(dc);
        // Query URL
        let data = c.get_url(&url, self.get_token())?;
        // Parse result
        let result: SeriesSearchResult = serde_json::from_str(&data).unwrap();

        Ok(result)
    }

    /*
    pub fn search_imdb(&self, imdb_id: &str){
        panic!();
    }

    pub fn search_zap2it(&self, zap2it_id: &str){
        panic!();
    }
*/
}
<commit_msg>Missed "use"<commit_after>use std::io::Read;
use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;

use url;
use reqwest;
use serde_json;

use super::error::{TvdbError, TvdbResult};
use super::api::RequestClient;
use super::api::DefaultHttpClient;

/// Main interface
#[derive(Debug, Clone)]
pub struct Tvdb<'a> {
    /// Your API key from TheTVDB.com
    pub key: String,
    http_client: Option<&'a RequestClient>,
    jwt_token: RefCell<Option<String>>,
    default_client: Rc<RequestClient>,

}

/// https://api.thetvdb.com/swagger#/Authentication
#[derive(Deserialize, Debug)]
struct LoginResponse {
    token: String,
}

/// List of `SeriesSearchData`, returned from a search
#[derive(Deserialize, Debug)]
pub struct SeriesSearchResult {
    data: Vec<SeriesSearchData>,
}

/// Info for a single series, as returned from search query
#[derive(Deserialize, Debug)]
pub struct SeriesSearchData {
    aliases: Option<Vec<String>>,
    banner: Option<String>,
    firstAired: Option<String>,
    id: Option<i64>,
    network: Option<String>,
    overview: Option<String>,
    seriesName: Option<String>,
    status: Option<String>,
}

impl<'a> Tvdb<'a> {
    /// Initalise API with the given API key. A key can be aquired via
    /// the [API Key Registration page](http://thetvdb.com/?tab=apiregister)
    pub fn new<S>(key: S) -> Tvdb<'a>
        where S: Into<String>,
    {
        Tvdb {
            key: key.into(),
            http_client: None,
            jwt_token: RefCell::new(None),
            default_client: Rc::new(DefaultHttpClient {}),
        }
    }

    /// Set the JWT session token
    fn set_token(&self, token: String) {
        let mut j = self.jwt_token.borrow_mut();
        *j = Some(token);
    }
    fn get_token(&self) -> Option<String> {
        let j = self.jwt_token.borrow();
        match *j {
            None => None,
            Some(ref t) => Some(format!("{}", *t)),
        }
    }

    /// Authenticate with TheTVDB, storing the JWT token internally for use by
    /// other methods.
    pub fn login(&self) -> TvdbResult<bool> {
        let mut map = HashMap::new();
        map.insert("apikey", &self.key);

        let c = reqwest::Client::new().unwrap();
        let mut resp = c.post("https://api.thetvdb.com/login")
            .json(&map)
            .send()
            .map_err(|x| {
                TvdbError::CommunicationError { reason: format!("{}", x) }
            })?;
        let mut result = String::new();
        resp.read_to_string(&mut result).map_err(|x| {
            TvdbError::CommunicationError { reason: format!("Error reading response: {}", x) }
        })?;

        let deserialized: serde_json::Value = serde_json::from_str(&result).unwrap();
        let tok: String = deserialized["token"].as_str().unwrap().into();
        self.set_token(tok);

        Ok(true)
    }

    /// Sets a custom client (implementation of `RequestClient`) used to
    /// perform HTTP requests
    pub fn set_http_client(&mut self, client: &'a RequestClient) {
        self.http_client = Some::<&'a RequestClient>(client);
    }

    pub fn search(&self, name: &str) -> TvdbResult<SeriesSearchResult> {
        let mut map = HashMap::new();
        map.insert("name", name);
        //map.insert("imdbId", "json");

        let search_url = "https://api.thetvdb.com/search/series";
        let url: String = url::Url::parse_with_params(search_url, map)
            .unwrap()
            .as_str()
            .into();

        let dc = self.default_client.as_ref();
        let c = self.http_client.unwrap_or(dc);
        // Query URL
        let data = c.get_url(&url, self.get_token())?;
        // Parse result
        let result: SeriesSearchResult = serde_json::from_str(&data).unwrap();

        Ok(result)
    }

    /*
    pub fn search_imdb(&self, imdb_id: &str){
        panic!();
    }

    pub fn search_zap2it(&self, zap2it_id: &str){
        panic!();
    }
*/
}
<|endoftext|>


<commit_before>
use itertools::*;
use byteorder::*;

use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};

use symbol_table::*;

pub type RegisterT = i64;
type Endianness = LittleEndian;

pub fn exec_program(program: Program) -> RegisterT {
    use self::Instruction::*;

    macro_rules! read_u16 {
        ($instr:ident, $ip:ident) => {{
            let val = Endianness::read_u16(&$instr[$ip..$ip + 2]);
            $ip += 2;
            val
        }}
    }

    macro_rules! read_u8 {
        ($instr:ident, $ip:ident) => {{
            let val = $instr[$ip];
            $ip += 1;
            val
        }}
    }

    macro_rules! read_i64 {
        ($instr:ident, $ip:ident) => {{
            let val = Endianness::read_i64(&$instr[$ip..$ip + 8]);
            $ip += 8;
            val
        }}
    }

    let mut ip = 0; // instruction pointer
    let mut data_stack = Vec::with_capacity(128);
    let mut ret_stack = Vec::with_capacity(128);
    let mut var_slots = vec![0; program.num_vars];
    let instructions = program.instructions;

    loop {
        let i = ip;
        ip += 1;
        let instr = as_inst(instructions[i]);
        match instr {
            I64 => {
                let val = read_i64!(instructions, ip);
                data_stack.push(val);
            }
            U16 => {
                let val = read_u16!(instructions, ip);
                data_stack.push(val as RegisterT);
            }
            Load => {
                let var_slot = read_u16!(instructions, ip) as usize;
                data_stack.push(var_slots[var_slot]);
            }
            Store => {
                let var_slot = read_u16!(instructions, ip) as usize;
                var_slots[var_slot] = data_stack.pop().expect("stack underflow: store");
            }
            Add => {
                let num_args = read_u8!(instructions, ip) as usize;
                assert!(data_stack.len() >= num_args, "stack underflow: add");
                let idx = data_stack.len() - num_args;
                let val = data_stack.drain(idx..).fold(0, |acc, e| acc + e);
                data_stack.push(val);
            }
            Pop => {
                data_stack.pop().expect("stack underflow: pop");
            }
            Call => {
                let jmp_addr = data_stack.pop().expect("stack underflow: call") as usize;
                assert!(jmp_addr <= ::std::u16::MAX as usize);
                ret_stack.push(ip);
                ip = jmp_addr;
            }
            Ret => {
                ip = ret_stack.pop().expect("return stack underflow: ret");
            }
            Exit => return data_stack.pop().expect("stack underflow: exit"),
        }
    }
}

fn as_byte(i: Instruction) -> u8 {
    unsafe { ::std::mem::transmute(i) }
}

fn as_inst(b: u8) -> Instruction {
    unsafe { ::std::mem::transmute(b) }
}

pub struct Program {
    instructions: Vec<u8>,
    num_vars: usize,
    debug_info: DebugInfo,
}

pub fn new_program() -> ProgramBuilder {
    ProgramBuilder {
        in_prologue: false,
        fn_cursor: vec![],
        fn_defs: Default::default(),
        constants: Default::default(),
        prologue: vec![],
        instructions: vec![],
        var_defs: Default::default(),
    }
}

// preliminary instructions
// essentially assembler macros
#[derive(Debug)]
enum PIns {
    I64(i64),
    Load(u16),
    Store(u16),
    Add(u8),
    Pop,
    Call,
    Ret,
    Exit,
    // fn_id
    LoadFnAddrPlaceholder(u32),
    // fn_id
    FnHeaderPlaceholder(u32),
    PrologueEnd,
}

macro_rules! current_def {
    ($e:ident) => {
        if $e.in_prologue {
            &mut $e.prologue
        } else {
            match $e.fn_cursor.len() {
            0 => &mut $e.instructions,
                n => $e.fn_defs.get_mut(&$e.fn_cursor[n - 1]).unwrap(),
            }
        }
    }
}

pub struct ProgramBuilder {
    in_prologue: bool,
    // stack of fn_ids
    fn_cursor: Vec<u32>,
    // fn_id -> fn_def
    fn_defs: HashMap<u32, Vec<PIns>>,
    constants: HashMap<u32, i64>,
    prologue: Vec<PIns>,
    instructions: Vec<PIns>,
    // var_ast_id -> var_slot_idx
    var_defs: HashMap<u32, u16>,
}

impl ProgramBuilder {
    pub fn in_prologue(&mut self) {
        self.in_prologue = true;
    }

    pub fn out_prologue(&mut self) {
        self.in_prologue = false;
    }

    pub fn begin_fn_def(&mut self, fn_id: u32) {
        self.fn_defs.insert(fn_id, vec![PIns::FnHeaderPlaceholder(fn_id)]);
        self.fn_cursor.push(fn_id);
    }

    pub fn end_fn_def(&mut self) {
        let fn_id = self.fn_cursor.pop().unwrap();
        self.prologue.push(PIns::LoadFnAddrPlaceholder(fn_id));
    }

    pub fn def_const(&mut self, var_ast_id: u32, val: i64) {
        self.constants.insert(var_ast_id, val);
    }

    pub fn call(&mut self) {
        current_def!(self).push(PIns::Call);
    }

    pub fn ret(&mut self) {
        current_def!(self).push(PIns::Ret);
    }

    pub fn def_var(&mut self, var_ast_id: u32) {
        let new_idx = self.var_defs.len();
        self.var_defs.insert(var_ast_id, new_idx as u16);
    }

    pub fn load_named_constant(&mut self, constant_ast_id: u32) {
        let val = self.constants[&constant_ast_id];
        self.load_i64(val);
    }

    pub fn load_var(&mut self, var_ast_id: u32) {
        let var_slot_idx = self.var_defs[&var_ast_id];
        assert!(self.var_defs.len() >= var_slot_idx as usize + 1);
        current_def!(self).push(PIns::Load(var_slot_idx));
    }

    pub fn store_var(&mut self, var_ast_id: u32) {
        let var_slot_idx = self.var_defs[&var_ast_id];
        assert!(self.var_defs.len() >= var_slot_idx as usize + 1);
        current_def!(self).push(PIns::Store(var_slot_idx));
    }

    pub fn load_i64(&mut self, val: RegisterT) {
        current_def!(self).push(PIns::I64(val));
    }

    pub fn add(&mut self, num_args: u8) {
        current_def!(self).push(PIns::Add(num_args));
    }

    pub fn pop(&mut self) {
        current_def!(self).push(PIns::Pop);
    }

    pub fn exit(&mut self) {
        current_def!(self).push(PIns::Exit);
    }

    pub fn finish(mut self, env: &SymbolTable) -> Program {
        use self::PIns::*;

        let fn_addr_load_placeholder = 255;
        let mut prologue_len = None;
        self.prologue.push(PrologueEnd);

        // fn_id -> call addr
        let mut fn_addrs: HashMap<u32, u16> = HashMap::new();

        // fn_id -> addr to write in fn_load
        let mut callsites_to_link = HashMap::new();
        let mut assembled = vec![];

        let itr = ::std::iter::once((::std::u32::MAX, self.prologue))
                      .chain(::std::iter::once((::std::u32::MAX, self.instructions)))
                      .chain(self.fn_defs.into_iter())
                      .flat_map(|(_, instructions)| instructions.into_iter());

        for pin in itr {
            match pin {
                I64(val) => {
                    assembled.push(as_byte(Instruction::I64));
                    assembled.write_i64::<Endianness>(val).unwrap();
                }
                Load(var_slot_idx) => {
                    assembled.push(as_byte(Instruction::Load));
                    assembled.write_u16::<Endianness>(var_slot_idx).unwrap();
                }
                Store(var_slot_idx) => {
                    assembled.push(as_byte(Instruction::Store));
                    assembled.write_u16::<Endianness>(var_slot_idx).unwrap();
                }
                Add(num_args) => {
                    assembled.push(as_byte(Instruction::Add));
                    assembled.push(num_args);
                }
                Pop => assembled.push(as_byte(Instruction::Pop)),
                Call => assembled.push(as_byte(Instruction::Call)),
                Ret => assembled.push(as_byte(Instruction::Ret)),
                Exit => assembled.push(as_byte(Instruction::Exit)),
                LoadFnAddrPlaceholder(fn_id) => {
                    let current_position = assembled.len();
                    callsites_to_link.insert(fn_id, current_position);
                    assembled.push(fn_addr_load_placeholder);
                    assembled.write_u16::<Endianness>(0).unwrap();
                }
                FnHeaderPlaceholder(fn_id) => {
                    fn_addrs.insert(fn_id, assembled.len() as u16);
                }
                PrologueEnd => {
                    prologue_len = Some(assembled.len() as u16);
                }
            }
        }

        for (fn_id, idx) in callsites_to_link {
            let fn_addr = fn_addrs[&fn_id];
            assembled[idx] = as_byte(Instruction::U16);
            Endianness::write_u16(&mut assembled[idx + 1..idx + 3], fn_addr);
        }

        // debug info

        let var_names = self.var_defs
                            .iter()
                            .map(|(&var_id, &var_addr)| {
                                (var_addr,
                                 env.lookup_id(var_id)
                                    .map_or_else(|| format!("<var {}>", var_id),
                                                 |r| r.ident().into()))
                            })
                            .collect();

        let labels = fn_addrs.iter()
                             .map(|(_, &fn_addr)| (fn_addr, format!("L{}", fn_addr)))
                             .chain(::std::iter::once((prologue_len.unwrap(), format!("main"))))
                             .collect();

        Program {
            instructions: assembled,
            num_vars: self.var_defs.len(),
            debug_info: DebugInfo {
                var_names: var_names,
                labels: labels,
            },
        }
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
enum Instruction {
    I64,
    U16,
    Load,
    Store,
    Add,
    Pop,
    Call,
    Ret,
    Exit,
}

#[derive(Default)]
struct DebugInfo {
    // fn_addr -> name
    labels: HashMap<u16, String>,
    // var_slot_idx -> name
    var_names: HashMap<u16, String>,
}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        use self::Instruction::*;

        fn format_inst(label: Option<&str>,
                       idx: usize,
                       i: Instruction,
                       args: &ToString)
                       -> Option<String> {
            let mnemonic = match i {
                I64 => "i64",
                U16 => "u16",
                Load => "load",
                Store => "stor",
                Call => "call",
                Add => "add",
                Pop => "pop",
                Exit => "exit",
                Ret => "ret",
            };

            let label = match label {
                Some(s) => format!("{}:\n", s),
                None => "".into(),
            };

            Some(format!("{}{:>6}:\t{:>4} {}", label, idx, mnemonic, args.to_string()))
        }

        let lines = self.instructions
                        .iter()
                        .enumerate()
                        .batching(|mut it| {
                            match it.next() {
                                None => None,
                                Some((idx, &b)) => {
                                    let label = match self.debug_info
                                                          .labels
                                                          .get(&(idx as u16)) {
                                        Some(name) => Some(&**name),
                                        _ => None,
                                    };

                                    let inst = as_inst(b);

                                    match inst {
                                        I64 => {
                                            let mut raw = vec![];
                                            for _ in 0..8 {
                                                match it.next() {
                                                    Some((_, &b)) => {
                                                        raw.push(b);
                                                    }
                                                    _ => return None,
                                                }
                                            }
                                            let val = Endianness::read_i64(&*raw);
                                            format_inst(label, idx, inst, &val)
                                        }
                                        U16 => {
                                            let mut raw = vec![];
                                            for _ in 0..2 {
                                                match it.next() {
                                                    Some((_, &b)) => {
                                                        raw.push(b);
                                                    }
                                                    _ => return None,
                                                }
                                            }
                                            let val = Endianness::read_u16(&*raw);
                                            format_inst(label, idx, inst, &val)
                                        }
                                        Load => {
                                            let bytes = [*it.next().unwrap().1,
                                                         *it.next().unwrap().1];
                                            let var_slot_idx = Endianness::read_u16(&bytes[..]);
                                            let name = &self.debug_info.var_names[&var_slot_idx];
                                            format_inst(label, idx, inst, name)
                                        }
                                        Store => {
                                            let bytes = [*it.next().unwrap().1,
                                                         *it.next().unwrap().1];
                                            let var_slot_idx = Endianness::read_u16(&bytes[..]);
                                            let name = &self.debug_info.var_names[&var_slot_idx];
                                            format_inst(label, idx, inst, name)
                                        }
                                        Call => format_inst(label, idx, inst, &""),
                                        Add => format_inst(label, idx, inst, it.next().unwrap().1),
                                        Ret => format_inst(label, idx, inst, &""),
                                        Exit => format_inst(label, idx, inst, &""),
                                        Pop => format_inst(label, idx, inst, &""),
                                    }
                                }
                            }
                        })
                        .join("\n");

        writeln!(f, "\n{}", lines)
    }
}

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

    #[test]
    fn raw_program_addition() {
        // (+ 1 2 3)

        let mut p = new_program();

        p.load_i64(1);
        p.load_i64(2);
        p.load_i64(3);
        p.add(3);
        p.exit();

        let p = p.finish(&SymbolTable::empty());
        println!("{:?}", p);
        assert_eq!(exec_program(p), 6);
    }

    #[test]
    fn var() {
        // (def x 7)
        // (+ x 3)

        let mut p = new_program();

        let x = 0; // 'ast' id, not slot number or value
        p.def_var(x);
        p.load_i64(7);
        p.store_var(x);
        p.load_i64(3);
        p.load_var(x);
        p.add(2);
        p.exit();

        let p = p.finish(&SymbolTable::empty());
        println!("{:?}", p);
        assert_eq!(exec_program(p), 10);
    }

    // TODO: static calls
    // #[test]
    // fn calls() {
    //     // (defn f [x]
    //     //   (+ 2 x))
    //     // (defn g [x]
    //     //   (f x))
    //     // (g (f 4))

    // let mut p = new_program();

    //     p.load_i64(4);
    //     p.call(16);
    //     p.call(28);
    //     p.exit();
    //     p.load_i64(2); // addr 16
    //     p.add(2);
    //     p.ret();
    //     p.call(16); // addr 28
    //     p.ret();

    //     let p = p.finish();
    //     println!("{:?}", p);
    //     assert_eq!(exec_program(p), 8);
    // }
}
<commit_msg>Sketchwork on new vm<commit_after>
use itertools::*;
use byteorder::*;

use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};

use symbol_table::*;

type Endianness = LittleEndian;
type Table<K, V> = HashMap<K, V>;

macro_rules! read_u32 {
    ($instr:ident, $ip:ident) => {{
        let val = Endianness::read_u32(&$instr[$ip..$ip + 4]);
        $ip += 4;
        val
    }}
}

macro_rules! read_u16 {
    ($instr:ident, $ip:ident) => {{
        let val = Endianness::read_u16(&$instr[$ip..$ip + 2]);
        $ip += 2;
        val
    }}
}

macro_rules! read_u8 {
    ($instr:ident, $ip:ident) => {{
        let val = $instr[$ip];
        $ip += 1;
        val
    }}
}

macro_rules! read_i64 {
    ($instr:ident, $ip:ident) => {{
        let val = Endianness::read_i64(&$instr[$ip..$ip + 8]);
        $ip += 8;
        val
    }}
}

macro_rules! peek {
    ($stack:ident) => {
        $stack.last().unwrap()
    }
}

macro_rules! peek_mut {
    ($stack:ident) => {
        $stack.last_mut().unwrap()
    }
}

macro_rules! pop {
    ($stack:ident) => {
        $stack.pop().unwrap()
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
enum Ins {
    LoadConst,
    Load,
    Save,
    Pop,
    Dup,
    Add,
    Call,
    Ret,
    Exit,
}

#[derive(Copy, Clone, Default)]
struct Slot {
    val: u64,
}

impl Slot {
    fn as_i64(&self) -> i64 {
        self.val as i64
    }
}

struct FnPrototype {

}

type FnAddr = u32;

struct FnTable {}

impl FnTable {
    fn new_stack_frame(&self, ret_addr: usize, fn_addr: FnAddr) -> StackFrame {
        //
        unimplemented!()
    }

    // get info via prototype_idx
}

struct StackFrame {
    locals: Vec<Slot>,
    return_addr: u32,
    prototype_idx: u32
}

impl StackFrame {
    fn load_local(&self, idx: u8) -> Slot {
        self.locals[idx as usize]
    }

    fn save_local(&mut self, idx: u8, val: Slot) {
        self.locals[idx as usize] = val;
    }

    fn slots(&self) -> &[Slot] {
        &*self.locals
    }

    fn slots_mut(&mut self) -> &mut [Slot] {
        &mut *self.locals
    }
}

pub fn exec_program(program: Program) -> i64 {
    use self::Ins::*;

    let const_table = program.const_table;
    let fn_table = program.fn_table;
    let program = program.instructions;

    let mut call_stack = vec![fn_table.new_stack_frame(0, 0)]; // correct?
    let mut data_stack = Vec::with_capacity(128);
    let mut ip = 0;

    loop {
        let i = ip;
        ip += 1;

        let inst = program[i].into();

        match inst {
            LoadConst => {
                let const_idx = read_u16!(program, ip);
                let val = const_table[&const_idx];
                data_stack.push(val);
            }
            Load => {
                let idx = read_u8!(program, ip);
                let val = peek!(call_stack).load_local(idx);
                data_stack.push(val);
            }
            Save => {
                let idx = read_u8!(program, ip);
                let val = pop!(data_stack);
                peek_mut!(call_stack).save_local(idx, val);
            }
            Pop => { pop!(data_stack); }
            Dup => {
                let val = pop!(data_stack);
                data_stack.push(val);
                data_stack.push(val);
            }
            Add => {
                let num_args = read_u8!(program, ip) as usize;
                assert!(data_stack.len() >= num_args, "stack underflow: add");
                let idx = data_stack.len() - num_args;
                //let val = data_stack.drain(idx..).fold(0, |acc, e| acc + e);
                //data_stack.push(val);
                unimplemented!();
            }
            Call => {
                let addr = read_u32!(program, ip);
                let new_frame = fn_table.new_stack_frame(ip, addr);
                call_stack.push(new_frame);
                ip = addr as usize;
            }
            Ret => {
                let old_frame = pop!(call_stack);
                ip = old_frame.return_addr as usize;
            }
            Exit => return pop!(data_stack).as_i64(),
        }
    }
}

pub struct Program {
    instructions: Vec<u8>,
    fn_table: FnTable,
    const_table: Table<u16, Slot>,
}

pub fn new_program() -> ProgramBuilder {
    ProgramBuilder {

    }
}

// macro assembler instructions
#[derive(Debug)]
enum MIns {
    Add {
        num_args: usize,
    },
    LoadLocal,
    SaveLocal,
    Call, // TODO: what info?
    Ret,
    Exit,
}

pub struct ProgramBuilder {

}

impl ProgramBuilder {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        use self::Ins::*;

        unimplemented!()
    }
}

impl ::std::convert::From<u8> for Ins {
    fn from(byte: u8) -> Self {
        unsafe { ::std::mem::transmute(byte) }
    }

}

impl ::std::convert::From<Ins> for u8 {
    fn from(ins: Ins) -> Self {
        unsafe { ::std::mem::transmute(ins) }
    }
}

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

}
<|endoftext|>


<commit_before>use std::fmt;
use instructions::Instruction;
const STACK_SIZE: usize = 256;
const REG_SIZE: usize = 16;

#[derive(Debug,PartialEq)]
enum VMErrorKind {
	StackError,
	ZeroDivision,
}
impl fmt::Debug for VM {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "Registers: \n {:?} \nStack Contents:\n {:?}", self.registers, self.stack)
	}
}

pub struct VM {
	stack: Vec<i32>,
	registers: [i32; REG_SIZE],
	ip: usize,
	running: bool,
	debug: bool,
}

impl VM {
	pub fn new() -> VM {
		VM { stack: Vec::with_capacity(STACK_SIZE), registers: [0; REG_SIZE], ip: 0, running: true, debug: true}
	}
	pub fn run(&mut self, program: Vec<Instruction>) {

		while self.running {
			let instruction = &program[self.ip];

			match self.eval(instruction) {
				Ok(_) => {},
				Err(e) => {
					println!("Registers: \n {:?}",self.registers);
					println!("Stack Contents:\n {:?}",self.stack);
					panic!("VMError: {:?} on ip {:?}", e, self.ip + 1);
				}
			}
			self.ip += 1;
		}
	}
	fn eval(&mut self, instruction: &Instruction) -> Result<(), VMErrorKind> {
		match instruction {
			&Instruction::OUT => {
				println!("{:?}", self.stack.last().unwrap() );
				Ok(())
			}
			&Instruction::PSH(value) => {
				self.stack.push(value);
				Ok(())
			}
			&Instruction::POP => {
				match self.stack.pop() {
					Some(val) => Ok(()),
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::ADD => {
				match (self.stack.pop(), self.stack.pop()) {
					(Some(a), Some(b)) => {
						self.stack.push(a + b);
						Ok(())
					},
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::SUB => {
				match (self.stack.pop(), self.stack.pop()) {
					(Some(a), Some(b)) => {
						self.stack.push(a - b);
						Ok(())
					},
					_ => Err(VMErrorKind::StackError)
				}

			}
			&Instruction::MUL => {
				match (self.stack.pop(), self.stack.pop()) {
					(Some(a), Some(b)) => {
						self.stack.push(a * b);
						Ok(())
					},
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::DIV => {

				match (self.stack.pop(), self.stack.pop()) {
					(Some(a), Some(b)) => {
						if b == 0 {
							return Err(VMErrorKind::ZeroDivision)
						} else {
							self.stack.push(a / b);
						}
						Ok(())

					},
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::SET(register, value) => {
				self.registers[register as usize] = value;
				Ok(())
			}
			&Instruction::MOV(register1, register2) => {
				self.registers[register1 as usize] = self.registers[register2 as usize];
				Ok(())
			}
			&Instruction::LDR(register) => {
				self.stack.push(self.registers[register as usize] as i32 );
				Ok(())
			}
			&Instruction::STR(register) => {
				match self.stack.pop() {
					Some(value) => {
						self.registers[register as usize] = value;
						Ok(())
					},
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::JMP => {
				unimplemented!()
				// Ok(())
			}
			&Instruction::JZ => {
				unimplemented!()
				// Ok(())
			}
			&Instruction::JNZ => {
				unimplemented!()
				// Ok(())
			}
			&Instruction::HLT => {
				self.running = false;
				Ok(())
			}
			&Instruction::NOP => {
				Ok(())
			}
		}
	}
}

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

	#[test]
	fn add() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::PSH(10),Instruction::ADD, Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &15);
	}
	#[test]
	fn sub() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::PSH(10),Instruction::SUB, Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &5);
	}
	#[test]
	fn mul() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::PSH(10),Instruction::MUL, Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &50);
	}
	#[test]
	fn div() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::PSH(10),Instruction::DIV, Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &2);
	}

	#[test]
	#[should_panic(expected = "VMError: StackError on ip 2")]
	fn add_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5),Instruction::ADD, Instruction::HLT];
		vm.run(program);
		assert_eq!(vm.stack.last().unwrap(), &3);
	}
	#[test]
	#[should_panic(expected = "VMError: StackError on ip 2")]
	fn sub_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5),Instruction::SUB, Instruction::HLT];
		vm.run(program);
		assert_eq!(vm.stack.last().unwrap(), &3);
	}
	#[test]
	#[should_panic(expected = "VMError: StackError on ip 2")]
	fn mul_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5),Instruction::MUL, Instruction::HLT];
		vm.run(program);
		assert_eq!(vm.stack.last().unwrap(), &3);
	}
	#[test]
	#[should_panic(expected = "VMError: StackError on ip 2")]
	fn div_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5),Instruction::DIV, Instruction::HLT];
		vm.run(program);
		assert_eq!(vm.stack.last().unwrap(), &3);
	}
	#[test]
	#[should_panic(expected = "VMError: ZeroDivision on ip 3")]
	fn zerodivision() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(0),Instruction::PSH(10),Instruction::DIV, Instruction::HLT];
		vm.run(program);
		assert_eq!(vm.stack.last().unwrap(), &0);
	}
}

<commit_msg>register tests<commit_after>use std::fmt;
use instructions::Instruction;
const STACK_SIZE: usize = 256;
const REG_SIZE: usize = 16;

#[derive(Debug,PartialEq)]
enum VMErrorKind {
	StackError,
	ZeroDivision,
}
impl fmt::Debug for VM {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "Registers: \n {:?} \nStack Contents:\n {:?}", self.registers, self.stack)
	}
}

pub struct VM {
	stack: Vec<i32>,
	registers: [i32; REG_SIZE],
	ip: usize,
	running: bool,
	debug: bool,
}

impl VM {
	pub fn new() -> VM {
		VM { stack: Vec::with_capacity(STACK_SIZE), registers: [0; REG_SIZE], ip: 0, running: true, debug: true}
	}
	pub fn run(&mut self, program: Vec<Instruction>) {

		while self.running {
			let instruction = &program[self.ip];

			match self.eval(instruction) {
				Ok(_) => {},
				Err(e) => {
					println!("Registers: \n {:?}",self.registers);
					println!("Stack Contents:\n {:?}",self.stack);
					panic!("VMError: {:?} on ip {:?}", e, self.ip + 1);
				}
			}
			self.ip += 1;
		}
	}
	fn eval(&mut self, instruction: &Instruction) -> Result<(), VMErrorKind> {
		match instruction {
			&Instruction::OUT => {
				println!("{:?}", self.stack.last().unwrap() );
				Ok(())
			}
			&Instruction::PSH(value) => {
				self.stack.push(value);
				Ok(())
			}
			&Instruction::POP => {
				match self.stack.pop() {
					Some(val) => Ok(()),
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::ADD => {
				match (self.stack.pop(), self.stack.pop()) {
					(Some(a), Some(b)) => {
						self.stack.push(a + b);
						Ok(())
					},
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::SUB => {
				match (self.stack.pop(), self.stack.pop()) {
					(Some(a), Some(b)) => {
						self.stack.push(a - b);
						Ok(())
					},
					_ => Err(VMErrorKind::StackError)
				}

			}
			&Instruction::MUL => {
				match (self.stack.pop(), self.stack.pop()) {
					(Some(a), Some(b)) => {
						self.stack.push(a * b);
						Ok(())
					},
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::DIV => {

				match (self.stack.pop(), self.stack.pop()) {
					(Some(a), Some(b)) => {
						if b == 0 {
							return Err(VMErrorKind::ZeroDivision)
						} else {
							self.stack.push(a / b);
						}
						Ok(())

					},
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::SET(register, value) => {
				self.registers[register as usize] = value;
				Ok(())
			}
			&Instruction::MOV(register1, register2) => {
				self.registers[register2 as usize] = self.registers[register1 as usize];
				Ok(())
			}
			&Instruction::LDR(register) => {
				self.stack.push(self.registers[register as usize] as i32 );
				Ok(())
			}
			&Instruction::STR(register) => {
				match self.stack.pop() {
					Some(value) => {
						self.registers[register as usize] = value;
						Ok(())
					},
					_ => Err(VMErrorKind::StackError)
				}
			}
			&Instruction::JMP => {
				unimplemented!()
				// Ok(())
			}
			&Instruction::JZ => {
				unimplemented!()
				// Ok(())
			}
			&Instruction::JNZ => {
				unimplemented!()
				// Ok(())
			}
			&Instruction::HLT => {
				self.running = false;
				Ok(())
			}
			&Instruction::NOP => {
				Ok(())
			}
		}
	}
}

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

	#[test]
	fn add() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::PSH(10),Instruction::ADD, Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &15);
	}
	#[test]
	fn sub() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::PSH(10),Instruction::SUB, Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &5);
	}
	#[test]
	fn mul() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::PSH(10),Instruction::MUL, Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &50);
	}
	#[test]
	fn div() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::PSH(10),Instruction::DIV, Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &2);
	}

	#[test]
	#[should_panic(expected = "VMError: StackError on ip 2")]
	fn add_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5),Instruction::ADD, Instruction::HLT];
		vm.run(program);
	}
	#[test]
	#[should_panic(expected = "VMError: StackError on ip 2")]
	fn sub_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5),Instruction::SUB, Instruction::HLT];
		vm.run(program);
	}
	#[test]
	#[should_panic(expected = "VMError: StackError on ip 2")]
	fn mul_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5),Instruction::MUL, Instruction::HLT];
		vm.run(program);
	}
	#[test]
	#[should_panic(expected = "VMError: StackError on ip 2")]
	fn div_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5),Instruction::DIV, Instruction::HLT];
		vm.run(program);
	}
	#[test]
	#[should_panic(expected = "VMError: ZeroDivision on ip 3")]
	fn zerodivision() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(0),Instruction::PSH(10),Instruction::DIV, Instruction::HLT];
		vm.run(program);
	}
	#[test]
	fn set() {
		let mut vm = VM::new();
		let program = vec![Instruction::SET(1, 15), Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.registers[1], 15);
	}
	#[test]
	fn mov() {
		let mut vm = VM::new();
		let program = vec![Instruction::SET(1, 15), Instruction::MOV(1, 2), Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.registers[2], 15);
	}
	#[test]
	fn ldr() {
		let mut vm = VM::new();
		let program = vec![Instruction::SET(1, 15), Instruction::LDR(1), Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.stack.last().unwrap(), &15);
	}
	#[test]
	fn str() {
		let mut vm = VM::new();
		let program = vec![Instruction::PSH(5), Instruction::STR(1), Instruction::HLT];
		vm.run(program);
		assert_eq!( vm.registers[1], 5);
	}
	#[test]
	#[should_panic(expected = "VMError: StackError on ip 1")]
	fn str_stackerror() {
		let mut vm = VM::new();
		let program = vec![Instruction::STR(1), Instruction::HLT];
		vm.run(program);

	}
}

<|endoftext|>


<commit_before>// Copyright 2015 Big Switch Networks, Inc
//      (Algorithms for uBPF helpers, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust, other helpers)
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use std::u64;

// Helpers associated to kernel helpers
// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.

// bpf_trace_printk()
// No side effect: just print arg3, arg4 and arg5 to standard output.
pub const BPF_TRACE_PRINTF_IDX: u32 = 6;

#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_trace_printf (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
    0
}

// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>

pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    arg1.wrapping_shl(32) |
    arg2.wrapping_shl(24) |
    arg3.wrapping_shl(16) |
    arg4.wrapping_shl(8)  |
    arg5
}

#[allow(unused_variables)]
pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    for i in 0..len {
        unsafe {
            let mut p = (ptr + i) as *mut u8;
            *p ^= 0b101010;
        }
    }
    0
}

// TODO: Try again when asm!() is available in stable Rust.
// #![feature(asm)]
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// #[allow(unused_variables)]
// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
//     unsafe {
//         asm!(
//                 "mov $0xf0, %rax"
//             ::: "mov $0xf1, %rcx"
//             ::: "mov $0xf2, %rdx"
//             ::: "mov $0xf3, %rsi"
//             ::: "mov $0xf4, %rdi"
//             ::: "mov $0xf5, %r8"
//             ::: "mov $0xf6, %r9"
//             ::: "mov $0xf7, %r10"
//             ::: "mov $0xf8, %r11"
//         );
//     }
//     0
// }

#[allow(dead_code)]
#[allow(unused_variables)]
pub fn sqrti (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    // Warning: untested
    (arg1 as f64).sqrt() as u64
}

#[allow(dead_code)]
#[allow(unused_variables)]
pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
    if arg1 == 0 || arg2 == 0 {
        return u64::MAX;
    }
    let mut a = arg1;
    let mut b = arg2;
    unsafe {
        let mut a_val = *(a as *const u8);
        let mut b_val = *(b as *const u8);
        while a_val == b_val && a_val != 0 && b_val != 0 {
            a +=1 ;
            b +=1 ;
            a_val = *(a as *const u8);
            b_val = *(b as *const u8);
        }
        if a_val >= b_val {
            (a_val - b_val) as u64
        } else {
            (b_val - a_val) as u64
        }
    }
}
<commit_msg>src/helpers.rs: add API documentation and doc tests<commit_after>// Copyright 2015 Big Switch Networks, Inc
//      (Algorithms for uBPF helpers, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust, other helpers)
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This module implements some built-in helpers that can be called from within an eBPF program.
//! These helpers may originate from several places:
//!
//! * Some of them mimic the helpers available in the Linux kernel.
//! * Some of them were proposed as example helpers in uBPF and they were adapted here.
//! * Other helpers may be specific to rbpf.
//!
//! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
//! respect this convention.

use std::u64;

// Helpers associated to kernel helpers
// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.

// bpf_trace_printk()

/// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_TRACE_PRINTF_IDX: u32 = 6;

/// Prints its **last three** arguments to standard output. The **first two** arguments are
/// **unused**. Returns 0.
///
/// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
/// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// helpers::bpf_trace_printf(1, 15, 32, 0, 0);
/// ```
///
/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
///
/// The eBPF code produced would be nearly the same as when compiling the following code from C to
/// eBPF with clang:
///
/// ```c
/// #include <linux/bpf.h>
/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
///
/// int main(struct __sk_buff *skb)
/// {
///     char *fmt = "bpf_trace_printk %llx %llx %llx\n";
///     return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
/// }
/// ```
///
/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
/// program is run.
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
    0
}

// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>

/// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
/// each argument must be a `u64`.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
/// assert_eq!(gathered, 0x1122334455);
/// ```
pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    arg1.wrapping_shl(32) |
    arg2.wrapping_shl(24) |
    arg3.wrapping_shl(16) |
    arg4.wrapping_shl(8)  |
    arg5
}

/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
/// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
/// cases. Arguments 3 to 5 are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let val: u64 = 0x112233;
/// let val_ptr = &val as *const u64;
///
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x2a2a2a2a2a3b0819);
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x112233);
/// ```
#[allow(unused_variables)]
pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    for i in 0..len {
        unsafe {
            let mut p = (ptr + i) as *mut u8;
            *p ^= 0b101010;
        }
    }
    0
}

// TODO: Try again when asm!() is available in stable Rust.
// #![feature(asm)]
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// #[allow(unused_variables)]
// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
//     unsafe {
//         asm!(
//                 "mov $0xf0, %rax"
//             ::: "mov $0xf1, %rcx"
//             ::: "mov $0xf2, %rdx"
//             ::: "mov $0xf3, %rsi"
//             ::: "mov $0xf4, %rdi"
//             ::: "mov $0xf5, %r8"
//             ::: "mov $0xf6, %r9"
//             ::: "mov $0xf7, %r10"
//             ::: "mov $0xf8, %r11"
//         );
//     }
//     0
// }

/// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
/// unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let x = helpers::sqrti(9, 0, 0, 0, 0);
/// assert_eq!(x, 3);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    (arg1 as f64).sqrt() as u64
}

/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let foo = "This is a string.".as_ptr() as u64;
/// let bar = "This is another sting.".as_ptr() as u64;
///
/// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
/// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
    if arg1 == 0 || arg2 == 0 {
        return u64::MAX;
    }
    let mut a = arg1;
    let mut b = arg2;
    unsafe {
        let mut a_val = *(a as *const u8);
        let mut b_val = *(b as *const u8);
        while a_val == b_val && a_val != 0 && b_val != 0 {
            a +=1 ;
            b +=1 ;
            a_val = *(a as *const u8);
            b_val = *(b as *const u8);
        }
        if a_val >= b_val {
            (a_val - b_val) as u64
        } else {
            (b_val - a_val) as u64
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use visitor::FmtVisitor;
use lists::{write_list, ListFormatting, SeparatorTactic, ListTactic};

use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::print::pprust;

use {IDEAL_WIDTH, MAX_WIDTH};

// TODO change import lists with one item to a single import
//      remove empty lists (if they're even possible)
// TODO (some day) remove unused imports, expand globs, compress many single imports into a list import

impl<'a> FmtVisitor<'a> {
    // Basically just pretty prints a multi-item import.
    pub fn rewrite_use_list(&mut self,
                            path: &ast::Path,
                            path_list: &[ast::PathListItem],
                            vp_span: Span) -> String {
        // FIXME remove unused imports

        // FIXME check indentation
        let l_loc = self.codemap.lookup_char_pos(vp_span.lo);

        let path_str = pprust::path_to_string(&path);

        // 3 = :: + {
        let indent = l_loc.col.0 + path_str.len() + 3;
        // 2 = } + ;
        let used_width = indent + path_str.len() + 2;
        let budget = if used_width >= IDEAL_WIDTH {
            if used_width < MAX_WIDTH {
                MAX_WIDTH - used_width
            } else {
                // Give up
                return String::new();
            }
        } else {
            IDEAL_WIDTH - used_width
        };
        let fmt = ListFormatting {
            tactic: ListTactic::Mixed,
            separator: ",",
            trailing_separator: SeparatorTactic::Never,
            indent: indent,
            h_width: budget,
            v_width: budget,
        };

        // TODO handle any comments inbetween items.
        // If `self` is in the list, put it first.
        let head = if path_list.iter().any(|vpi|
            if let ast::PathListItem_::PathListMod{ .. } = vpi.node {
                true
            } else {
                false
            }
        ) {
            Some(("self".to_string(), String::new()))
        } else {
            None
        };

        let items: Vec<_> = head.into_iter().chain(path_list.iter().filter_map(|vpi| {
            match vpi.node {
                ast::PathListItem_::PathListIdent{ name, .. } => {
                    Some((token::get_ident(name).to_string(), String::new()))
                }
                // Skip `self`, because we added it above.
                ast::PathListItem_::PathListMod{ .. } => None,
            }
        })).collect();

        format!("use {}::{{{}}};", path_str, write_list(&items, &fmt))
    }
}
<commit_msg>Absolute paths<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use visitor::FmtVisitor;
use lists::{write_list, ListFormatting, SeparatorTactic, ListTactic};

use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::print::pprust;

use {IDEAL_WIDTH, MAX_WIDTH};

// TODO change import lists with one item to a single import
//      remove empty lists (if they're even possible)
// TODO (some day) remove unused imports, expand globs, compress many single imports into a list import

impl<'a> FmtVisitor<'a> {
    // Basically just pretty prints a multi-item import.
    pub fn rewrite_use_list(&mut self,
                            path: &ast::Path,
                            path_list: &[ast::PathListItem],
                            vp_span: Span) -> String {
        // FIXME check indentation
        let l_loc = self.codemap.lookup_char_pos(vp_span.lo);

        let path_str = pprust::path_to_string(&path);

        // 1 = {
        let mut indent = l_loc.col.0 + path_str.len() + 1;
        if path_str.len() > 0 {
            // 2 = ::
            indent += 2;
        }
        // 2 = } + ;
        let used_width = indent + 2;
        let budget = if used_width >= IDEAL_WIDTH {
            if used_width < MAX_WIDTH {
                MAX_WIDTH - used_width
            } else {
                // Give up
                return String::new();
            }
        } else {
            IDEAL_WIDTH - used_width
        };
        let fmt = ListFormatting {
            tactic: ListTactic::Mixed,
            separator: ",",
            trailing_separator: SeparatorTactic::Never,
            indent: indent,
            h_width: budget,
            v_width: budget,
        };

        // TODO handle any comments inbetween items.
        // If `self` is in the list, put it first.
        let head = if path_list.iter().any(|vpi|
            if let ast::PathListItem_::PathListMod{ .. } = vpi.node {
                true
            } else {
                false
            }
        ) {
            Some(("self".to_string(), String::new()))
        } else {
            None
        };

        let items: Vec<_> = head.into_iter().chain(path_list.iter().filter_map(|vpi| {
            match vpi.node {
                ast::PathListItem_::PathListIdent{ name, .. } => {
                    Some((token::get_ident(name).to_string(), String::new()))
                }
                // Skip `self`, because we added it above.
                ast::PathListItem_::PathListMod{ .. } => None,
            }
        })).collect();

        if path_str.len() == 0 {
            format!("use {{{}}};", write_list(&items, &fmt))
        } else {
            format!("use {}::{{{}}};", path_str, write_list(&items, &fmt))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::sync::Arc;

use buffer::TypedBuffer;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor::DescriptorWrite;
use image::ImageView;
use sampler::Sampler;

/// Call this macro with the layout of a pipeline to generate some helper structs that wrap around
/// vulkano's unsafe APIs.
// TODO: more docs
#[macro_export]
macro_rules! pipeline_layout {
    ($($name:ident: { $($field:ident: $ty:ty),* }),*) => {
        use std::sync::Arc;
        use std::vec::IntoIter as VecIntoIter;
        use $crate::OomError;
        use $crate::device::Device;
        use $crate::descriptor::descriptor::DescriptorDesc;
        use $crate::descriptor::pipeline_layout::PipelineLayout;
        use $crate::descriptor::pipeline_layout::PipelineLayoutDesc;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayout;

        pub struct CustomPipeline {
            inner: UnsafePipelineLayout
        }

        impl CustomPipeline {
            #[allow(unsafe_code)]
            pub fn new(device: &Arc<Device>) -> Result<Arc<CustomPipeline>, OomError> {
                let layouts = vec![
                    $(
                        try!($name::build_set_layout(device))
                    ),*
                ];

                let inner = unsafe {
                    try!(UnsafePipelineLayout::new(device, layouts.iter()))
                };

                Ok(Arc::new(CustomPipeline {
                    inner: inner
                }))
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayout for CustomPipeline {
            #[inline]
            fn inner_pipeline_layout(&self) -> &UnsafePipelineLayout {
                &self.inner
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayoutDesc for CustomPipeline {
            type SetsIter = VecIntoIter<Self::DescIter>;
            type DescIter = VecIntoIter<DescriptorDesc>;

            fn descriptors_desc(&self) -> Self::SetsIter {
                // FIXME:
                vec![].into_iter()
            }
        }

        /* TODO: uncomment when specialization lands
        #[allow(unsafe_code)]
        unsafe impl<'a> PipelineLayoutSetsCompatible<($(&'a Arc<$name::Set>),*)> for CustomPipeline {
            #[inline]
            default fn is_compatible(&self, _: &($(&'a Arc<$name::Set>),*)) -> bool {
                true
            }
        }*/

        pipeline_layout!{__inner__ (0) $($name: {$($field: $ty),*}),*}
    };

    (__inner__ ($num:expr) $name:ident: { $($field:ident: $ty:ty),* } $($rest:tt)*) => {
        pub mod $name {
            #![allow(unused_imports)]

            use std::sync::Arc;
            use std::vec::IntoIter as VecIntoIter;
            use super::CustomPipeline;
            use $crate::OomError;
            use $crate::device::Device;
            use $crate::descriptor::descriptor::DescriptorDesc;
            use $crate::descriptor::descriptor::DescriptorWrite;
            use $crate::descriptor::descriptor::ShaderStages;
            use $crate::descriptor::descriptor_set::DescriptorPool;
            use $crate::descriptor::descriptor_set::DescriptorSet;
            use $crate::descriptor::descriptor_set::DescriptorSetDesc;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSet;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
            use $crate::descriptor::pipeline_layout::PipelineLayout;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::CombinedImageSampler;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::DescriptorMarker;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::ValidParameter;

            // This constant is part of the API, but Rust sees it as dead code.
            #[allow(dead_code)]
            pub const SET_NUM: u32 = $num;

            #[allow(non_camel_case_types)]
            pub struct Descriptors<$($field),*> {
                $(
                    pub $field: $field
                ),*
            }

            #[allow(non_camel_case_types)]
            #[allow(unused_assignments)]
            impl<$($field: ValidParameter<$ty>),*> Descriptors<$($field),*> {
                pub fn writes(&self) -> Vec<DescriptorWrite> {
                    let mut writes = Vec::new();
                    let mut binding = 0;
                    $(
                        writes.push(self.$field.write(binding));
                        binding += 1;
                    )*
                    writes
                }
            }

            pub struct Set {
                inner: UnsafeDescriptorSet
            }

            impl Set {
                #[inline]
                #[allow(non_camel_case_types)]
                pub fn new<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field)*>)
                           -> Result<Arc<Set>, OomError>
                {
                    #![allow(unsafe_code)]
                    unsafe {
                        let layout = layout.inner_pipeline_layout().descriptor_set_layout($num).unwrap();
                        let mut set = try!(UnsafeDescriptorSet::uninitialized(pool, layout));
                        set.write(descriptors.writes());
                        Ok(Arc::new(Set { inner: set }))
                    }
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSet for Set {
                #[inline]
                fn inner_descriptor_set(&self) -> &UnsafeDescriptorSet {
                    &self.inner
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSetDesc for Set {
                type Iter = VecIntoIter<DescriptorDesc>;

                #[inline]
                fn desc(&self) -> Self::Iter {
                    // FIXME:
                    vec![].into_iter()
                }
            }

            #[allow(unused_assignments)]
            pub fn build_set_layout(device: &Arc<Device>)
                                    -> Result<Arc<UnsafeDescriptorSetLayout>, OomError>
            {
                let mut descriptors = Vec::new();
                let mut binding = 0;

                $(
                    descriptors.push(DescriptorDesc {
                        binding: binding,
                        ty: <$ty as DescriptorMarker>::descriptor_type(),
                        array_count: 1,                     // TODO:
                        stages: ShaderStages::all(),        // TODO:
                    });

                    binding += 1;
                )*

                UnsafeDescriptorSetLayout::new(device, descriptors.into_iter())
            }
        }

        pipeline_layout!{__inner__ ($num+1) $($rest)*}
    };

    (__inner__ ($num:expr)) => {};
}

pub unsafe trait ValidParameter<Target> {
    fn write(&self, binding: u32) -> DescriptorWrite;
}

pub unsafe trait DescriptorMarker {
    fn descriptor_type() -> DescriptorType;
}

pub struct UniformBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for UniformBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::UniformBuffer
    }
}

unsafe impl<'a, B, T: ?Sized + 'static> ValidParameter<UniformBuffer<T>> for &'a Arc<B>
    where B: TypedBuffer<Content = T>
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::uniform_buffer(binding, *self)
    }
}

pub struct CombinedImageSampler;
unsafe impl DescriptorMarker for CombinedImageSampler {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::CombinedImageSampler
    }
}

unsafe impl<'a, I> ValidParameter<CombinedImageSampler> for (&'a Arc<Sampler>, &'a Arc<I>)
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::combined_image_sampler(binding, self.0, self.1)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn no_warning() {
        #![deny(warnings)]
        mod layout {
            pipeline_layout! {
                set0: {
                    field1: UniformBuffer<[u8]>
                }
            }
        }
    }
}
<commit_msg>Fix pipeline_layout! macro with more than one field and one set<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::sync::Arc;

use buffer::TypedBuffer;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor::DescriptorWrite;
use image::ImageView;
use sampler::Sampler;

/// Call this macro with the layout of a pipeline to generate some helper structs that wrap around
/// vulkano's unsafe APIs.
// TODO: more docs
#[macro_export]
macro_rules! pipeline_layout {
    ($($name:ident: { $($field:ident: $ty:ty),* }),*) => {
        use std::sync::Arc;
        use std::vec::IntoIter as VecIntoIter;
        use $crate::OomError;
        use $crate::device::Device;
        use $crate::descriptor::descriptor::DescriptorDesc;
        use $crate::descriptor::pipeline_layout::PipelineLayout;
        use $crate::descriptor::pipeline_layout::PipelineLayoutDesc;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayout;

        pub struct CustomPipeline {
            inner: UnsafePipelineLayout
        }

        impl CustomPipeline {
            #[allow(unsafe_code)]
            pub fn new(device: &Arc<Device>) -> Result<Arc<CustomPipeline>, OomError> {
                let layouts = vec![
                    $(
                        try!($name::build_set_layout(device))
                    ),*
                ];

                let inner = unsafe {
                    try!(UnsafePipelineLayout::new(device, layouts.iter()))
                };

                Ok(Arc::new(CustomPipeline {
                    inner: inner
                }))
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayout for CustomPipeline {
            #[inline]
            fn inner_pipeline_layout(&self) -> &UnsafePipelineLayout {
                &self.inner
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayoutDesc for CustomPipeline {
            type SetsIter = VecIntoIter<Self::DescIter>;
            type DescIter = VecIntoIter<DescriptorDesc>;

            fn descriptors_desc(&self) -> Self::SetsIter {
                // FIXME:
                vec![].into_iter()
            }
        }

        /* TODO: uncomment when specialization lands
        #[allow(unsafe_code)]
        unsafe impl<'a> PipelineLayoutSetsCompatible<($(&'a Arc<$name::Set>),*)> for CustomPipeline {
            #[inline]
            default fn is_compatible(&self, _: &($(&'a Arc<$name::Set>),*)) -> bool {
                true
            }
        }*/

        pipeline_layout!{__inner__ (0) $($name: {$($field: $ty),*})*}
    };

    (__inner__ ($num:expr) $name:ident: { $($field:ident: $ty:ty),* } $($rest:tt)*) => {
        pub mod $name {
            #![allow(unused_imports)]

            use std::sync::Arc;
            use std::vec::IntoIter as VecIntoIter;
            use super::CustomPipeline;
            use $crate::OomError;
            use $crate::device::Device;
            use $crate::descriptor::descriptor::DescriptorDesc;
            use $crate::descriptor::descriptor::DescriptorWrite;
            use $crate::descriptor::descriptor::ShaderStages;
            use $crate::descriptor::descriptor_set::DescriptorPool;
            use $crate::descriptor::descriptor_set::DescriptorSet;
            use $crate::descriptor::descriptor_set::DescriptorSetDesc;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSet;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
            use $crate::descriptor::pipeline_layout::PipelineLayout;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::CombinedImageSampler;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::DescriptorMarker;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::ValidParameter;

            // This constant is part of the API, but Rust sees it as dead code.
            #[allow(dead_code)]
            pub const SET_NUM: u32 = $num;

            #[allow(non_camel_case_types)]
            pub struct Descriptors<$($field),*> {
                $(
                    pub $field: $field
                ),*
            }

            #[allow(non_camel_case_types)]
            #[allow(unused_assignments)]
            impl<$($field: ValidParameter<$ty>),*> Descriptors<$($field),*> {
                pub fn writes(&self) -> Vec<DescriptorWrite> {
                    let mut writes = Vec::new();
                    let mut binding = 0;
                    $(
                        writes.push(self.$field.write(binding));
                        binding += 1;
                    )*
                    writes
                }
            }

            pub struct Set {
                inner: UnsafeDescriptorSet
            }

            impl Set {
                #[inline]
                #[allow(non_camel_case_types)]
                pub fn new<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field),*>)
                           -> Result<Arc<Set>, OomError>
                {
                    #![allow(unsafe_code)]
                    unsafe {
                        let layout = layout.inner_pipeline_layout().descriptor_set_layout($num).unwrap();
                        let mut set = try!(UnsafeDescriptorSet::uninitialized(pool, layout));
                        set.write(descriptors.writes());
                        Ok(Arc::new(Set { inner: set }))
                    }
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSet for Set {
                #[inline]
                fn inner_descriptor_set(&self) -> &UnsafeDescriptorSet {
                    &self.inner
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSetDesc for Set {
                type Iter = VecIntoIter<DescriptorDesc>;

                #[inline]
                fn desc(&self) -> Self::Iter {
                    // FIXME:
                    vec![].into_iter()
                }
            }

            #[allow(unused_assignments)]
            pub fn build_set_layout(device: &Arc<Device>)
                                    -> Result<Arc<UnsafeDescriptorSetLayout>, OomError>
            {
                let mut descriptors = Vec::new();
                let mut binding = 0;

                $(
                    descriptors.push(DescriptorDesc {
                        binding: binding,
                        ty: <$ty as DescriptorMarker>::descriptor_type(),
                        array_count: 1,                     // TODO:
                        stages: ShaderStages::all(),        // TODO:
                    });

                    binding += 1;
                )*

                UnsafeDescriptorSetLayout::new(device, descriptors.into_iter())
            }
        }

        pipeline_layout!{__inner__ ($num+1) $($rest)*}
    };

    (__inner__ ($num:expr)) => {};
}

pub unsafe trait ValidParameter<Target> {
    fn write(&self, binding: u32) -> DescriptorWrite;
}

pub unsafe trait DescriptorMarker {
    fn descriptor_type() -> DescriptorType;
}

pub struct UniformBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for UniformBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::UniformBuffer
    }
}

unsafe impl<'a, B, T: ?Sized + 'static> ValidParameter<UniformBuffer<T>> for &'a Arc<B>
    where B: TypedBuffer<Content = T>
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::uniform_buffer(binding, *self)
    }
}

pub struct CombinedImageSampler;
unsafe impl DescriptorMarker for CombinedImageSampler {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::CombinedImageSampler
    }
}

unsafe impl<'a, I> ValidParameter<CombinedImageSampler> for (&'a Arc<Sampler>, &'a Arc<I>)
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::combined_image_sampler(binding, self.0, self.1)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn no_warning() {
        #![deny(warnings)]
        mod layout {
            pipeline_layout! {
                set0: {
                    field1: UniformBuffer<[u8]>,
                    field2: UniformBuffer<[u8]>
                },
                set1: {
                    field1: UniformBuffer<[u8]>,
                    field2: UniformBuffer<[u8]>
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use common::{Result, Id, Op2, Const};
use explicit;
use implicit;
use env;
use hindley_milner;

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Imm {
    Bool(bool),
    Int(i64),
    Var(Id),
    //    Fun(Id, Box<Expr>),
    //    Fix(Id, Box<Expr>),
    //    Star,
    //    V,
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Op {
    Op2(Op2, Box<Imm>, Box<Imm>),
    //    MkArray(Box<Imm>, Box<Imm>),
    //    GetArray(Box<Imm>, Box<Imm>),
    //    SetArray(Box<Imm>, Box<Imm>, Box<Imm>),
    Imm(Imm),
}
//    WellFormed(Imm), // Var-only

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Expr {
    //    If(Box<Imm>, Box<Imm>, Box<Imm>),
    //    App(Box<Imm>, Box<Imm>),
    Let(Id, Box<Expr>, Box<Expr>),
    Op(Op),
}

#[derive(PartialEq, Eq, Clone, Debug)]
struct ConvEnv {
    //env: HashMap<Id, explicit::Type>,
    next_id: i32,
}

impl ConvEnv {
    fn new() -> ConvEnv {
        ConvEnv {
            //env: HashMap::new(),
            next_id: 0,
        }
    }

    fn tmp(&self) -> (ConvEnv, Id) {
        let id = self.next_id;
        let c = ConvEnv{
            //env: self.env.clone(),
            next_id: self.next_id+1,
        };

        (c, format!("!tmp!{}", id))
    }
}

fn op(cenv: ConvEnv, e: &explicit::Expr) -> (ConvEnv, Op) {
    use typed::Expr as E;
    match *e {
        E::Const(Const::Bool(c)) => (cenv, Op::Imm(Imm::Bool(c))),
        E::Const(Const::Int(c)) => (cenv, Op::Imm(Imm::Int(c))),
        _ => {
            panic!("TODO: implement term for {:?}", e);
        }
    }
}

fn identity(cenv: ConvEnv, e: Expr) -> (ConvEnv, Expr) {
    (cenv, e)
}

fn is_imm(e: &Expr) -> bool {
    if let &Expr::Op(Op::Imm(_)) = e {
        true
    } else {
        false
    }
}

// 1:1 translation -- can't fail
fn expr(cenv: ConvEnv, e: &explicit::Expr, k: &Fn(ConvEnv, Expr) -> (ConvEnv, Expr)) -> (ConvEnv, Expr) {

    use self::Imm as I;
    use typed::Expr as E;
    use self::Op::*;
    use self::Expr::*;

    match *e {
        E::Const(_) => {
            let (cenv, eop) = op(cenv, e);
            k(cenv, Op(eop))
        }
        E::Op2(op, ref l, ref r) => {
            expr(cenv, l, &|cenv: ConvEnv, ll: Expr| -> (ConvEnv, Expr) {
                expr(cenv, r, &|cenv: ConvEnv, rr: Expr| -> (ConvEnv, Expr) {
                    // allocate vars
                    let (cenv, l_tmp) = cenv.tmp();
                    let (cenv, r_tmp) = cenv.tmp();

                    let (l_ref, l_bound) = (I::Var(l_tmp.clone()), true);
                    let (r_ref, r_bound) = (I::Var(r_tmp.clone()), true);

                    // value to pass to the continuation
                    let val = Op(Op2(op, box l_ref, box r_ref));

                    // our inner expression is whatever the
                    // continuation says it is.
                    let (cenv, mut result) = k(cenv, val);

                    if r_bound {
                        result = Let(r_tmp.clone(), box rr, box result);
                    }
                    if l_bound {
                        result = Let(l_tmp.clone(), box ll.clone(), box result);
                    }

                    (cenv, result)
                })
            })
        }
        _ => {
            panic!("TODO: implement expr for {:?}", e);
        }
    }
    // E::Op2(op, ref e1, ref e2) => {
    //     let (n, e1, _) = convert(n, env, renamed, e1);
    //     let (n, e2, _) = convert(n, env, renamed, e2);
    //     (n, I::Op2(op, box e1, box e2), explicit::opty(op))
    // }
    // E::If(ref e1, ref e2, ref e3) => {
    //     let (n, e1, _) = convert(n, env, renamed, e1);
    //     let (n, e2, t) = convert(n, env, renamed, e2);
    //     let (n, e3, _) = convert(n, env, renamed, e3);
    //     (n, I::If(box e1, box e2, box e3), t)
    // }
    // E::Var(ref x) => {
    //     let αx = renamed.get(x).unwrap();
    //     (n, I::Var(αx.clone()), env.get(αx).unwrap().clone())
    // }
    // E::Let(ref id, ref e1, ref e2) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     let (n, e1, t1) = convert(n, env, &renamed, e1);

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1);

    //     let (n, e2, t2) = convert(n, env, &renamed, e2);
    //     (n, I::Let(αid, box e1, box e2), t2)
    // }
    // E::Fun(ref id, ref t1, ref e) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1.clone());

    //     let (n, e, t2) = convert(n, env, &renamed, e);

    //     (n, I::Fun(αid, box e), Type::TFun(box t1.clone(), box t2))
    // }
    // E::Fix(ref id, ref t1, ref e) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1.clone());

    //     let (n, e, t2) = convert(n, env, &renamed, e);

    //     (n, I::Fix(αid, box e), t2)
    // }
    // E::App(ref e1, ref e2) => {
    //     let (n, e1, t1) = convert(n, env, renamed, e1);
    //     let (n, e2, _) = convert(n, env, renamed, e2);
    //     let t = match t1 {
    //         Type::TFun(_, t2) => *t2,
    //         _ => panic!("expected TFun, not {:?}", t1),
    //     };
    //     (n, I::App(box e1, box e2), t)
    // }
    // E::MkArray(ref sz, ref val) => {
    //     let (n, sz, _) = convert(n, env, renamed, sz);
    //     let (n, val, _) = convert(n, env, renamed, val);
    //     (n, I::MkArray(box sz, box val), Type::TIntArray)
    // }
    // E::GetArray(ref id, ref idx) => {
    //     let (n, id, _) = convert(n, env, renamed, id);
    //     let (n, idx, _) = convert(n, env, renamed, idx);
    //     (n, I::GetArray(box id, box idx), Type::TInt)
    // }
    // E::SetArray(ref id, ref idx, ref v) => {
    //     let (n, id, _) = convert(n, env, renamed, id);
    //     let (n, idx, _) = convert(n, env, renamed, idx);
    //     let (n, v, _) = convert(n, env, renamed, v);
    //     (n, I::SetArray(box id, box idx, box v), Type::TIntArray)
    // }
}

pub fn anf(implicit_expr: &implicit::Expr) -> Result<(Expr, HashMap<Id, explicit::Type>)> {

    let explicit_expr = hindley_milner::infer(implicit_expr)?;
    // alpha-renaming
    let (alpha_expr, env) = env::extract(&explicit_expr);

    // println!("α-implicit: {:?}\n", α_expr);
    // println!("Γ         : {:?}\n", env);

    let cenv = ConvEnv::new();
    let (_, expr) = expr(cenv, &alpha_expr, &identity);

    Ok((expr, env))
    // step 1 -- arithmatic + let bindings
    // step 2 -- conds + boolean vals
    // step 3 -- arrays
    // step 4 -- closures

    // (define (Value? M)
    //   (match M
    //     [`(quote ,_)         #t]
    //     [(? number?)         #t]
    //     [(? boolean?)        #t]
    //     [(? string?)         #t]
    //     [(? char?)           #t]
    //     [(? symbol?)         #t]
    //     [(or '+ '- '* '/ '=) #t]
    //     [else                #f]))

    // (define (normalize-term M) (normalize M (λ (x) x)))

    // (define (normalize M k)
    //   (match M
    //     [`(λ ,params ,body)
    //       (k `(λ ,params ,(normalize-term body)))]

    //     [`(let ([,x ,M1]) ,M2)
    //       (normalize M1 (λ (N1)
    //        `(let ([,x ,N1])
    //          ,(normalize M2 k))))]

    //     [`(if ,M1 ,M2 ,M3)
    //       (normalize-name M1 (λ (t)
    //        (k `(if ,t ,(normalize-term M2)
    //                   ,(normalize-term M3)))))]

    //     [`(,Fn . ,M*)
    //       (normalize-name Fn (λ (t)
    //        (normalize-name* M* (λ (t*)
    //         (k `(,t . ,t*))))))]

    //     [(? Value?)             (k M)]))

    // (define (normalize-name M k)
    //   (normalize M (λ (N)
    //     (if (Value? N) (k N)
    //         (let ([t (gensym)])
    //          `(let ([,t ,N]) ,(k t)))))))

    // (define (normalize-name* M* k)
    //   (if (null? M*)
    //       (k '())
    //       (normalize-name (car M*) (λ (t)
    //        (normalize-name* (cdr M*) (λ (t*)
    //         (k `(,t . ,t*))))))))

}

macro_rules! test_anf(
    ($s:expr, $ae:expr) => { {
        use implicit_parse;
        use tok::Tokenizer;
        use std;
        let s = $s;
        let tokenizer = Tokenizer::new(&s);
        let iexpr = match implicit_parse::parse_Program(&s, tokenizer) {
            Ok(iexpr) => iexpr,
            Err(e) => {
                die!("parse_Program({}): {:?}", $s, e);
            }
        };
        let anf_expr = match anf(&iexpr) {
            Ok((anf_expr, _)) => anf_expr,
            Err(e) => {
                die!("anf: {:?}", e);
            }
        };
        if anf_expr != $ae {
            die!("mismatch {:?} != {:?}", anf_expr, $ae);
        }
    } }
);

#[test]
fn anf_transforms() {
    use common::Op2 as O;
    use self::Imm as I;
    use self::Op::*;
    use self::Expr::*;

    test_anf!(
        "-22",
        Op(Imm(I::Int(-22))));

    test_anf!(
        "2+3",
        Let(String::from("!tmp!0"),
            box Op(Op2(O::Add, box I::Int(2), box I::Int(3))),
            box Op(Imm(I::Var(String::from("!tmp!0"))))));
}
<commit_msg>only introduce let bindings if we have to<commit_after>use std::collections::HashMap;

use common::{Result, Id, Op2, Const};
use explicit;
use implicit;
use env;
use hindley_milner;

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Imm {
    Bool(bool),
    Int(i64),
    Var(Id),
    //    Fun(Id, Box<Expr>),
    //    Fix(Id, Box<Expr>),
    //    Star,
    //    V,
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Op {
    Op2(Op2, Box<Imm>, Box<Imm>),
    //    MkArray(Box<Imm>, Box<Imm>),
    //    GetArray(Box<Imm>, Box<Imm>),
    //    SetArray(Box<Imm>, Box<Imm>, Box<Imm>),
    Imm(Imm),
}
//    WellFormed(Imm), // Var-only

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Expr {
    //    If(Box<Imm>, Box<Imm>, Box<Imm>),
    //    App(Box<Imm>, Box<Imm>),
    Let(Id, Box<Expr>, Box<Expr>),
    Op(Op),
}

#[derive(PartialEq, Eq, Clone, Debug)]
struct ConvEnv {
    //env: HashMap<Id, explicit::Type>,
    next_id: i32,
}

impl ConvEnv {
    fn new() -> ConvEnv {
        ConvEnv {
            //env: HashMap::new(),
            next_id: 0,
        }
    }

    fn tmp(&self) -> (ConvEnv, Id) {
        let id = self.next_id;
        let c = ConvEnv{
            //env: self.env.clone(),
            next_id: self.next_id+1,
        };

        (c, format!("!tmp!{}", id))
    }
}

fn op(cenv: ConvEnv, e: &explicit::Expr) -> (ConvEnv, Op) {
    use typed::Expr as E;
    match *e {
        E::Const(Const::Bool(c)) => (cenv, Op::Imm(Imm::Bool(c))),
        E::Const(Const::Int(c)) => (cenv, Op::Imm(Imm::Int(c))),
        _ => {
            panic!("TODO: implement term for {:?}", e);
        }
    }
}

fn identity(cenv: ConvEnv, e: Expr) -> (ConvEnv, Expr) {
    (cenv, e)
}

fn imm(e: &Expr) -> Option<Imm> {
    if let &Expr::Op(Op::Imm(ref i)) = e {
        Some(i.clone())
    } else {
        None
    }
}

// 1:1 translation -- can't fail
fn expr(cenv: ConvEnv, e: &explicit::Expr, k: &Fn(ConvEnv, Expr) -> (ConvEnv, Expr)) -> (ConvEnv, Expr) {

    use self::Imm as I;
    use typed::Expr as E;
    use self::Op::*;
    use self::Expr::*;

    match *e {
        E::Const(_) => {
            let (cenv, eop) = op(cenv, e);
            k(cenv, Op(eop))
        }
        E::Op2(op, ref l, ref r) => {
            expr(cenv, l, &|cenv: ConvEnv, ll: Expr| -> (ConvEnv, Expr) {
                expr(cenv, r, &|cenv: ConvEnv, rr: Expr| -> (ConvEnv, Expr) {
                    // allocate vars
                    let mut cenv = cenv;

                    let (l_ref, l_bound) = match imm(&ll) {
                        Some(i) => (i, None),
                        None    => {
                            let (l_cenv, l_tmp) = cenv.tmp();
                            cenv = l_cenv;
                            (I::Var(l_tmp.clone()), Some(l_tmp))
                        }
                    };

                    let (r_ref, r_bound) = match imm(&rr) {
                        Some(i) => (i, None),
                        None    => {
                            let (r_cenv, r_tmp) = cenv.tmp();
                            cenv = r_cenv;
                            (I::Var(r_tmp.clone()), Some(r_tmp))
                        }
                    };

                    // value to pass to the continuation
                    let val = Op(Op2(op, box l_ref, box r_ref));

                    // our inner expression is whatever the
                    // continuation says it is.
                    let (cenv, mut result) = k(cenv, val);

                    if let Some(r_tmp) = r_bound {
                        result = Let(r_tmp, box rr, box result);
                    }
                    if let Some(l_tmp) = l_bound {
                        result = Let(l_tmp, box ll.clone(), box result);
                    }

                    (cenv, result)
                })
            })
        }
        _ => {
            panic!("TODO: implement expr for {:?}", e);
        }
    }
    // E::Op2(op, ref e1, ref e2) => {
    //     let (n, e1, _) = convert(n, env, renamed, e1);
    //     let (n, e2, _) = convert(n, env, renamed, e2);
    //     (n, I::Op2(op, box e1, box e2), explicit::opty(op))
    // }
    // E::If(ref e1, ref e2, ref e3) => {
    //     let (n, e1, _) = convert(n, env, renamed, e1);
    //     let (n, e2, t) = convert(n, env, renamed, e2);
    //     let (n, e3, _) = convert(n, env, renamed, e3);
    //     (n, I::If(box e1, box e2, box e3), t)
    // }
    // E::Var(ref x) => {
    //     let αx = renamed.get(x).unwrap();
    //     (n, I::Var(αx.clone()), env.get(αx).unwrap().clone())
    // }
    // E::Let(ref id, ref e1, ref e2) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     let (n, e1, t1) = convert(n, env, &renamed, e1);

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1);

    //     let (n, e2, t2) = convert(n, env, &renamed, e2);
    //     (n, I::Let(αid, box e1, box e2), t2)
    // }
    // E::Fun(ref id, ref t1, ref e) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1.clone());

    //     let (n, e, t2) = convert(n, env, &renamed, e);

    //     (n, I::Fun(αid, box e), Type::TFun(box t1.clone(), box t2))
    // }
    // E::Fix(ref id, ref t1, ref e) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1.clone());

    //     let (n, e, t2) = convert(n, env, &renamed, e);

    //     (n, I::Fix(αid, box e), t2)
    // }
    // E::App(ref e1, ref e2) => {
    //     let (n, e1, t1) = convert(n, env, renamed, e1);
    //     let (n, e2, _) = convert(n, env, renamed, e2);
    //     let t = match t1 {
    //         Type::TFun(_, t2) => *t2,
    //         _ => panic!("expected TFun, not {:?}", t1),
    //     };
    //     (n, I::App(box e1, box e2), t)
    // }
    // E::MkArray(ref sz, ref val) => {
    //     let (n, sz, _) = convert(n, env, renamed, sz);
    //     let (n, val, _) = convert(n, env, renamed, val);
    //     (n, I::MkArray(box sz, box val), Type::TIntArray)
    // }
    // E::GetArray(ref id, ref idx) => {
    //     let (n, id, _) = convert(n, env, renamed, id);
    //     let (n, idx, _) = convert(n, env, renamed, idx);
    //     (n, I::GetArray(box id, box idx), Type::TInt)
    // }
    // E::SetArray(ref id, ref idx, ref v) => {
    //     let (n, id, _) = convert(n, env, renamed, id);
    //     let (n, idx, _) = convert(n, env, renamed, idx);
    //     let (n, v, _) = convert(n, env, renamed, v);
    //     (n, I::SetArray(box id, box idx, box v), Type::TIntArray)
    // }
}

pub fn anf(implicit_expr: &implicit::Expr) -> Result<(Expr, HashMap<Id, explicit::Type>)> {

    let explicit_expr = hindley_milner::infer(implicit_expr)?;
    // alpha-renaming
    let (alpha_expr, env) = env::extract(&explicit_expr);

    // println!("α-implicit: {:?}\n", α_expr);
    // println!("Γ         : {:?}\n", env);

    let cenv = ConvEnv::new();
    let (_, expr) = expr(cenv, &alpha_expr, &identity);

    Ok((expr, env))
    // step 1 -- arithmatic + let bindings
    // step 2 -- conds + boolean vals
    // step 3 -- arrays
    // step 4 -- closures

    // (define (Value? M)
    //   (match M
    //     [`(quote ,_)         #t]
    //     [(? number?)         #t]
    //     [(? boolean?)        #t]
    //     [(? string?)         #t]
    //     [(? char?)           #t]
    //     [(? symbol?)         #t]
    //     [(or '+ '- '* '/ '=) #t]
    //     [else                #f]))

    // (define (normalize-term M) (normalize M (λ (x) x)))

    // (define (normalize M k)
    //   (match M
    //     [`(λ ,params ,body)
    //       (k `(λ ,params ,(normalize-term body)))]

    //     [`(let ([,x ,M1]) ,M2)
    //       (normalize M1 (λ (N1)
    //        `(let ([,x ,N1])
    //          ,(normalize M2 k))))]

    //     [`(if ,M1 ,M2 ,M3)
    //       (normalize-name M1 (λ (t)
    //        (k `(if ,t ,(normalize-term M2)
    //                   ,(normalize-term M3)))))]

    //     [`(,Fn . ,M*)
    //       (normalize-name Fn (λ (t)
    //        (normalize-name* M* (λ (t*)
    //         (k `(,t . ,t*))))))]

    //     [(? Value?)             (k M)]))

    // (define (normalize-name M k)
    //   (normalize M (λ (N)
    //     (if (Value? N) (k N)
    //         (let ([t (gensym)])
    //          `(let ([,t ,N]) ,(k t)))))))

    // (define (normalize-name* M* k)
    //   (if (null? M*)
    //       (k '())
    //       (normalize-name (car M*) (λ (t)
    //        (normalize-name* (cdr M*) (λ (t*)
    //         (k `(,t . ,t*))))))))

}

macro_rules! test_anf(
    ($s:expr, $ae:expr) => { {
        use implicit_parse;
        use tok::Tokenizer;
        use std;
        let s = $s;
        let tokenizer = Tokenizer::new(&s);
        let iexpr = match implicit_parse::parse_Program(&s, tokenizer) {
            Ok(iexpr) => iexpr,
            Err(e) => {
                die!("parse_Program({}): {:?}", $s, e);
            }
        };
        let anf_expr = match anf(&iexpr) {
            Ok((anf_expr, _)) => anf_expr,
            Err(e) => {
                die!("anf: {:?}", e);
            }
        };
        if anf_expr != $ae {
            die!("mismatch {:?} != {:?}", anf_expr, $ae);
        }
    } }
);

#[test]
fn anf_transforms() {
    use common::Op2 as O;
    use self::Imm as I;
    use self::Op::*;
    use self::Expr::*;

    test_anf!(
        "-22",
        Op(Imm(I::Int(-22))));

    test_anf!(
        "2+3",
        Op(Op2(O::Add, box I::Int(2), box I::Int(3))));

    test_anf!(
        "2+(3 - 2)",
        Let(String::from("!tmp!0"), box Op(Op2(O::Sub, box I::Int(3), box I::Int(2))),
            box Op(Op2(O::Add, box I::Int(2), box I::Var(String::from("!tmp!0"))))));
}
<|endoftext|>