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

use serde::ser::Serialize;
use serde_json::value::{Value, to_value};
use serde::Serializer;
use serde::ser::SerializeMap;

use errors::{Result as TeraResult, ResultExt};

/// The struct that holds the context of a template rendering.
///
/// Light wrapper around a `BTreeMap` for easier insertions of Serializable
/// values
#[derive(Debug, Clone)]
pub struct Context {
    data: BTreeMap<String, Value>,
}

impl Context {
    /// Initializes an empty context
    pub fn new() -> Context {
        Context {
            data: BTreeMap::new()
        }
    }

    /// Converts the `val` parameter to `Value` and insert it into the context
    ///
    /// ```rust,ignore
    /// let mut context = Context::new();
    /// // user is an instance of a struct implementing `Serialize`
    /// context.add("number_users", 42);
    /// ```
    pub fn add<T: Serialize>(&mut self, key: &str, val: &T) {
        self.data.insert(key.to_owned(), to_value(val).unwrap());
    }

    #[doc(hidden)]
    pub fn as_json(&self) -> TeraResult<Value> {
        to_value(&self.data).chain_err(|| "Failed to convert data to JSON")
    }

    /// Appends the data of the `source` parameter to `self`, overwriting existing keys.
    /// The source context will be dropped.
    ///
    /// ```rust,ignore
    /// let mut target = Context::new();
    /// target.add("a", 1);
    /// target.add("b", 2);
    /// let mut source = Context::new();
    /// source.add("b", 3);
    /// source.add("d", 4);
    /// target.extend(source);
    /// ```
    pub fn extend(&mut self, mut source: Context) {
        self.data.append(&mut source.data);
    }
}

impl Default for Context {
    fn default() -> Context {
        Context::new()
    }
}

impl Serialize for Context {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut map = serializer.serialize_map(Some(self.data.len()))?;
        for (k, v) in &self.data {
            map.serialize_key(&k)?;
            map.serialize_value(&v)?;
        }
        map.end()
    }
}

pub trait ValueRender {
    fn render(&self) -> String;
}

// Convert serde Value to String
impl ValueRender for Value {
    fn render(&self) -> String {
        match *self {
            Value::String(ref s) => s.clone(),
            Value::Number(ref i) => i.to_string(),
            Value::Bool(i) => i.to_string(),
            Value::Null => "".to_owned(),
            Value::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    if buf.len() > 1 {
                        buf.push_str(", ");
                    }
                    buf.push_str(i.render().as_ref());
                }
                buf.push(']');
                buf
            },
            Value::Object(_) => "[object]".to_owned()
        }
    }
}

pub trait ValueNumber {
    fn to_number(&self) -> Result<f64, ()>;
}
// Needed for all the maths
// Convert everything to f64, seems like a terrible idea
impl ValueNumber for Value {
    fn to_number(&self) -> Result<f64, ()> {
        match *self {
            Value::Number(ref i) => Ok(i.as_f64().unwrap()),
            _ => Err(())
        }
    }
}

// From handlebars-rust
pub trait ValueTruthy {
    fn is_truthy(&self) -> bool;
}

impl ValueTruthy for Value {
    fn is_truthy(&self) -> bool {
        match *self {
            Value::Number(ref i) => {
                if i.is_i64() {
                    return i.as_i64().unwrap() != 0;
                }
                if i.is_u64() {
                    return i.as_u64().unwrap() != 0;
                }
                let f = i.as_f64().unwrap();
                f != 0.0 && !f.is_nan()
            }
            Value::Bool(ref i) => *i,
            Value::Null => false,
            Value::String(ref i) => !i.is_empty(),
            Value::Array(ref i) => !i.is_empty(),
            Value::Object(ref i) => !i.is_empty()
        }
    }
}

/// Converts a dotted path to a json pointer one
#[inline]
pub fn get_json_pointer(key: &str) -> String {
    ["/", &key.replace(".", "/")].join("")
}

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

    #[test]
    fn test_extend() {
        let mut target = Context::new();
        target.add("a", &1);
        target.add("b", &2);
        let mut source = Context::new();
        source.add("b", &3);
        source.add("c", &4);
        target.extend(source);
        assert_eq!(*target.data.get("a").unwrap(), to_value(1).unwrap());
        assert_eq!(*target.data.get("b").unwrap(), to_value(3).unwrap());
        assert_eq!(*target.data.get("c").unwrap(), to_value(4).unwrap());
    }
}
<commit_msg>Remove Sized constraint on T in Context.add()<commit_after>use std::collections::BTreeMap;

use serde::ser::Serialize;
use serde_json::value::{Value, to_value};
use serde::Serializer;
use serde::ser::SerializeMap;

use errors::{Result as TeraResult, ResultExt};

/// The struct that holds the context of a template rendering.
///
/// Light wrapper around a `BTreeMap` for easier insertions of Serializable
/// values
#[derive(Debug, Clone)]
pub struct Context {
    data: BTreeMap<String, Value>,
}

impl Context {
    /// Initializes an empty context
    pub fn new() -> Context {
        Context {
            data: BTreeMap::new()
        }
    }

    /// Converts the `val` parameter to `Value` and insert it into the context
    ///
    /// ```rust,ignore
    /// let mut context = Context::new();
    /// // user is an instance of a struct implementing `Serialize`
    /// context.add("number_users", 42);
    /// ```
    pub fn add<T: Serialize + ?Sized>(&mut self, key: &str, val: &T) {
        self.data.insert(key.to_owned(), to_value(val).unwrap());
    }

    #[doc(hidden)]
    pub fn as_json(&self) -> TeraResult<Value> {
        to_value(&self.data).chain_err(|| "Failed to convert data to JSON")
    }

    /// Appends the data of the `source` parameter to `self`, overwriting existing keys.
    /// The source context will be dropped.
    ///
    /// ```rust,ignore
    /// let mut target = Context::new();
    /// target.add("a", 1);
    /// target.add("b", 2);
    /// let mut source = Context::new();
    /// source.add("b", 3);
    /// source.add("d", 4);
    /// target.extend(source);
    /// ```
    pub fn extend(&mut self, mut source: Context) {
        self.data.append(&mut source.data);
    }
}

impl Default for Context {
    fn default() -> Context {
        Context::new()
    }
}

impl Serialize for Context {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut map = serializer.serialize_map(Some(self.data.len()))?;
        for (k, v) in &self.data {
            map.serialize_key(&k)?;
            map.serialize_value(&v)?;
        }
        map.end()
    }
}

pub trait ValueRender {
    fn render(&self) -> String;
}

// Convert serde Value to String
impl ValueRender for Value {
    fn render(&self) -> String {
        match *self {
            Value::String(ref s) => s.clone(),
            Value::Number(ref i) => i.to_string(),
            Value::Bool(i) => i.to_string(),
            Value::Null => "".to_owned(),
            Value::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    if buf.len() > 1 {
                        buf.push_str(", ");
                    }
                    buf.push_str(i.render().as_ref());
                }
                buf.push(']');
                buf
            },
            Value::Object(_) => "[object]".to_owned()
        }
    }
}

pub trait ValueNumber {
    fn to_number(&self) -> Result<f64, ()>;
}
// Needed for all the maths
// Convert everything to f64, seems like a terrible idea
impl ValueNumber for Value {
    fn to_number(&self) -> Result<f64, ()> {
        match *self {
            Value::Number(ref i) => Ok(i.as_f64().unwrap()),
            _ => Err(())
        }
    }
}

// From handlebars-rust
pub trait ValueTruthy {
    fn is_truthy(&self) -> bool;
}

impl ValueTruthy for Value {
    fn is_truthy(&self) -> bool {
        match *self {
            Value::Number(ref i) => {
                if i.is_i64() {
                    return i.as_i64().unwrap() != 0;
                }
                if i.is_u64() {
                    return i.as_u64().unwrap() != 0;
                }
                let f = i.as_f64().unwrap();
                f != 0.0 && !f.is_nan()
            }
            Value::Bool(ref i) => *i,
            Value::Null => false,
            Value::String(ref i) => !i.is_empty(),
            Value::Array(ref i) => !i.is_empty(),
            Value::Object(ref i) => !i.is_empty()
        }
    }
}

/// Converts a dotted path to a json pointer one
#[inline]
pub fn get_json_pointer(key: &str) -> String {
    ["/", &key.replace(".", "/")].join("")
}

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

    #[test]
    fn test_extend() {
        let mut target = Context::new();
        target.add("a", &1);
        target.add("b", &2);
        let mut source = Context::new();
        source.add("b", &3);
        source.add("c", &4);
        target.extend(source);
        assert_eq!(*target.data.get("a").unwrap(), to_value(1).unwrap());
        assert_eq!(*target.data.get("b").unwrap(), to_value(3).unwrap());
        assert_eq!(*target.data.get("c").unwrap(), to_value(4).unwrap());
    }
}
<|endoftext|>


<commit_before>
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use std::sync::atomic::{Ordering, AtomicBool};
use std::io;
use std::io::{Error, ErrorKind};
use mio::{Token, Events};
use mio::net::{TcpListener, TcpStream};
use slab;
use connection;
use poll;
use server::SERVERTOKEN;

#[derive(Clone)]
pub struct ServerContext {
    pub _listener: Arc<RwLock<TcpListener>>,
    pub _conns: Arc<RwLock<slab::Slab<connection::Connection, Token>>>,
    pub _poller: Arc<RwLock<poll::Poller>>,

    _is_registed: Arc<AtomicBool>,
}

impl ServerContext {
    pub fn new(addr: &str, max_clients: usize) -> Option<ServerContext> {
        if max_clients >= SERVERTOKEN.into() {
            println!("too many clients, should less than 1_000");
            return None;
        }
        let poller_result = poll::Poller::new();
        let poller = match poller_result {
            Ok(p) => p,
            Err(_) => {
                return None;
            }
        };

        let address = addr.parse::<SocketAddr>();
        if let Ok(r) = address {
            let listener = TcpListener::bind(&r);
            println!("binded {:?}", r);
            if let Ok(l) = listener {
                return Some(ServerContext {
                                _listener: Arc::new(RwLock::new(l)),
                                _conns:
                                    Arc::new(RwLock::new(slab::Slab::with_capacity(max_clients))),
                                _poller: Arc::new(RwLock::new(poller)),
                                _is_registed: Arc::new(AtomicBool::new(false)),
                            });
            } else {
                println!("bind failed,  port used?");
            }
        }

        println!("address format [ip:port]");
        None
    }

    pub fn register_read(&self, token: Token) -> io::Result<()> {
        if self._is_registed.load(Ordering::SeqCst) {
            return Ok(());
        }

        let poller = self._poller.read().unwrap();
        let listener_guard = self._listener.read().unwrap();
        self._is_registed.store(true, Ordering::SeqCst);
        poller.register_read(&*listener_guard, token)
    }

    pub fn poll_once(&self, events: &mut Events) -> io::Result<usize> {
        let poller = self._poller.read().unwrap();
        poller.poll_once(events)
    }

    pub fn remove_client(&self, token: Token) {
        let mut clients = self._conns.write().unwrap();
        clients.remove(token);
    }

    pub fn available_token(&self, client: TcpStream) -> Option<Token> {
        let mut conns = self._conns.write().unwrap();
        let entry_op = conns.vacant_entry();
        let token = match entry_op {
            Some(e) => {
                let connection = connection::Connection::new(client, e.index());
                e.insert(connection).index()
            }
            None => {
                println!("no empty entry for new clients");
                return None;
            }
        };

        Some(token)
    }

    pub fn register_token(&self, token: Token) -> io::Result<()> {
        let clients = self._conns.read().unwrap();
        let mut poller = self._poller.write().unwrap();
        if let Some(c) = clients.get(token) {
            c.register(&mut poller)?;
            return Ok(());
        }

        Err(Error::new(ErrorKind::InvalidInput, "Invalid token"))
    }

    #[allow(dead_code)]
    pub fn send_message_to_client(&self, token: Token, msg: Arc<Vec<u8>>) -> io::Result<()> {
        let conns = self._conns.read().unwrap();
        let client_op = conns.get(token);
        let client = match client_op {
            Some(expr) => expr,
            None => {
                println!("no client got:{:?}", token);
                return Err(Error::new(ErrorKind::InvalidData, "invlid token"));
            }
        };

        client.send_message(msg.clone());
        Ok(())
    } //end send?
}
<commit_msg>Update context.rs<commit_after>
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use std::io;
use std::io::{Error, ErrorKind};
use mio::{Token};
use mio::net::{TcpListener, TcpStream};
use slab;
use connection;
use serialize;

/* only one tcplistener */
pub fn bind(addr:&str)->io::Result<TcpListener> {
    let address = addr.parse::<SocketAddr>();
    if let Ok(r) = address {
        return TcpListener::bind(&r);
    }

    Err(Error::new(ErrorKind::InvalidInput, "Invalid input"))
}

//#[derive(Clone)]
pub struct Context<T: serialize::MessageHandler + Sized> {
    pub _conns: Arc<RwLock<slab::Slab<connection::Connection, Token>>>,
    //the refcell used betten than raw trait
    //it can callback the mut function when needed
    pub _handle: Arc<RwLock<T>>,

    pub _capacity:usize,
}

impl<T: serialize::MessageHandler+Sized> Clone for Context<T> {
    fn clone(&self) -> Self {
        Context {
            _conns:Arc::new(RwLock::new(slab::Slab::with_capacity(self._capacity))),
            _handle: self._handle.clone(),
            _capacity:self._capacity,
        }
    }
}

impl<T: serialize::MessageHandler + Sized> Context<T> {
    pub fn new(handle:T, max_clients:usize) -> Self {
        Context {
            _conns: Arc::new(RwLock::new(slab::Slab::with_capacity(max_clients))),
            _handle:Arc::new(RwLock::new(handle)),
            _capacity:max_clients,
        }
    }

    pub fn remove_client(&self, token: Token) {
        let mut clients = self._conns.write().unwrap();
        clients.remove(token);
    }

    pub fn available_token(&self, client: TcpStream) -> Option<Token> {
        let mut conns = self._conns.write().unwrap();
        let entry_op = conns.vacant_entry();
        let token = match entry_op {
            Some(e) => {
                let connection = connection::Connection::new(client, e.index());
                e.insert(connection).index()
            }
            None => {
                println!("no empty entry for new clients");
                return None;
            }
        };

        Some(token)
    }

    #[allow(dead_code)]
    pub fn send_message_to_client(&self, token: Token, msg: Arc<Vec<u8>>) -> io::Result<()> {
        let conns = self._conns.read().unwrap();
        let client_op = conns.get(token);
        let client = match client_op {
            Some(expr) => expr,
            None => {
                println!("no client got:{:?}", token);
                return Err(Error::new(ErrorKind::InvalidData, "invlid token"));
            }
        };

        client.send_message(msg.clone());
        Ok(())
    } //end send?
}
<|endoftext|>


<commit_before>// The CPU
#![allow(dead_code)]
#![allow(non_snake_case)]
mod opcodes;
use utils;
use std::mem;

struct Memory
{
    bytes: [u8;65536]
}

impl Memory
{
    pub fn new() -> Memory
    {
        Memory
        {
            bytes: [0;65536]
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte_be(0x0000, 0xFF);
        self.write_byte_be(0x0001, 0x07);
    }

    // Write to memory using little endian memory address
    pub fn write_byte_le(&mut self, addr_le: u16, value: u8)
    {
        let addr_be = ((addr_le << 8) & 0xFF) | ((addr_le >> 8) & 0xFF);
        self.bytes[addr_be as usize] = value;
    }

    // Read from memory using little endian memory address
    pub fn read_byte_le(&mut self, addr_le: u16) -> u8
    {
        let addr_be = ((addr_le << 8) & 0xFF) | ((addr_le >> 8) & 0xFF);
        self.bytes[addr_be as usize]
    }

    // Write to memory using big endian memory address
    pub fn write_byte_be(&mut self, addr_be: u16, value: u8)
    {
        self.bytes[addr_be as usize] = value;
    }

    // Read from memory using big endian memory address
    pub fn read_byte_be(&mut self, addr_be: u16) -> u8
    {
        self.bytes[addr_be as usize]
    }

    // Read a word from memory, convert it to little endian
    pub fn read_word_lele(&mut self, addr_le: u16) -> u16
    {
        let addr_be = ((addr_le << 8) & 0xFF) | ((addr_le >> 8) & 0xFF);
        let value_be: u16 = ((self.bytes[addr_be as usize] as u16) << 8 & 0xFF00) |
                            ((self.bytes[(addr_be+1) as usize] as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    pub fn read_word_bele(&mut self, addr_be: u16) -> u16
    {
        let value_be: u16 = ((self.bytes[addr_be as usize] as u16) << 8 & 0xFF00) |
                            ((self.bytes[(addr_be+1) as usize] as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    pub fn read_word_bebe(&mut self, addr_be: u16) -> u16
    {
        let value_be: u16 = ((self.bytes[addr_be as usize] as u16) << 8 & 0xFF00) |
                            ((self.bytes[(addr_be+1) as usize] as u16) & 0x00FF);
        value_be
    }

    pub fn read_word_lebe(&mut self, addr_le: u16) -> u16
    {
        let addr_be = ((addr_le << 8) & 0xFF) | ((addr_le >> 8) & 0xFF);
        let value_be: u16 = ((self.bytes[addr_be as usize] as u16) << 8 & 0xFF00) |
                            ((self.bytes[(addr_be+1) as usize] as u16) & 0x00FF);
        value_be
    }
}

// status flags for P register
enum StatusFlag
{
    N = 1 << 0, // negative flag
    V = 1 << 1, // overflow flag
    X = 1 << 2, // unused flag
    B = 1 << 3, // break flag
    D = 1 << 4, // decimal mode flag
    I = 1 << 5, // interrupt disable flag
    Z = 1 << 6, // zero flag
    C = 1 << 7  // carry flag
}

pub struct CPU
{
    PC: u16, // program counter
    S: u8,   // stack pointer
    P: u8,   // processor status
    A: u8,   // accumulator
    X: u8,   // index register
    Y: u8,   // index register
    mem: Memory
}

impl CPU
{
    pub fn new() -> CPU
    {
        CPU
        {
            PC: 0,
            S: 0,
            P: 0,
            A: 0,
            X: 0,
            Y: 0,
            mem: Memory::new()
        }
    }

    pub fn reset(&mut self)
    {
        // set the registers to initial state on power up
        self.mem.reset();

        // load basic
        let mut startAddress: u32 = 0xA000;
        let basic = utils::open_file("rom/basic.rom");

        for (i,addr) in (startAddress..0xC000).enumerate()
        {
            self.mem.write_byte_be(addr as u16, basic[i as usize]);
        }

        // load chargen
        startAddress = 0xD000;
        let chargen = utils::open_file("rom/chargen.rom");

        for (i,addr) in (startAddress..0xE000).enumerate()
        {
            self.mem.write_byte_be(addr as u16, chargen[i as usize]);
        }

        // load kernal
        startAddress = 0xE000;
        let kernal = utils::open_file("rom/kernal.rom");

        for (i,addr) in (startAddress..0x10000).enumerate()
        {
            self.mem.write_byte_be(addr as u16, kernal[i as usize]);
        }

        // reset program counter
        self.PC = self.mem.read_word_bele(0xFFFC);
    }

    pub fn update(&mut self)
    {
        //self.process_op(15);
        //self.process_op(16);
        // process opcodes, to the cpu stuff
        //self.mem.bytes[0] = 1;

        //for i in (0..65536)
        //{
        //println!("{}", self.mem.bytes[i]);
        //}
    }

    fn u8_to_enum(v: u8) -> opcodes::Opcodes
    {
        unsafe { mem::transmute(v) }
    }

    fn mem_dump(&mut self)
    {
        for i in (0..0x10000)
        {
            let val = self.mem.read_byte_be(i as u16);
            if val != 0
                { println!("Addr: {} {}", i, val); }
        }
    }

    fn process_op(&self, opcode: u8)
    {
        use cpu::opcodes::Opcodes;
        match CPU::u8_to_enum(opcode)
        {
            Opcodes::BRK => println!("TODO: {}", opcode),
            Opcodes::NOP_zp   => (),
            Opcodes::NOP_abs  => (),
            Opcodes::HLT1 => panic!("Received HLT1 instruction: 0x{0:X}", opcode),
            Opcodes::NOP_zpx  => (),
            Opcodes::NOP0     => (),
            Opcodes::NOP_abx  => (),
            Opcodes::HLT2 => panic!("Received HLT2 instruction: 0x{0:X}", opcode),
            Opcodes::HLT3 => panic!("Received HLT3 instruction: 0x{0:X}", opcode),
            Opcodes::NOP_zpx2 => (),
            Opcodes::NOP1     => (),
            Opcodes::NOP_abx2 => (),
            Opcodes::HLT4 => panic!("Received HLT4 instruction: 0x{0:X}", opcode),
            Opcodes::NOP2     => (),
            Opcodes::HLT5 => panic!("Received HLT5 instruction: 0x{0:X}", opcode),
            Opcodes::NOP_zpx3 => (),
            Opcodes::NOP3     => (),
            Opcodes::NOP_abx3 => (),
            Opcodes::HLT6 => panic!("Received HLT6 instruction: 0x{0:X}", opcode),
            Opcodes::NOP_zp2  => (),
            Opcodes::HLT7 => panic!("Received HLT7 instruction: 0x{0:X}", opcode),
            Opcodes::NOP_zpx4 => (),
            Opcodes::NOP4     => (),
            Opcodes::NOP_abx4 => (),
            Opcodes::NOP_imm  => (),
            Opcodes::NOP_imm2 => (),
            Opcodes::NOP_imm3 => (),
            Opcodes::HLT8 => panic!("Received HLT8 instruction: 0x{0:X}", opcode),
            Opcodes::HLT9 => panic!("Received HLT9 instruction: 0x{0:X}", opcode),
            Opcodes::NOP_imm4 => (),
            Opcodes::HLT10 => panic!("Received HLT10 instruction: 0x{0:X}", opcode),
            Opcodes::NOP_zpx5 => (),
            Opcodes::NOP5     => (),
            Opcodes::NOP_abx5 => (),
            Opcodes::NOP_imm5 => (),
            Opcodes::NOP      => (),
            Opcodes::HLT11 => panic!("Received HLT11 instruction: 0x{0:X}", opcode),
            Opcodes::NOP_zpx6 => (),
            Opcodes::NOP6     => (),
            Opcodes::NOP_abx6 => (),
            _ => println!("Unknown opcode: 0x{0:X}", opcode)
        }
    }
}
<commit_msg>stack push/pop<commit_after>// The CPU
#![allow(dead_code)]
#![allow(non_snake_case)]
mod opcodes;
use utils;
use std::mem;

struct Memory
{
    bytes: [u8;65536]
}

impl Memory
{
    pub fn new() -> Memory
    {
        Memory
        {
            bytes: [0;65536]
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte_be(0x0000, 0xFF);
        self.write_byte_be(0x0001, 0x07);
    }

    // Write to memory using little endian memory address
    pub fn write_byte_le(&mut self, addr_le: u16, value: u8)
    {
        let addr_be = ((addr_le << 8) & 0xFF) | ((addr_le >> 8) & 0xFF);
        self.bytes[addr_be as usize] = value;
    }

    // Read from memory using little endian memory address
    pub fn read_byte_le(&mut self, addr_le: u16) -> u8
    {
        let addr_be = ((addr_le << 8) & 0xFF) | ((addr_le >> 8) & 0xFF);
        self.bytes[addr_be as usize]
    }

    // Write to memory using big endian memory address
    pub fn write_byte_be(&mut self, addr_be: u16, value: u8)
    {
        self.bytes[addr_be as usize] = value;
    }

    // Read from memory using big endian memory address
    pub fn read_byte_be(&mut self, addr_be: u16) -> u8
    {
        self.bytes[addr_be as usize]
    }

    // Read a word from memory, convert it to little endian
    pub fn read_word_lele(&mut self, addr_le: u16) -> u16
    {
        let addr_be = ((addr_le << 8) & 0xFF) | ((addr_le >> 8) & 0xFF);
        let value_be: u16 = ((self.bytes[addr_be as usize] as u16) << 8 & 0xFF00) |
                            ((self.bytes[(addr_be+1) as usize] as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    pub fn read_word_bele(&mut self, addr_be: u16) -> u16
    {
        let value_be: u16 = ((self.bytes[addr_be as usize] as u16) << 8 & 0xFF00) |
                            ((self.bytes[(addr_be+1) as usize] as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    pub fn read_word_bebe(&mut self, addr_be: u16) -> u16
    {
        let value_be: u16 = ((self.bytes[addr_be as usize] as u16) << 8 & 0xFF00) |
                            ((self.bytes[(addr_be+1) as usize] as u16) & 0x00FF);
        value_be
    }

    pub fn read_word_lebe(&mut self, addr_le: u16) -> u16
    {
        let addr_be = ((addr_le << 8) & 0xFF) | ((addr_le >> 8) & 0xFF);
        let value_be: u16 = ((self.bytes[addr_be as usize] as u16) << 8 & 0xFF00) |
                            ((self.bytes[(addr_be+1) as usize] as u16) & 0x00FF);
        value_be
    }

    pub fn write_word_bele(&mut self, addr_be: u16, value_be: u16)
    {
        let value_le_hi: u8 = (((value_be << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_lo: u8 = ((value_be >> 8) & 0x00FF) as u8;

        self.bytes[addr_be as usize] = value_le_hi;
        self.bytes[(addr_be + 0x01) as usize] = value_le_lo;
    }

}

// status flags for P register
enum StatusFlag
{
    N = 1 << 0, // negative flag
    V = 1 << 1, // overflow flag
    X = 1 << 2, // unused flag
    B = 1 << 3, // break flag
    D = 1 << 4, // decimal mode flag
    I = 1 << 5, // interrupt disable flag
    Z = 1 << 6, // zero flag
    C = 1 << 7  // carry flag
}

pub struct CPU
{
    PC: u16, // program counter
    SP: u8,  // stack pointer
    P: u8,   // processor status
    A: u8,   // accumulator
    X: u8,   // index register
    Y: u8,   // index register
    mem: Memory
}

impl CPU
{
    pub fn new() -> CPU
    {
        CPU
        {
            PC: 0,
            SP: 0xFF,
            P: 0,
            A: 0,
            X: 0,
            Y: 0,
            mem: Memory::new()
        }
    }

    pub fn reset(&mut self)
    {
        // set the registers to initial state on power up
        self.mem.reset();

        // load basic
        let mut startAddress: u32 = 0xA000;
        let basic = utils::open_file("rom/basic.rom");

        for (i,addr) in (startAddress..0xC000).enumerate()
        {
            self.mem.write_byte_be(addr as u16, basic[i as usize]);
        }

        // load chargen
        startAddress = 0xD000;
        let chargen = utils::open_file("rom/chargen.rom");

        for (i,addr) in (startAddress..0xE000).enumerate()
        {
            self.mem.write_byte_be(addr as u16, chargen[i as usize]);
        }

        // load kernal
        startAddress = 0xE000;
        let kernal = utils::open_file("rom/kernal.rom");

        for (i,addr) in (startAddress..0x10000).enumerate()
        {
            self.mem.write_byte_be(addr as u16, kernal[i as usize]);
        }

        // reset program counter
        self.PC = self.mem.read_word_bele(0xFFFC);
    }

    pub fn update(&mut self)
    {
        let op = self.fetch_op();
        self.process_op(op);
        //self.process_op(15);
        //self.process_op(16);
        // process opcodes, to the cpu stuff
        //self.mem.bytes[0] = 1;

        //for i in (0..65536)
        //{
        //println!("{}", self.mem.bytes[i]);
        //}
    }

    fn fetch_op(&mut self) -> u8
    {
        let op = self.mem.read_byte_be(self.PC);
        self.PC += 1;
        op
    }

    // stack memory: $0100 - $01FF (256 byes)
    fn push_byte(&mut self, value: u8)
    {
        self.SP -= 0x01;

        if self.SP == 0xFF
            { panic!("Stack underflow"); }

        self.mem.write_byte_be(0x0100 + ((self.SP + 0x01) as u16) & 0x00FF, value);
    }

    fn pop_byte(&mut self) -> u8
    {
        let value = self.mem.read_byte_be(0x0100 + ((self.SP + 0x01) as u16) & 0x00FF);
        self.PC += 0x01;

        if self.SP == 0x00
            { panic!("Stack overflow"); }

        value
    }

    fn push_word(&mut self, value: u16)
    {
        self.SP -= 0x02;

        if self.SP == 0xFF || self.SP == 0xFE
            { panic!("Stack underflow"); }

        self.mem.write_word_bele(0x0100 + ((self.SP + 0x01) as u16) & 0x00FF, value);
    }

    fn pop_word(&mut self) -> u16
    {
        let value = self.mem.read_word_bele(0x0100 + ((self.SP + 0x01) as u16) & 0x00FF);
        self.PC += 0x02;

        if self.SP == 0x00 || self.SP == 0x01
            { panic!("Stack overflow"); }

        value
    }

    fn u8_to_enum(v: u8) -> opcodes::Opcodes
    {
        unsafe { mem::transmute(v) }
    }

    fn mem_dump(&mut self)
    {
        for i in (0..0x10000)
        {
            let val = self.mem.read_byte_be(i as u16);
            if val != 0
                { println!("Addr: ${:04X} -> 0x{:02X}", i, val); }
        }
    }

    fn process_op(&self, opcode: u8)
    {
        use cpu::opcodes::Opcodes;
        match CPU::u8_to_enum(opcode)
        {
            Opcodes::BRK => println!("TODO: {}", opcode),
            Opcodes::NOP_zp   => (),
            Opcodes::NOP_abs  => (),
            Opcodes::HLT1 => panic!("Received HLT1 instruction: 0x{:02X} at ${:02X}", opcode, self.PC),
            Opcodes::NOP_zpx  => (),
            Opcodes::NOP0     => (),
            Opcodes::NOP_abx  => (),
            Opcodes::HLT2 => panic!("Received HLT2 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::HLT3 => panic!("Received HLT3 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::NOP_zpx2 => (),
            Opcodes::NOP1     => (),
            Opcodes::NOP_abx2 => (),
            Opcodes::HLT4 => panic!("Received HLT4 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::NOP2     => (),
            Opcodes::HLT5 => panic!("Received HLT5 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::NOP_zpx3 => (),
            Opcodes::NOP3     => (),
            Opcodes::NOP_abx3 => (),
            Opcodes::HLT6 => panic!("Received HLT6 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::NOP_zp2  => (),
            Opcodes::HLT7 => panic!("Received HLT7 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::NOP_zpx4 => (),
            Opcodes::NOP4     => (),
            Opcodes::NOP_abx4 => (),
            Opcodes::NOP_imm  => (),
            Opcodes::NOP_imm2 => (),
            Opcodes::NOP_imm3 => (),
            Opcodes::HLT8 => panic!("Received HLT8 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::HLT9 => panic!("Received HLT9 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::NOP_imm4 => (),
            Opcodes::HLT10 => panic!("Received HLT10 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::NOP_zpx5 => (),
            Opcodes::NOP5     => (),
            Opcodes::NOP_abx5 => (),
            Opcodes::NOP_imm5 => (),
            Opcodes::NOP      => (),
            Opcodes::HLT11 => panic!("Received HLT11 instruction: 0x{:02X} at ${:04X}", opcode, self.PC),
            Opcodes::NOP_zpx6 => (),
            Opcodes::NOP6     => (),
            Opcodes::NOP_abx6 => (),
            _ => println!("Unknown opcode: 0x{:02X} at ${:04X}", opcode, self.PC)
        }
    }
}
<|endoftext|>


<commit_before>//! Simple module to store files in database.
//!
//! cratesfyi is generating more than 5 million files, they are small and mostly html files.
//! They are using so many inodes and it is better to store them in database instead of
//! filesystem. This module is adding files into database and retrieving them.

use std::path::{PathBuf, Path};
use postgres::Connection;
use rustc_serialize::json::{Json, ToJson};
use std::fs;
use std::io::Read;
use error::Result;
use failure::err_msg;
use rusoto_s3::{S3, PutObjectRequest, GetObjectRequest, S3Client};
use rusoto_core::region::Region;
use rusoto_credential::EnvironmentProvider;

fn get_file_list_from_dir<P: AsRef<Path>>(path: P,
                                          files: &mut Vec<PathBuf>)
                                          -> Result<()> {
    let path = path.as_ref();

    for file in try!(path.read_dir()) {
        let file = try!(file);

        if try!(file.file_type()).is_file() {
            files.push(file.path());
        } else if try!(file.file_type()).is_dir() {
            try!(get_file_list_from_dir(file.path(), files));
        }
    }

    Ok(())
}

pub fn get_file_list<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>> {
    let path = path.as_ref();
    let mut files = Vec::new();

    if !path.exists() {
        return Err(err_msg("File not found"));
    } else if path.is_file() {
        files.push(PathBuf::from(path.file_name().unwrap()));
    } else if path.is_dir() {
        try!(get_file_list_from_dir(path, &mut files));
        for file_path in &mut files {
            // We want the paths in this list to not be {path}/bar.txt but just bar.txt
            *file_path = PathBuf::from(file_path.strip_prefix(path).unwrap());
        }
    }

    Ok(files)
}

pub struct Blob {
    pub path: String,
    pub mime: String,
    pub date_updated: time::Timespec,
    pub content: Vec<u8>,
}

pub fn get_path(conn: &Connection, path: &str) -> Option<Blob> {
    let rows = conn.query("SELECT path, mime, date_updated, content
                           FROM files
                           WHERE path = $1", &[&path]).unwrap();

    if rows.len() == 0 {
        None
    } else {
        let row = rows.get(0);
        let mut content = row.get(3);
        if content == b"in-s3" {
            let client = s3_client();
            content = client.and_then(|c| c.get_object(GetObjectRequest {
                bucket: "rust-docs-rs".into(),
                key: path.into(),
                ..Default::default()
            }).sync().ok()).and_then(|r| r.body).map(|b| {
                let mut b = b.into_blocking_read();
                let mut content = Vec::new();
                b.read_to_end(&mut content).unwrap();
                content
            }).unwrap();
        };

        Some(Blob {
            path: row.get(0),
            mime: row.get(1),
            date_updated: row.get(2),
            content,
        })
    }
}

fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() {
        return None;
    }
    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        EnvironmentProvider::default(),
        std::env::var("S3_ENDPOINT").ok().map(|e| Region::Custom {
            name: "us-west-1".to_owned(),
            endpoint: e,
        }).unwrap_or(Region::UsWest1),
    ))
}

/// Adds files into database and returns list of files with their mime type in Json
pub fn add_path_into_database<P: AsRef<Path>>(conn: &Connection,
                                              prefix: &str,
                                              path: P)
                                              -> Result<Json> {
    use magic::{Cookie, flags};
    let cookie = try!(Cookie::open(flags::MIME_TYPE));
    try!(cookie.load::<&str>(&[]));

    let trans = try!(conn.transaction());
    let client = s3_client();
    let mut file_list_with_mimes: Vec<(String, PathBuf)> = Vec::new();

    for file_path in try!(get_file_list(&path)) {
        let (path, content, mime) = {
            let path = Path::new(path.as_ref()).join(&file_path);
            // Some files have insufficient permissions (like .lock file created by cargo in
            // documentation directory). We are skipping this files.
            let mut file = match fs::File::open(path) {
                Ok(f) => f,
                Err(_) => continue,
            };
            let mut content: Vec<u8> = Vec::new();
            try!(file.read_to_end(&mut content));
            let bucket_path = Path::new(prefix).join(&file_path)
                .into_os_string().into_string().unwrap();

            let mime = {
                let mime = try!(cookie.buffer(&content));
                // css's are causing some problem in browsers
                // magic will return text/plain for css file types
                // convert them to text/css
                // do the same for javascript files
                if mime == "text/plain" {
                    let e = file_path.extension().unwrap_or_default();
                    if e == "css" {
                        "text/css".to_owned()
                    } else if e == "js" {
                        "application/javascript".to_owned()
                    } else {
                        mime.to_owned()
                    }
                } else {
                    mime.to_owned()
                }
            };

            let content: Option<Vec<u8>> = if let Some(client) = &client {
                let s3_res = client.put_object(PutObjectRequest {
                    bucket: "rust-docs-rs".into(),
                    key: bucket_path.clone(),
                    body: Some(content.clone().into()),
                    content_type: Some(mime.clone()),
                    ..Default::default()
                }).sync();
                match s3_res {
                    // we've successfully uploaded the content, so steal it;
                    // we don't want to put it in the DB
                    Ok(_) => None,
                    // Since s3 was configured, we want to panic on failure to upload.
                    Err(e) => {
                        panic!("failed to upload to {}: {:?}", bucket_path, e)
                    },
                }
            } else {
                Some(content.clone().into())
            };

            file_list_with_mimes.push((mime.clone(), file_path.clone()));

            (
                bucket_path,
                content,
                mime,
            )
        };

        // check if file already exists in database
        let rows = try!(conn.query("SELECT COUNT(*) FROM files WHERE path = $1", &[&path]));

        let content = content.unwrap_or_else(|| "in-s3".to_owned().into());

        if rows.get(0).get::<usize, i64>(0) == 0 {
            try!(trans.query("INSERT INTO files (path, mime, content) VALUES ($1, $2, $3)",
                             &[&path, &mime, &content]));
        } else {
            try!(trans.query("UPDATE files SET mime = $2, content = $3, date_updated = NOW() \
                              WHERE path = $1",
                             &[&path, &mime, &content]));
        }
    }

    try!(trans.commit());

    file_list_to_json(file_list_with_mimes)
}

fn file_list_to_json(file_list: Vec<(String, PathBuf)>) -> Result<Json> {

    let mut file_list_json: Vec<Json> = Vec::new();

    for file in file_list {
        let mut v: Vec<String> = Vec::new();
        v.push(file.0.clone());
        v.push(file.1.into_os_string().into_string().unwrap());
        file_list_json.push(v.to_json());
    }

    Ok(file_list_json.to_json())
}

pub fn move_to_s3(conn: &Connection, n: usize) -> Result<usize> {
    let trans = try!(conn.transaction());
    let client = s3_client().expect("configured s3");

    let rows = try!(trans.query(
            &format!("SELECT path, mime, content FROM files WHERE content != E'in-s3' LIMIT {}", n),
            &[]));
    let count = rows.len();

    let mut rt = ::tokio::runtime::current_thread::Runtime::new().unwrap();
    let mut futures = Vec::new();
    for row in &rows {
        let path: String = row.get(0);
        let mime: String = row.get(1);
        let content: Vec<u8> = row.get(2);
        let path_1 = path.clone();
        futures.push(client.put_object(PutObjectRequest {
            bucket: "rust-docs-rs".into(),
            key: path.clone(),
            body: Some(content.into()),
            content_type: Some(mime),
            ..Default::default()
        }).map(move |_| {
            path_1
        }).map_err(move |e| {
            panic!("failed to upload to {}: {:?}", path, e)
        }));
    }

    use ::futures::future::Future;
    match rt.block_on(::futures::future::join_all(futures)) {
        Ok(paths) => {
            let statement = trans.prepare("UPDATE files SET content = E'in-s3' WHERE path = $1")
                .unwrap();
            for path in paths {
                statement.execute(&[&path]).unwrap();
            }
        }
        Err(e) => {
            panic!("results err: {:?}", e);
        }
    }

    try!(trans.commit());

    Ok(count)
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::env;
    use super::get_file_list;

    #[test]
    fn test_get_file_list() {
        let _ = env_logger::try_init();

        let files = get_file_list(env::current_dir().unwrap());
        assert!(files.is_ok());
        assert!(files.unwrap().len() > 0);

        let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
        assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
    }
}
<commit_msg>Only query files table if S3 credentials are not configured<commit_after>//! Simple module to store files in database.
//!
//! cratesfyi is generating more than 5 million files, they are small and mostly html files.
//! They are using so many inodes and it is better to store them in database instead of
//! filesystem. This module is adding files into database and retrieving them.

use std::path::{PathBuf, Path};
use postgres::Connection;
use rustc_serialize::json::{Json, ToJson};
use std::fs;
use std::io::Read;
use error::Result;
use failure::err_msg;
use rusoto_s3::{S3, PutObjectRequest, GetObjectRequest, S3Client};
use rusoto_core::region::Region;
use rusoto_credential::EnvironmentProvider;

fn get_file_list_from_dir<P: AsRef<Path>>(path: P,
                                          files: &mut Vec<PathBuf>)
                                          -> Result<()> {
    let path = path.as_ref();

    for file in try!(path.read_dir()) {
        let file = try!(file);

        if try!(file.file_type()).is_file() {
            files.push(file.path());
        } else if try!(file.file_type()).is_dir() {
            try!(get_file_list_from_dir(file.path(), files));
        }
    }

    Ok(())
}

pub fn get_file_list<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>> {
    let path = path.as_ref();
    let mut files = Vec::new();

    if !path.exists() {
        return Err(err_msg("File not found"));
    } else if path.is_file() {
        files.push(PathBuf::from(path.file_name().unwrap()));
    } else if path.is_dir() {
        try!(get_file_list_from_dir(path, &mut files));
        for file_path in &mut files {
            // We want the paths in this list to not be {path}/bar.txt but just bar.txt
            *file_path = PathBuf::from(file_path.strip_prefix(path).unwrap());
        }
    }

    Ok(files)
}

pub struct Blob {
    pub path: String,
    pub mime: String,
    pub date_updated: time::Timespec,
    pub content: Vec<u8>,
}

pub fn get_path(conn: &Connection, path: &str) -> Option<Blob> {
    if let Some(client) = s3_client() {
        let res = client.get_object(GetObjectRequest {
            bucket: "rust-docs-rs".into(),
            key: path.into(),
            ..Default::default()
        }).sync();

        let res = match res {
            Ok(r) => r,
            Err(err) => {
                debug!("error fetching {}: {:?}", path, err);
                return None;
            }
        };

        let mut b = res.body.unwrap().into_blocking_read();
        let mut content = Vec::new();
        b.read_to_end(&mut content).unwrap();

        let last_modified = res.last_modified.unwrap();
        let last_modified = time::strptime(&last_modified, "%a, %d %b %Y %H:%M:%S %Z")
            .unwrap_or_else(|e| panic!("failed to parse {:?} as timespec: {:?}", last_modified, e))
            .to_timespec();

        Some(Blob {
            path: path.into(),
            mime: res.content_type.unwrap(),
            date_updated: last_modified,
            content,
        })
    } else {
        let rows = conn.query("SELECT path, mime, date_updated, content
                            FROM files
                            WHERE path = $1", &[&path]).unwrap();

        if rows.len() == 0 {
            None
        } else {
            let row = rows.get(0);

            Some(Blob {
                path: row.get(0),
                mime: row.get(1),
                date_updated: row.get(2),
                content: row.get(3),
            })
        }
    }
}

fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() {
        return None;
    }
    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        EnvironmentProvider::default(),
        std::env::var("S3_ENDPOINT").ok().map(|e| Region::Custom {
            name: "us-west-1".to_owned(),
            endpoint: e,
        }).unwrap_or(Region::UsWest1),
    ))
}

/// Adds files into database and returns list of files with their mime type in Json
pub fn add_path_into_database<P: AsRef<Path>>(conn: &Connection,
                                              prefix: &str,
                                              path: P)
                                              -> Result<Json> {
    use magic::{Cookie, flags};
    let cookie = try!(Cookie::open(flags::MIME_TYPE));
    try!(cookie.load::<&str>(&[]));

    let trans = try!(conn.transaction());
    let client = s3_client();
    let mut file_list_with_mimes: Vec<(String, PathBuf)> = Vec::new();

    for file_path in try!(get_file_list(&path)) {
        let (path, content, mime) = {
            let path = Path::new(path.as_ref()).join(&file_path);
            // Some files have insufficient permissions (like .lock file created by cargo in
            // documentation directory). We are skipping this files.
            let mut file = match fs::File::open(path) {
                Ok(f) => f,
                Err(_) => continue,
            };
            let mut content: Vec<u8> = Vec::new();
            try!(file.read_to_end(&mut content));
            let bucket_path = Path::new(prefix).join(&file_path)
                .into_os_string().into_string().unwrap();

            let mime = {
                let mime = try!(cookie.buffer(&content));
                // css's are causing some problem in browsers
                // magic will return text/plain for css file types
                // convert them to text/css
                // do the same for javascript files
                if mime == "text/plain" {
                    let e = file_path.extension().unwrap_or_default();
                    if e == "css" {
                        "text/css".to_owned()
                    } else if e == "js" {
                        "application/javascript".to_owned()
                    } else {
                        mime.to_owned()
                    }
                } else {
                    mime.to_owned()
                }
            };

            let content: Option<Vec<u8>> = if let Some(client) = &client {
                let s3_res = client.put_object(PutObjectRequest {
                    bucket: "rust-docs-rs".into(),
                    key: bucket_path.clone(),
                    body: Some(content.clone().into()),
                    content_type: Some(mime.clone()),
                    ..Default::default()
                }).sync();
                match s3_res {
                    // we've successfully uploaded the content, so steal it;
                    // we don't want to put it in the DB
                    Ok(_) => None,
                    // Since s3 was configured, we want to panic on failure to upload.
                    Err(e) => {
                        panic!("failed to upload to {}: {:?}", bucket_path, e)
                    },
                }
            } else {
                Some(content.clone().into())
            };

            file_list_with_mimes.push((mime.clone(), file_path.clone()));

            (
                bucket_path,
                content,
                mime,
            )
        };

        // If AWS credentials are configured, don't insert/update the database
        if client.is_none() {
            // check if file already exists in database
            let rows = try!(conn.query("SELECT COUNT(*) FROM files WHERE path = $1", &[&path]));

            let content = content.expect("content never None if client is None");

            if rows.get(0).get::<usize, i64>(0) == 0 {
                try!(trans.query("INSERT INTO files (path, mime, content) VALUES ($1, $2, $3)",
                                &[&path, &mime, &content]));
            } else {
                try!(trans.query("UPDATE files SET mime = $2, content = $3, date_updated = NOW() \
                                WHERE path = $1",
                                &[&path, &mime, &content]));
            }
        }
    }

    try!(trans.commit());

    file_list_to_json(file_list_with_mimes)
}

fn file_list_to_json(file_list: Vec<(String, PathBuf)>) -> Result<Json> {

    let mut file_list_json: Vec<Json> = Vec::new();

    for file in file_list {
        let mut v: Vec<String> = Vec::new();
        v.push(file.0.clone());
        v.push(file.1.into_os_string().into_string().unwrap());
        file_list_json.push(v.to_json());
    }

    Ok(file_list_json.to_json())
}

pub fn move_to_s3(conn: &Connection, n: usize) -> Result<usize> {
    let trans = try!(conn.transaction());
    let client = s3_client().expect("configured s3");

    let rows = try!(trans.query(
            &format!("SELECT path, mime, content FROM files WHERE content != E'in-s3' LIMIT {}", n),
            &[]));
    let count = rows.len();

    let mut rt = ::tokio::runtime::current_thread::Runtime::new().unwrap();
    let mut futures = Vec::new();
    for row in &rows {
        let path: String = row.get(0);
        let mime: String = row.get(1);
        let content: Vec<u8> = row.get(2);
        let path_1 = path.clone();
        futures.push(client.put_object(PutObjectRequest {
            bucket: "rust-docs-rs".into(),
            key: path.clone(),
            body: Some(content.into()),
            content_type: Some(mime),
            ..Default::default()
        }).map(move |_| {
            path_1
        }).map_err(move |e| {
            panic!("failed to upload to {}: {:?}", path, e)
        }));
    }

    use ::futures::future::Future;
    match rt.block_on(::futures::future::join_all(futures)) {
        Ok(paths) => {
            let statement = trans.prepare("DELETE FROM files WHERE path = $1").unwrap();
            for path in paths {
                statement.execute(&[&path]).unwrap();
            }
        }
        Err(e) => {
            panic!("results err: {:?}", e);
        }
    }

    try!(trans.commit());

    Ok(count)
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::env;
    use super::get_file_list;

    #[test]
    fn test_get_file_list() {
        let _ = env_logger::try_init();

        let files = get_file_list(env::current_dir().unwrap());
        assert!(files.is_ok());
        assert!(files.unwrap().len() > 0);

        let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
        assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
    }
}
<|endoftext|>


<commit_before>use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    if msg.len() == 0 {
        return Err(OscError::BadPacket("Empty packet."));
    }

    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let bundle_tag = try!(read_osc_string(&mut cursor));
    if bundle_tag != "#bundle" {
        return Err(OscError::BadBundle(format!("Wrong bundle specifier: {}", bundle_tag)));
    }

    let time_tag = try!(read_time_tag(&mut cursor));

    let mut bundle: Vec<OscPacket> = Vec::new();

    let mut elem_size = try!(read_bundle_element_size(&mut cursor));

    while msg.len() >= (cursor.position() as usize) + elem_size {
        let packet = try!(read_bundle_element(&mut cursor, elem_size));
        bundle.push(packet);

        if msg.len() == cursor.position() as usize {
            break;
        }

        elem_size = try!(read_bundle_element_size(&mut cursor));
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_bundle_element_size(cursor: &mut io::Cursor<&[u8]>) -> Result<usize> {
    cursor.read_u32::<BigEndian>()
          .map(|size| size as usize)
          .map_err(OscError::ByteOrderError)
}

fn read_bundle_element(cursor: &mut io::Cursor<&[u8]>, elem_size: usize) -> Result<OscPacket> {
    let mut buf: Vec<u8> = Vec::with_capacity(elem_size);

    let mut handle = cursor.take(elem_size as u64);

    let cnt = try!(handle.read_to_end(&mut buf)
                         .map_err(OscError::ReadError));

    if cnt == elem_size {
        decode(&mut buf)
    } else {
        return Err(OscError::BadBundle("Bundle shorter than expected!".to_string()));
    }
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();

    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            read_blob(cursor)
        }
        'r' => {
            read_osc_color(cursor)
        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            read_char(cursor)
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Remove unnecessary `return`<commit_after>use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    if msg.len() == 0 {
        return Err(OscError::BadPacket("Empty packet."));
    }

    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let bundle_tag = try!(read_osc_string(&mut cursor));
    if bundle_tag != "#bundle" {
        return Err(OscError::BadBundle(format!("Wrong bundle specifier: {}", bundle_tag)));
    }

    let time_tag = try!(read_time_tag(&mut cursor));

    let mut bundle: Vec<OscPacket> = Vec::new();

    let mut elem_size = try!(read_bundle_element_size(&mut cursor));

    while msg.len() >= (cursor.position() as usize) + elem_size {
        let packet = try!(read_bundle_element(&mut cursor, elem_size));
        bundle.push(packet);

        if msg.len() == cursor.position() as usize {
            break;
        }

        elem_size = try!(read_bundle_element_size(&mut cursor));
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_bundle_element_size(cursor: &mut io::Cursor<&[u8]>) -> Result<usize> {
    cursor.read_u32::<BigEndian>()
          .map(|size| size as usize)
          .map_err(OscError::ByteOrderError)
}

fn read_bundle_element(cursor: &mut io::Cursor<&[u8]>, elem_size: usize) -> Result<OscPacket> {
    let mut buf: Vec<u8> = Vec::with_capacity(elem_size);

    let mut handle = cursor.take(elem_size as u64);

    let cnt = try!(handle.read_to_end(&mut buf)
                         .map_err(OscError::ReadError));

    if cnt == elem_size {
        decode(&mut buf)
    } else {
        Err(OscError::BadBundle("Bundle shorter than expected!".to_string()))
    }
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();

    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            read_blob(cursor)
        }
        'r' => {
            read_osc_color(cursor)
        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            read_char(cursor)
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>use std::thread;
use std::io;
use std::io::Read;
use std::sync::mpsc;
use std::sync::mpsc::{SyncSender, Receiver};
use std::default::Default;
use std::marker::Send;
use self::mad_decoder_mode::* ;
use std::option::Option::{None, Some};
use libc::types::common::c95::c_void;
use libc::types::common::c99::*;
use libc::types::os::arch::c95::*;

#[allow(unused)]
#[repr(C)]
static mut input_buffer: [u8; 16384] = [0; 16384];

#[allow(unused, improper_ctypes)]
#[link(name = "mad")]
extern {
    fn mad_decoder_init(decoder: *mut mad_decoder,
                        message: *mut c_void,
                        input_callback: extern fn(message: *mut MadMessage,
                                                  stream: &mad_stream) -> mad_flow,
                        header_callback: extern fn(),
                        filter_callback: extern fn(),
                        output_callback: extern fn(message: *mut MadMessage,
                                                   header: c_int,
                                                   pcm: &mad_pcm) -> mad_flow,
                        error_callback: extern fn(message: *mut MadMessage,
                                                  stream: &mad_stream,
                                                  frame: c_int) -> mad_flow,
                        message_callback: extern fn());
    #[allow(dead_code)]
    fn mad_decoder_run(input: &mut mad_decoder, mode: mad_decoder_mode) -> c_int;
    fn mad_stream_buffer(stream: &mad_stream, buf_start: *const u8, buf_length: size_t);
}

#[allow(unused)]
#[repr(C)]
enum mad_flow {
    mf_continue = 0x0000,    /* continue normally */
    mf_stop     = 0x0010,    /* stop decoding normally */
    mf_break    = 0x0011,    /* stop decoding and signal an error */
    mf_ignore   = 0x0020    /* ignore the current frame */
}

#[allow(unused)]
#[derive(Debug)]
#[repr(C)]
enum mad_error {
  mad_error_none           = 0x0000,    /* no error */

  mad_error_buflen         = 0x0001,    /* input buffer too small (or eof) */
  mad_error_bufptr         = 0x0002,    /* invalid (null) buffer pointer */

  mad_error_nomem          = 0x0031,    /* not enough memory */

  mad_error_lostsync       = 0x0101,    /* lost synchronization */
  mad_error_badlayer       = 0x0102,    /* reserved header layer value */
  mad_error_badbitrate     = 0x0103,    /* forbidden bitrate value */
  mad_error_badsamplerate  = 0x0104,    /* reserved sample frequency value */
  mad_error_bademphasis    = 0x0105,    /* reserved emphasis value */

  mad_error_badcrc         = 0x0201,    /* crc check failed */
  mad_error_badbitalloc    = 0x0211,    /* forbidden bit allocation value */
  mad_error_badscalefactor = 0x0221,    /* bad scalefactor index */
  mad_error_badmode        = 0x0222,    /* bad bitrate/mode combination */
  mad_error_badframelen    = 0x0231,    /* bad frame length */
  mad_error_badbigvalues   = 0x0232,    /* bad big_values count */
  mad_error_badblocktype   = 0x0233,    /* reserved block_type */
  mad_error_badscfsi       = 0x0234,    /* bad scalefactor selection info */
  mad_error_baddataptr     = 0x0235,    /* bad main_data_begin pointer */
  mad_error_badpart3len    = 0x0236,    /* bad audio data length */
  mad_error_badhufftable   = 0x0237,    /* bad huffman table select */
  mad_error_badhuffdata    = 0x0238,    /* huffman data overrun */
  mad_error_badstereo      = 0x0239,    /* incompatible block_type for js */
}

#[allow(unused)]
#[repr(C)]
struct mad_bitptr {
    byte: size_t,
    cache: uint16_t,
    left: uint16_t,
}

#[allow(unused)]
#[repr(C)]
struct mad_stream {
    buffer: size_t,
    buff_end: size_t,
    skip_len: c_ulong,
    sync: c_int,
    free_rate: c_ulong,
    this_frame: size_t,
    next_frame: size_t,
    ptr: mad_bitptr,
    anc_ptr: mad_bitptr,
    anc_bitlen: c_uint,
    buffer_mdlen: size_t,
    md_len: c_uint,
    options: c_int,
    error: mad_error,
}

#[allow(unused)]
#[repr(C)]
struct mad_pcm {
    sample_rate: c_uint,
    channels: uint16_t,
    length: uint16_t,
    samples: [[int32_t; 1152]; 2],
}

#[allow(unused)]
struct MadMessage<'a> {
    buffer: &'static mut [u8; 16384],
    reader: &'a mut (io::Read + 'a),
    sender: &'a SyncSender<Frame>,
}

#[allow(unused)]
#[repr(C)]
enum mad_decoder_mode {
    MAD_DECODER_MODE_SYNC = 0,
    MAD_DECODER_MODE_ASYNC
}

impl Default for mad_decoder_mode {
    fn default() -> mad_decoder_mode {MAD_DECODER_MODE_SYNC}
}

#[derive(Default)]
#[repr(C)]
struct mad_async_parameters {
    pid: u64,
    ain: u32,
    aout: u32,
}

#[derive(Default)]
#[repr(C)]
struct mad_decoder {
    mode: mad_decoder_mode,
    options: c_int,
    async: mad_async_parameters,
    sync: size_t,
    cb_data: size_t,
    input_func: size_t,
    header_func: size_t,
    filter_func: size_t,
    output_func: size_t,
    error_func: size_t,
    message_func: size_t,
}

#[allow(unused)]
pub struct Frame {
    pub sample_rate: u32,
    pub channels: uint16_t,
    pub length: uint16_t,
    pub samples: [[i32; 1152]; 2],
}

#[allow(unused)]
extern fn empty_callback() {

}

#[allow(unused)]
extern fn input_callback (msg: *mut MadMessage, stream: &mad_stream) -> mad_flow {
    unsafe {
        let buffer_size = (*msg).buffer.len();
        let next_frame_position = (stream.next_frame - stream.buffer) as usize;
        let unused_byte_count = buffer_size - next_frame_position;

        if unused_byte_count > 0 {
            for idx in 0 .. unused_byte_count {
                (*msg).buffer[idx] = (*msg).buffer[idx + next_frame_position];
            }
        }

        let mut bytes_read = None;

        if next_frame_position == 0 {
            bytes_read = Some((*msg).reader.read((*msg).buffer).unwrap());
        } else {
            let slice = &mut (*msg).buffer[unused_byte_count .. buffer_size];
            bytes_read = Some((*msg).reader.read(slice).unwrap());
        }

        match bytes_read {
            None    => return mad_flow::mf_stop,
            Some(0) => return mad_flow::mf_stop,
            Some(n) => mad_stream_buffer(stream, (*msg).buffer.as_ptr(), n as u64),
        }
    }

    mad_flow::mf_continue
}

#[allow(unused)]
extern fn error_callback(msg: *mut MadMessage,
                         stream: &mad_stream,
                         frame: c_int) -> mad_flow
{
    mad_flow::mf_continue
}

#[allow(unused)]
extern fn output_callback(msg: *mut MadMessage,
                          header: c_int,
                          pcm: &mad_pcm) -> mad_flow
{
    unsafe {
        (*msg).sender.send(Frame {sample_rate: pcm.sample_rate,
                                  channels: pcm.channels,
                                  length: pcm.length,
                                  samples: pcm.samples});
    }
    mad_flow::mf_continue
}

#[allow(unused)]
pub fn decode<T>(mut reader: T) -> Receiver<Frame>
    where T: io::Read + Send + 'static {
    let (tx, rx) = mpsc::sync_channel::<Frame>(0);
    thread::spawn(move || {
        unsafe {
            let mut message = MadMessage {
                buffer: &mut input_buffer,
                reader: &mut reader,
                sender: &tx,
            };
            let message_ptr = &mut message as *mut _ as *mut c_void;
            let mut decoder: mad_decoder = Default::default();
            mad_decoder_init(&mut decoder,
                             message_ptr,
                             input_callback,
                             empty_callback,
                             empty_callback,
                             output_callback,
                             error_callback,
                             empty_callback);
            mad_decoder_run(&mut decoder, mad_decoder_mode::MAD_DECODER_MODE_SYNC);
        }
    });
    rx
}

#[test]
fn data_sizes() {
    use std::mem::size_of;
    assert_eq!(size_of::<mad_bitptr>(), 16);
    assert_eq!(size_of::<mad_error>(), 4);
    assert_eq!(size_of::<mad_decoder>(), 88);
    assert_eq!(size_of::<mad_pcm>(), 9224);
    assert_eq!(size_of::<mad_stream>(), 120);
}

#[test]
fn test_short_file() {
    use std::path::Path;
    use std::fs::File;
    println!("");
    let path = Path::new("test_samples/tailtoddle_lo.mp3");
    let f = File::open(&path).unwrap();
    let decoder = decode(f);
    let mut frame_count = 0;
    for _ in decoder.iter() {
        frame_count += 1;
    }
    assert_eq!(frame_count, 1656);
}

<commit_msg>Added error propagation<commit_after>use std::thread;
use std::io;
use std::io::Read;
use std::sync::mpsc;
use std::sync::mpsc::{SyncSender, Receiver};
use std::default::Default;
use std::marker::Send;
use self::mad_decoder_mode::* ;
use std::option::Option::{None, Some};
use libc::types::common::c95::c_void;
use libc::types::common::c99::*;
use libc::types::os::arch::c95::*;

#[allow(unused)]
#[repr(C)]
static mut input_buffer: [u8; 16384] = [0; 16384];

#[allow(unused, improper_ctypes)]
#[link(name = "mad")]
extern {
    fn mad_decoder_init(decoder: *mut mad_decoder,
                        message: *mut c_void,
                        input_callback: extern fn(message: *mut MadMessage,
                                                  stream: &mad_stream) -> mad_flow,
                        header_callback: extern fn(),
                        filter_callback: extern fn(),
                        output_callback: extern fn(message: *mut MadMessage,
                                                   header: c_int,
                                                   pcm: &mad_pcm) -> mad_flow,
                        error_callback: extern fn(message: *mut MadMessage,
                                                  stream: &mad_stream,
                                                  frame: c_int) -> mad_flow,
                        message_callback: extern fn());
    #[allow(dead_code)]
    fn mad_decoder_run(input: &mut mad_decoder, mode: mad_decoder_mode) -> c_int;
    fn mad_stream_buffer(stream: &mad_stream, buf_start: *const u8, buf_length: size_t);
}

#[allow(unused)]
#[repr(C)]
enum mad_flow {
    mf_continue = 0x0000,    /* continue normally */
    mf_stop     = 0x0010,    /* stop decoding normally */
    mf_break    = 0x0011,    /* stop decoding and signal an error */
    mf_ignore   = 0x0020    /* ignore the current frame */
}

#[allow(unused)]
#[derive(Debug, Clone)]
#[repr(C)]
pub enum Error {
  mad_error_none           = 0x0000,    /* no error */

  mad_error_buflen         = 0x0001,    /* input buffer too small (or eof) */
  mad_error_bufptr         = 0x0002,    /* invalid (null) buffer pointer */

  mad_error_nomem          = 0x0031,    /* not enough memory */

  mad_error_lostsync       = 0x0101,    /* lost synchronization */
  mad_error_badlayer       = 0x0102,    /* reserved header layer value */
  mad_error_badbitrate     = 0x0103,    /* forbidden bitrate value */
  mad_error_badsamplerate  = 0x0104,    /* reserved sample frequency value */
  mad_error_bademphasis    = 0x0105,    /* reserved emphasis value */

  mad_error_badcrc         = 0x0201,    /* crc check failed */
  mad_error_badbitalloc    = 0x0211,    /* forbidden bit allocation value */
  mad_error_badscalefactor = 0x0221,    /* bad scalefactor index */
  mad_error_badmode        = 0x0222,    /* bad bitrate/mode combination */
  mad_error_badframelen    = 0x0231,    /* bad frame length */
  mad_error_badbigvalues   = 0x0232,    /* bad big_values count */
  mad_error_badblocktype   = 0x0233,    /* reserved block_type */
  mad_error_badscfsi       = 0x0234,    /* bad scalefactor selection info */
  mad_error_baddataptr     = 0x0235,    /* bad main_data_begin pointer */
  mad_error_badpart3len    = 0x0236,    /* bad audio data length */
  mad_error_badhufftable   = 0x0237,    /* bad huffman table select */
  mad_error_badhuffdata    = 0x0238,    /* huffman data overrun */
  mad_error_badstereo      = 0x0239,    /* incompatible block_type for js */
}

#[allow(unused)]
#[repr(C)]
struct mad_bitptr {
    byte: size_t,
    cache: uint16_t,
    left: uint16_t,
}

#[allow(unused)]
#[repr(C)]
struct mad_stream {
    buffer: size_t,
    buff_end: size_t,
    skip_len: c_ulong,
    sync: c_int,
    free_rate: c_ulong,
    this_frame: size_t,
    next_frame: size_t,
    ptr: mad_bitptr,
    anc_ptr: mad_bitptr,
    anc_bitlen: c_uint,
    buffer_mdlen: size_t,
    md_len: c_uint,
    options: c_int,
    error: Error,
}

#[allow(unused)]
#[repr(C)]
struct mad_pcm {
    sample_rate: c_uint,
    channels: uint16_t,
    length: uint16_t,
    samples: [[int32_t; 1152]; 2],
}

#[allow(unused)]
struct MadMessage<'a> {
    buffer: &'static mut [u8; 16384],
    reader: &'a mut (io::Read + 'a),
    sender: &'a SyncSender<Result<Frame, Error>>,
}

#[allow(unused)]
#[repr(C)]
enum mad_decoder_mode {
    MAD_DECODER_MODE_SYNC = 0,
    MAD_DECODER_MODE_ASYNC
}

impl Default for mad_decoder_mode {
    fn default() -> mad_decoder_mode {MAD_DECODER_MODE_SYNC}
}

#[derive(Default)]
#[repr(C)]
struct mad_async_parameters {
    pid: c_long,
    ain: c_int,
    aout: c_int,
}

#[derive(Default)]
#[repr(C)]
struct mad_decoder {
    mode: mad_decoder_mode,
    options: c_int,
    async: mad_async_parameters,
    sync: size_t,
    cb_data: size_t,
    input_func: size_t,
    header_func: size_t,
    filter_func: size_t,
    output_func: size_t,
    error_func: size_t,
    message_func: size_t,
}

#[allow(unused)]
pub struct Frame {
    pub sample_rate: u32,
    pub channels: uint16_t,
    pub length: uint16_t,
    pub samples: [[i32; 1152]; 2],
}

#[allow(unused)]
extern fn empty_callback() {

}

#[allow(unused)]
extern fn input_callback (msg: *mut MadMessage, stream: &mad_stream) -> mad_flow {
    unsafe {
        let buffer_size = (*msg).buffer.len();
        let next_frame_position = (stream.next_frame - stream.buffer) as usize;
        let unused_byte_count = buffer_size - next_frame_position;

        if unused_byte_count > 0 {
            for idx in 0 .. unused_byte_count {
                (*msg).buffer[idx] = (*msg).buffer[idx + next_frame_position];
            }
        }

        let mut bytes_read = None;

        if next_frame_position == 0 {
            bytes_read = Some((*msg).reader.read((*msg).buffer).unwrap());
        } else {
            let slice = &mut (*msg).buffer[unused_byte_count .. buffer_size];
            bytes_read = Some((*msg).reader.read(slice).unwrap());
        }

        match bytes_read {
            None    => return mad_flow::mf_stop,
            Some(0) => return mad_flow::mf_stop,
            Some(n) => mad_stream_buffer(stream, (*msg).buffer.as_ptr(), n as u64),
        }
    }

    mad_flow::mf_continue
}

#[allow(unused)]
extern fn error_callback(msg: *mut MadMessage,
                         stream: &mad_stream,
                         frame: c_int) -> mad_flow
{
    unsafe {
        let error_type = stream.error.clone();
        (*msg).sender.send(Err(error_type));
    }
    mad_flow::mf_continue
}

#[allow(unused)]
extern fn output_callback(msg: *mut MadMessage,
                          header: c_int,
                          pcm: &mad_pcm) -> mad_flow
{
    unsafe {
        let frame = Ok(Frame {sample_rate: pcm.sample_rate,
                              channels: pcm.channels,
                              length: pcm.length,
                              samples: pcm.samples});
        (*msg).sender.send(frame);
    }
    mad_flow::mf_continue
}

#[allow(unused)]
pub fn decode<T>(mut reader: T) -> Receiver<Result<Frame, Error>>
    where T: io::Read + Send + 'static {
    let (tx, rx): (SyncSender<Result<Frame, Error>>, Receiver<Result<Frame, Error>>) = mpsc::sync_channel::<Result<Frame, Error>>(2);
    thread::spawn(move || {
        unsafe {
            let mut message = MadMessage {
                buffer: &mut input_buffer,
                reader: &mut reader,
                sender: &tx,
            };
            let message_ptr = &mut message as *mut _ as *mut c_void;
            let mut decoder: mad_decoder = Default::default();
            mad_decoder_init(&mut decoder,
                             message_ptr,
                             input_callback,
                             empty_callback,
                             empty_callback,
                             output_callback,
                             error_callback,
                             empty_callback);
            mad_decoder_run(&mut decoder, mad_decoder_mode::MAD_DECODER_MODE_SYNC);
        }
    });
    rx
}

#[test]
fn data_sizes() {
    use std::mem::size_of;
    assert_eq!(size_of::<mad_bitptr>(), 16);
    assert_eq!(size_of::<Error>(), 4);
    assert_eq!(size_of::<mad_decoder>(), 88);
    assert_eq!(size_of::<mad_pcm>(), 9224);
    assert_eq!(size_of::<mad_stream>(), 120);
}

#[test]
fn test_short_file() {
    use std::path::Path;
    use std::fs::File;
    let path = Path::new("test_samples/tailtoddle_lo.mp3");
    let f = File::open(&path).unwrap();
    let decoder = decode(f);
    let mut frame_count = 0;
    let mut error_count = 0;
    for frame in decoder.iter() {
        match frame {
            Ok(_) => frame_count += 1,
            Err(_) => error_count += 1,
        }
    }
    assert_eq!(frame_count, 1656);
    assert_eq!(error_count, 1);
}

<|endoftext|>