<commit_before>use std::cmp::Ordering;
use std::mem;

#[derive(PartialEq, Eq)]
enum Color {
    Red,
    Black,
}

type Link = Box<Node>;
type LinkOrEmpty = Option<Link>;

pub struct RBTree {
    root: LinkOrEmpty,
}

struct Node {
    key: i32,
    val: i32,
    color: Color,
    left: LinkOrEmpty,
    right: LinkOrEmpty,
}

impl RBTree {

    pub fn new() -> Self {
        RBTree { root: None }
    }

    pub fn get(&self, key: i32) -> Option<i32> {
        self.root.get(key)
    }

    pub fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = self.root.insert(key, value);
        self.root.as_mut().unwrap().color = Color::Black;
        prev
    }

}

fn new_leaf(key: i32, val: i32) -> LinkOrEmpty {
    Some(Box::new(Node::new(key, val)))
}

impl Node {

    fn new(key: i32, val: i32) -> Self {
        Node {
            key: key,
            val: val,
            color: Color::Red,
            left: None,
            right: None,
        }
    }

}

trait BoxNode {
    fn left_rotate(&mut self) -> ();
}

impl BoxNode for Link {

    fn left_rotate(&mut self) -> () {
        let mut y = self.right.take().unwrap();
        mem::swap(&mut self.right, &mut y.left);
        mem::swap(self, &mut y.left.take().unwrap());
    }
}

trait PtrNode {
    fn get(&self, key: i32) -> Option<i32>;
    fn insert(&mut self, key: i32, val: i32) -> Option<i32>;
}

impl PtrNode for LinkOrEmpty {

    fn get(&self, key: i32) -> Option<i32> {
        match *self {
            None => None,
            Some(ref node) => match key.cmp(&node.key) {
                Ordering::Equal => Some(node.val),
                Ordering::Less => node.left.get(key),
                Ordering::Greater => node.right.get(key)
            }
        }
    }

    fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        match *self {
            None => {
                *self = new_leaf(key, value);
                None
            },
            Some(ref mut node) => {
                match key.cmp(&node.key) {
                    Ordering::Equal => {
                        let prev = node.val;
                        node.val = value;
                        Some(prev)
                    },
                    Ordering::Less => node.left.insert(key, value),
                    Ordering::Greater => node.right.insert(key, value),
                }
            }
        }
    }

}

#[test]
fn basic_construction() {
    let mut tree = RBTree::new();
    assert_eq!(tree.get(0), None);
    assert_eq!(tree.insert(0, 1), None);
    assert_eq!(tree.insert(0, 2), Some(1));
    assert_eq!(tree.get(0), Some(2));
 }
<commit_msg>Simplify initial implementation.<commit_after>//! A naive implementation of left-leaning red-black trees
//! that are isomorphic to 2-3 trees. This implementation
//! borrows heavily from https://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf
//! and https://github.com/rcatolino/rbtree-rust.

use std::cmp::Ordering;
use std::mem;

#[derive(PartialEq, Eq, Copy, Clone)]
enum Color {
    Red,
    Black,
}

pub struct RBTree {
    root: Option<Box<Node>>,
}

struct Node {
    key: i32,
    val: i32,
    color: Color,
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
}

impl Color {
    fn flip(self) -> Color {
        match self {
            Color::Red => Color::Black,
            Color::Black => Color::Red
        }
    }
}

impl RBTree {

    pub fn new() -> Self {
        RBTree { root: None }
    }

    pub fn get(&self, key: i32) -> Option<i32> {
        self.root.get(key)
    }

    pub fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = self.root.insert(key, value);
        self.root.mutate().color = Color::Black;
        prev
    }

    #[allow(dead_code)]
    fn to_string(&self) -> String {
        to_string(&self.root)
    }

}

fn new_leaf(key: i32, val: i32) -> Option<Box<Node>> {
    Some(Box::new(Node::new(key, val)))
}

impl Node {

    fn new(key: i32, val: i32) -> Self {
        Node {
            key: key,
            val: val,
            color: Color::Red,
            left: None,
            right: None,
        }
    }

}

trait Link {
    fn left_rotate(&mut self);
    fn right_rotate(&mut self);
    fn flip_colors(&mut self);
}

impl Link for Box<Node> {

    fn left_rotate(&mut self) {
        let mut child = self.right.take().unwrap();
        mem::swap(self, &mut child);
        mem::swap(&mut child.right, &mut self.left);
        self.color = child.color;
        child.color = Color::Red;
        self.left = Some(child);
    }

    fn right_rotate(&mut self) {
        let mut child = self.left.take().unwrap();
        mem::swap(self, &mut child);
        mem::swap(&mut child.left, &mut self.right);
        self.color = child.color;
        child.color = Color::Red;
        self.right = Some(child);
    }

    fn flip_colors(&mut self) {
        self.color.flip();
        self.left.mutate().color.flip();
        self.right.mutate().color.flip();
    }
}

trait OptionLink {
    fn get(&self, key: i32) -> Option<i32>;
    fn is_red(&self) -> bool;
    fn insert(&mut self, key: i32, val: i32) -> Option<i32>;
    fn reference(&mut self) -> & Box<Node>;
    fn mutate(&mut self) -> &mut Box<Node>;
}

impl OptionLink for Option<Box<Node>> {

    fn get(&self, key: i32) -> Option<i32> {
        match *self {
            None => None,
            Some(ref node) => match key.cmp(&node.key) {
                Ordering::Equal => Some(node.val),
                Ordering::Less => node.left.get(key),
                Ordering::Greater => node.right.get(key)
            }
        }
    }

    fn is_red(&self) -> bool {
        match *self {
            None => false,
            Some(ref node) => (node.color == Color::Red)
        }
    }

    fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = match *self {
            None => {
                *self = new_leaf(key, value);
                None
            },
            Some(ref mut node) => {
                match key.cmp(&node.key) {
                    Ordering::Equal => {
                        let prev = node.val;
                        node.val = value;
                        Some(prev)
                    },
                    Ordering::Less => node.left.insert(key, value),
                    Ordering::Greater => node.right.insert(key, value),
                }
            }
        };
        let ref mut node = self.mutate();
        if !node.left.is_red() && node.right.is_red() {
            node.left_rotate();
        }
        if node.left.is_red() && node.left.reference().left.is_red() {
            node.right_rotate();
        }
        if node.left.is_red() && node.right.is_red() {
            node.flip_colors();
        }
        prev
    }

    fn reference(&mut self) -> & Box<Node> {
        self.as_ref().unwrap()
    }

    fn mutate(&mut self) -> &mut Box<Node> {
        self.as_mut().unwrap()
    }

}

#[allow(dead_code)]
fn to_string(link: &Option<Box<Node>>) -> String {
    match *link {
        None => String::from("nil"),
        Some(ref node) => format!("{} ({}) ({})",
            node.key,
            to_string(&node.left),
            to_string(&node.right))
    }
}

#[test]
fn basic_construction() {
    let mut tree = RBTree::new();
    assert_eq!(tree.get(0), None);
    assert_eq!(tree.insert(0, 1), None);
    assert_eq!(tree.insert(0, 2), Some(1));
    assert_eq!(tree.get(0), Some(2));
 }
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Error};

#[derive(Clone, Debug)]
pub enum StoreAction {
    Create,
    Retrieve,
    Update,
    Delete,
}

impl Display for StoreAction {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "StoreAction: {}",
                match *self {
                    StoreAction::Create   => "create",
                    StoreAction::Retrieve => "retrieve",
                    StoreAction::Update   => "update",
                    StoreAction::Delete   => "delete",
                })
    }

}

<commit_msg>Add StoreAction::uppercase() utility function<commit_after>use std::fmt::{Display, Formatter, Error};

#[derive(Clone, Debug)]
pub enum StoreAction {
    Create,
    Retrieve,
    Update,
    Delete,
}

impl StoreAction {

    pub fn uppercase(&self) -> &str {
        match *self {
            StoreAction::Create   => "CREATE",
            StoreAction::Retrieve => "RETRIEVE",
            StoreAction::Update   => "UPDATE",
            StoreAction::Delete   => "DELETE",
        }
    }
}

impl Display for StoreAction {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "StoreAction: {}",
                match *self {
                    StoreAction::Create   => "create",
                    StoreAction::Retrieve => "retrieve",
                    StoreAction::Update   => "update",
                    StoreAction::Delete   => "delete",
                })
    }

}

<|endoftext|>


<commit_before>use std::io::File;
use std::io::IoErrorKind::EndOfFile;
use std::cmp::max;
use self::Action::*;

macro_rules! get_memory {
    ($foo: ident, $addr: expr) => {
        match $foo.memory.memory_space.get($addr as uint) {
            Some(&x) => x,
            None => return None,
        }
    };
    ($foo: ident, $addr: expr, $rval: expr) => {
        match $foo.memory.memory_space.get($addr as uint) {
            Some(&x) => x,
            None => return $rval,
        }
    };
}

struct Memory {
    data_stack: Vec<i32>,
    address_stack: Vec<i32>,
    memory_space: Vec<i32>,
}

impl Memory {
    fn new(path: &Path) -> Memory {
        let mut file = File::open(path).unwrap();
        let size = file.stat().unwrap().size / 4;
        let mut memory = Vec::with_capacity(max(size as uint, 1024*1024)); // 4MB or image size

        loop {
            match file.read_le_i32() {
                Ok(x) => memory.push(x),
                Err(ref e) if e.kind == EndOfFile => break,
                Err(e) => panic!(e),
            }
        }
        Memory {
            data_stack: Vec::new(),
            address_stack: Vec::new(),
            memory_space: memory
        }
    }
}

pub struct Ports<'a> {
    ports: &'a mut [i32]
}

#[unsafe_destructor]
impl<'a> Drop for Ports<'a> {
    fn drop(&mut self) {
        self.ports.get_mut(0).map(|x| *x = 1);
    }
}

impl<'a> Deref<[i32]> for Ports<'a> {
    fn deref(&self) -> &[i32] {
        &*self.ports
    }
}

impl<'a> DerefMut<[i32]> for Ports<'a> {
    fn deref_mut(&mut self) -> &mut [i32] {
        self.ports
    }
}

pub struct Info {
    pub memory_size: i32,
    pub data_stack_depth: i32,
    pub address_stack_depth: i32,
}

pub struct CPU {
    memory: Memory,
    ip: i32,
    ports: [i32, ..12]
}

impl CPU {
    pub fn new(path: &Path) -> CPU {
        CPU {
            memory: Memory::new(path),
            ip: 0,
            ports: [0, ..12],
        }
    }

    pub fn ports_and_stack<'a>(&'a mut self) -> (Ports<'a>, &'a mut Vec<i32>) {
        let ports = Ports { ports: self.ports.as_mut_slice() };
        let stack = &mut self.memory.data_stack;
        (ports, stack)
    }

    pub fn get_info(&self) -> Info {
        Info {
            memory_size: self.memory.memory_space.len() as i32,
            data_stack_depth: self.memory.data_stack.len() as i32,
            address_stack_depth: self.memory.address_stack.len() as i32,
        }
    }

    pub fn pop_data(&mut self) -> i32 {
        self.memory.data_stack.pop().expect("Data stack underflow.")
    }

    pub fn push_data(&mut self, data: i32) {
        println!("{}", self.memory.data_stack);
        self.memory.data_stack.push(data)
    }

    fn pop_address(&mut self) -> i32 {
        self.memory.address_stack.pop().expect("Address stack underflow.")
    }

    fn push_address(&mut self, data: i32) {
        self.memory.address_stack.push(data)
    }

    fn jump(&mut self) {
        self.ip += 1;
        self.ip = get_memory!(self, self.ip, panic!("Jump out of bounds.")) - 1;
    }

    fn cond_stack_jump(&mut self, cond: |i32, i32| -> bool) {
        let (a, b) = (self.pop_data(), self.pop_data());
        if cond(a,b) { self.jump() } else { self.ip += 1; }
    }

    fn pop_2_push_1(&mut self, func: |i32, i32| -> i32) {
        let (a, b) = (self.pop_data(), self.pop_data());
        self.push_data(func(a,b));
    }
}

impl Iterator<Action> for CPU {
    fn next(&mut self) -> Option<Action> {
        let mut result = Empty;
        /* println!("IP: {} Instr: {} Data Depth: {} Address Depth: {}",
                 self.ip,
                 self.memory.memory_space.get(self.ip as uint).map(|&x| opcode_to_name(x)),
                 self.memory.data_stack.len(),
                 self.memory.address_stack.len()); // */
        match get_memory!(self, self.ip) {
            0 => { } // NOP
            1 => { // LIT X
                self.ip += 1;
                let data = get_memory!(self, self.ip);
                self.push_data(data);
            }
            2 => { // DUP
                let item = self.pop_data();
                self.push_data(item);
                self.push_data(item);
            }
            3 => { // DROP
                self.pop_data();
            }
            4 => { // SWAP
                let (a, b) = (self.pop_data(), self.pop_data());
                self.push_data(a);
                self.push_data(b);
            }
            5 => { // PUSH
                let data = self.pop_data();
                self.push_address(data);
            }
            6 => { // POP
                let data = self.pop_address();
                self.push_data(data);
            }
            7 => { // LOOP A
                let mut data = self.pop_data();
                self.ip += 1;
                data -= 1;
                if data > 0 {
                    self.jump();
                    self.push_data(data);
                }
            }
            8 => { // JUMP A
                self.jump();
            }
            9 => { // RETURN
                let addr = self.pop_address();
                self.ip = addr;
            }
            10 => { // LT_JUMP
                self.cond_stack_jump(|a, b| a < b);
            }
            11 => { // GT_JUMP
                self.cond_stack_jump(|a, b| a > b);
            }
            12 => { // NE_JUMP
                self.cond_stack_jump(|a, b| a != b);
            }
            13 => { // EQ_JUMP
                self.cond_stack_jump(|a, b| a == b);
            }
            14 => { // FETCH
                let addr = self.pop_data();
                let data = *self.memory.memory_space.get(addr as uint).expect("FETCH beyond bounds.");
                self.push_data(data);
            }
            15 => { // STORE
                let (addr, data) = (self.pop_data(), self.pop_data());
                println!("Addr: {} Data: {}", addr, data);
                *self.memory.memory_space.get_mut(addr as uint).expect("STORE beyond bounds.") = data;
            }
            16 => { // ADD
                self.pop_2_push_1(|a, b| a+b);
            }
            17 => { // SUBTRACT
                self.pop_2_push_1(|a, b| a-b);
            }
            18 => { // MULTIPLY
                self.pop_2_push_1(|a, b| a*b);
            }
            19 => { // DIVMOD
                let (a, b) = (self.pop_data(), self.pop_data());
                self.push_data(b % a);
                self.push_data(b / a);
            }
            20 => { // AND
                self.pop_2_push_1(|a, b| a&b);
            }
            21 => { // OR
                self.pop_2_push_1(|a, b| a|b);
            }
            22 => { // XOR
                self.pop_2_push_1(|a, b| a^b);
            }
            23 => { // SHL
                self.pop_2_push_1(|a, b| b<<(a as uint));
            }
            24 => { // SHR
                self.pop_2_push_1(|a, b| (b as u32>>(a as uint)) as i32);
            }
            25 => { // ZERO_EXIT
                let data = self.pop_data();
                if data == 0 {
                    self.ip = self.pop_address();
                } else {
                    self.push_data(data);
                }
            }
            26 => { // INC
                let data = self.pop_data();
                self.push_data(data+1);
            }
            27 => { // DEC
                let data = self.pop_data();
                self.push_data(data-1);
            }
            28 => { // IN
                let port = self.pop_data();
                let data = self.ports.get(port as uint).map_or(0, |&x| x);
                self.push_data(data);
                self.ports.get_mut(port as uint).map(|x| *x = 0);
            }
            29 => { // OUT
                let (port, data) = (self.pop_data(), self.pop_data());
                // println!("OUT: port: {} data: {}", port, data);
                self.ports.get_mut(port as uint).map(|x| *x = data);
            }
            30 => { // WAIT
                if self.ports.get(0).map_or(false, |&x| x == 0) {
                    result = Wait;
                }
            }
            x => { // Implicit call
                let ip = self.ip;
                self.push_address(ip);
                self.ip = x - 1;
            }
        };
        self.ip += 1;
        return Some(result);
    }
}

pub enum Action {
    Empty,
    Wait,
}

fn opcode_to_name(opcode: i32) -> &'static str {
    const NAMES: &'static [&'static str] = &[
        "NOP",
        "LIT",
        "DUP",
        "DROP",
        "SWAP",
        "PUSH",
        "POP",
        "LOOP",
        "JUMP",
        "RETURN",
        "LT_JUMP",
        "GT_JUMP",
        "NE_JUMP",
        "EQ_JUMP",
        "FETCH",
        "STORE",
        "ADD",
        "SUBTRACT",
        "MULTIPLY",
        "DIVMOD",
        "AND",
        "OR",
        "XOR",
        "SHL",
        "SHR",
        "ZERO_EXIT",
        "INC",
        "DEC",
        "IN",
        "OUT",
        "WAIT",
    ];
    NAMES.get(opcode as uint).map_or("CALL", |&x| x)
}
<commit_msg>Minor changes. Change names of instructions 10 and 11.<commit_after>use std::io::File;
use std::io::IoErrorKind::EndOfFile;
use std::cmp::max;
use self::Action::*;

macro_rules! get_memory {
    ($foo: ident, $addr: expr) => {
        match $foo.memory.memory_space.get($addr as uint) {
            Some(&x) => x,
            None => return None,
        }
    };
    ($foo: ident, $addr: expr, $rval: expr) => {
        match $foo.memory.memory_space.get($addr as uint) {
            Some(&x) => x,
            None => return $rval,
        }
    };
}

struct Memory {
    data_stack: Vec<i32>,
    address_stack: Vec<i32>,
    memory_space: Vec<i32>,
}

impl Memory {
    fn new(path: &Path) -> Memory {
        let mut file = File::open(path).unwrap();
        let size = file.stat().unwrap().size / 4;
        let mut memory = Vec::with_capacity(max(size as uint, 1024*1024)); // 4MB or image size

        loop {
            match file.read_le_i32() {
                Ok(x) => memory.push(x),
                Err(ref e) if e.kind == EndOfFile => break,
                Err(e) => panic!(e),
            }
        }
        Memory {
            data_stack: Vec::new(),
            address_stack: Vec::new(),
            memory_space: memory
        }
    }
}

pub struct Ports<'a> {
    ports: &'a mut [i32]
}

#[unsafe_destructor]
impl<'a> Drop for Ports<'a> {
    fn drop(&mut self) {
        self.ports.get_mut(0).map(|x| *x = 1);
    }
}

impl<'a> Deref<[i32]> for Ports<'a> {
    fn deref(&self) -> &[i32] {
        &*self.ports
    }
}

impl<'a> DerefMut<[i32]> for Ports<'a> {
    fn deref_mut(&mut self) -> &mut [i32] {
        self.ports
    }
}

pub struct Info {
    pub memory_size: i32,
    pub data_stack_depth: i32,
    pub address_stack_depth: i32,
}

pub struct CPU {
    memory: Memory,
    ip: i32,
    ports: [i32, ..12]
}

impl CPU {
    pub fn new(path: &Path) -> CPU {
        CPU {
            memory: Memory::new(path),
            ip: 0,
            ports: [0, ..12],
        }
    }

    pub fn ports_and_stack<'a>(&'a mut self) -> (Ports<'a>, &'a mut Vec<i32>) {
        let ports = Ports { ports: self.ports.as_mut_slice() };
        let stack = &mut self.memory.data_stack;
        (ports, stack)
    }

    pub fn get_info(&self) -> Info {
        Info {
            memory_size: self.memory.memory_space.len() as i32,
            data_stack_depth: self.memory.data_stack.len() as i32,
            address_stack_depth: self.memory.address_stack.len() as i32,
        }
    }

    pub fn pop_data(&mut self) -> i32 {
        self.memory.data_stack.pop().expect("Data stack underflow.")
    }

    pub fn push_data(&mut self, data: i32) {
        self.memory.data_stack.push(data)
    }

    fn pop_address(&mut self) -> i32 {
        self.memory.address_stack.pop().expect("Address stack underflow.")
    }

    fn push_address(&mut self, data: i32) {
        self.memory.address_stack.push(data)
    }

    fn jump(&mut self) {
        self.ip += 1;
        self.ip = get_memory!(self, self.ip, panic!("Jump out of bounds.")) - 1;
    }

    fn cond_stack_jump(&mut self, cond: |i32, i32| -> bool) {
        let (a, b) = (self.pop_data(), self.pop_data());
        if cond(a,b) { self.jump() } else { self.ip += 1; }
    }

    fn pop_2_push_1(&mut self, func: |i32, i32| -> i32) {
        let (a, b) = (self.pop_data(), self.pop_data());
        self.push_data(func(a,b));
    }
}

impl Iterator<Action> for CPU {
    fn next(&mut self) -> Option<Action> {
        let mut stderr = ::std::io::stdio::stderr();
        let mut stderr = &mut stderr;
        let mut result = Empty;
//        writeln!(stderr, "IP: {} Data: {} Address: {}", self.ip, self.memory.data_stack, self.memory.address_stack);
        let instruction = get_memory!(self, self.ip);
//        writeln!(stderr, "Instruction: {}", debug::opcode_to_name(instruction));
        match instruction {
            0 => { } // NOP
            1 => { // LIT X
                self.ip += 1;
                let data = get_memory!(self, self.ip);
                self.push_data(data);
            }
            2 => { // DUP
                let item = self.pop_data();
                self.push_data(item);
                self.push_data(item);
            }
            3 => { // DROP
                self.pop_data();
            }
            4 => { // SWAP
                let (a, b) = (self.pop_data(), self.pop_data());
                self.push_data(a);
                self.push_data(b);
            }
            5 => { // PUSH
                let data = self.pop_data();
                self.push_address(data);
            }
            6 => { // POP
                let data = self.pop_address();
                self.push_data(data);
            }
            7 => { // LOOP A
                let mut data = self.pop_data();
                self.ip += 1;
                data -= 1;
                if data > 0 {
                    self.jump();
                    self.push_data(data);
                }
            }
            8 => { // JUMP A
                self.jump();
            }
            9 => { // RETURN
                let addr = self.pop_address();
                self.ip = addr;
            }
            10 => { // GT_JUMP
                self.cond_stack_jump(|a, b| b > a);
            }
            11 => { // LT_JUMP
                self.cond_stack_jump(|a, b| b < a);
            }
            12 => { // NE_JUMP
                self.cond_stack_jump(|a, b| a != b);
            }
            13 => { // EQ_JUMP
                self.cond_stack_jump(|a, b| a == b);
            }
            14 => { // FETCH
                let addr = self.pop_data();
                let data = *self.memory.memory_space.get(addr as uint).expect("FETCH beyond bounds.");
                self.push_data(data);
            }
            15 => { // STORE
                let (addr, data) = (self.pop_data(), self.pop_data());
                *self.memory.memory_space.get_mut(addr as uint).expect("STORE beyond bounds.") = data;
            }
            16 => { // ADD
                self.pop_2_push_1(|a, b| a+b);
            }
            17 => { // SUBTRACT
                self.pop_2_push_1(|a, b| b-a);
            }
            18 => { // MULTIPLY
                self.pop_2_push_1(|a, b| a*b);
            }
            19 => { // DIVMOD
                let (a, b) = (self.pop_data(), self.pop_data());
                self.push_data(b % a);
                self.push_data(b / a);
            }
            20 => { // AND
                self.pop_2_push_1(|a, b| a&b);
            }
            21 => { // OR
                self.pop_2_push_1(|a, b| a|b);
            }
            22 => { // XOR
                self.pop_2_push_1(|a, b| a^b);
            }
            23 => { // SHL
                self.pop_2_push_1(|a, b| b<<(a as uint));
            }
            24 => { // SHR
                self.pop_2_push_1(|a, b| (b as u32>>(a as uint)) as i32);
            }
            25 => { // ZERO_EXIT
                let data = self.pop_data();
                if data == 0 {
                    self.ip = self.pop_address();
                } else {
                    self.push_data(data);
                }
            }
            26 => { // INC
                let data = self.pop_data();
                self.push_data(data+1);
            }
            27 => { // DEC
                let data = self.pop_data();
                self.push_data(data-1);
            }
            28 => { // IN
                let port = self.pop_data();
                let data = self.ports.get(port as uint).map_or(0, |&x| x);
                self.push_data(data);
                self.ports.get_mut(port as uint).map(|x| *x = 0);
            }
            29 => { // OUT
                let (port, data) = (self.pop_data(), self.pop_data());
                self.ports.get_mut(port as uint).map(|x| *x = data);
            }
            30 => { // WAIT
                if self.ports.get(0).map_or(false, |&x| x == 0) {
                    result = Wait;
                }
            }
            x => { // Implicit call
                let ip = self.ip;
                self.push_address(ip);
                self.ip = x - 1;
            }
        };
        self.ip += 1;
        return Some(result);
    }
}

pub enum Action {
    Empty,
    Wait,
}

#[allow(dead_code)]
mod debug {
    pub fn opcode_to_name(opcode: i32) -> &'static str {
        const NAMES: &'static [&'static str] = &[
            "NOP",
            "LIT",
            "DUP",
            "DROP",
            "SWAP",
            "PUSH",
            "POP",
            "LOOP",
            "JUMP",
            "RETURN",
            "LT_JUMP",
            "GT_JUMP",
            "NE_JUMP",
            "EQ_JUMP",
            "FETCH",
            "STORE",
            "ADD",
            "SUBTRACT",
            "MULTIPLY",
            "DIVMOD",
            "AND",
            "OR",
            "XOR",
            "SHL",
            "SHR",
            "ZERO_EXIT",
            "INC",
            "DEC",
            "IN",
            "OUT",
            "WAIT",
                ];
        NAMES.get(opcode as uint).map_or("CALL", |&x| x)
    }
}
<|endoftext|>


<commit_before>use memory;

pub struct Cpu {
    pub memory: memory::Memory,
    a: u8,
    f: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    h: u8,
    l: u8,
    pc: u16,
    sp: u16,
    cycles: uint
}

static CPU_CYCLES: [uint, ..256] = [
//  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
    4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, // 0x30
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0
    0, 0, 0,16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0
   12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0
    0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xF0
];

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        Cpu {
            memory: memory,
            a: 0x01,
            f: 0xB0,
            b: 0x00,
            c: 0x13,
            d: 0x00,
            e: 0xD8,
            h: 0x01,
            l: 0x4D,
            pc: 0x0100,
            sp: 0xFFFE,
            cycles: 0
        }
    }

    pub fn step(&mut self) {
        let opcode = self.read_next_byte();

        println!("Executing: {:#04X}", opcode);

        match opcode {
            0x00 => {},
            0x3E => {
                self.a = self.read_next_byte();
                println!("  a: {:#04X}", self.a);
            },
            0xC3 => {
                self.pc = self.read_next_word();
                println!("  address: {:#06X}", self.pc);
            },
            0xE0 => {
                let addr = 0xFF00 + self.read_next_byte() as u16;
                self.memory.write_byte(addr, self.a);
                println!("  memory[{:#06X}] = A ({:#04X})", addr, self.a);
            },
            0xF3 => {
                println!("  implement interrupts stuff...");
            },
            _ => fail!("Opcode not implemented: {:#04X}", opcode)
        }

        self.cycles += CPU_CYCLES[opcode as uint];
        println!("  cycles: {}", self.cycles);
    }

    fn read_next_byte(&mut self) -> u8 {
        let value = self.memory.read_byte(self.pc);
        self.pc += 1;
        value
    }

    fn read_next_word(&mut self) -> u16 {
        let value = self.memory.read_word(self.pc);
        self.pc += 2;
        value
    }

    pub fn run(&mut self) {
        loop {
            self.step();
        }
    }
}
<commit_msg>Add XOR instructions<commit_after>use memory;

pub struct Cpu {
    pub memory: memory::Memory,
    a: u8,
    f: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    h: u8,
    l: u8,
    pc: u16,
    sp: u16,
    cycles: uint
}

static CPU_CYCLES: [uint, ..256] = [
//  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
    4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, // 0x30
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90
    0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 8, 4, // 0xA0
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0
    0, 0, 0,16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0
   12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, // 0xE0
    0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xF0
];

static Z_FLAG: u8 = 0b1000_0000;

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        Cpu {
            memory: memory,
            a: 0x01,
            f: 0xB0,
            b: 0x00,
            c: 0x13,
            d: 0x00,
            e: 0xD8,
            h: 0x01,
            l: 0x4D,
            pc: 0x0100,
            sp: 0xFFFE,
            cycles: 0
        }
    }

    pub fn step(&mut self) {
        let opcode = self.read_next_byte();

        println!("Executing: {:#04X}", opcode);

        match opcode {
            0x00 => {},
            0x3E => {
                self.a = self.read_next_byte();
                println!("  a: {:#04X}", self.a);
            },
            0xA8 => {
                let val = self.b;
                self.xor(val);
            },
            0xA9 => {
                let val = self.c;
                self.xor(val);
            },
            0xAA => {
                let val = self.d;
                self.xor(val);
            },
            0xAB => {
                let val = self.e;
                self.xor(val);
            },
            0xAC => {
                let val = self.h;
                self.xor(val);
            },
            0xAD => {
                let val = self.l;
                self.xor(val);
            },
            0xAE => {
                let val = self.memory.read_byte(self.hl());
                self.xor(val);
            },
            0xAF => {
                let val = self.a;
                self.xor(val);
                println!("  a: {:#04X}", self.a);
                println!("  f: {:#08t}", self.f);
            },
            0xC3 => {
                self.pc = self.read_next_word();
                println!("  address: {:#06X}", self.pc);
            },
            0xE0 => {
                let addr = 0xFF00 + self.read_next_byte() as u16;
                self.memory.write_byte(addr, self.a);
                println!("  memory[{:#06X}] = A ({:#04X})", addr, self.a);
            },
            0xEE => {
                let val = self.read_next_byte();
                self.xor(val);
            },
            0xF3 => {
                println!("  implement interrupts stuff...");
            },
            _ => fail!("Opcode not implemented: {:#04X}", opcode)
        }

        self.cycles += CPU_CYCLES[opcode as uint];
        println!("  cycles: {}", self.cycles);
    }

    fn read_next_byte(&mut self) -> u8 {
        let value = self.memory.read_byte(self.pc);
        self.pc += 1;
        value
    }

    fn read_next_word(&mut self) -> u16 {
        let value = self.memory.read_word(self.pc);
        self.pc += 2;
        value
    }

    fn xor(&mut self, value: u8) {
        self.a ^= value;
        self.f = if self.a == 0 { Z_FLAG } else { 0x0000 };
    }

    fn hl(&self) -> u16 {
        self.h as u16 << 8 | self.l as u16
    }

    pub fn run(&mut self) {
        loop {
            self.step();
        }
    }
}
<|endoftext|>


<commit_before>//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website [https://serde.rs/] for additional documentation and
//! usage examples.
//!
//! [https://serde.rs/]: https://serde.rs/
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Bincode], a compact binary format
//!   used for IPC within the Servo rendering engine.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a popular human-friendly configuration language that ain't markup
//!   language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [RON], a Rusty Object Notation.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
//!   definition.
//! - [JSON5], A superset of JSON including some productions from ES5.
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
//! - [URL], the x-www-form-urlencoded format.
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
//!   Rust structs. *(deserialization only)*
//! - [S-expressions], the textual representation of code and data used by the
//!   Lisp language family.
//! - [D-Bus]'s binary wire format.
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Bincode]: https://github.com/TyOverby/bincode
//! [CBOR]: https://github.com/pyfisch/cbor
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/alexcrichton/toml-rs
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [RON]: https://github.com/ron-rs/ron
//! [BSON]: https://github.com/zonyitoo/bson-rs
//! [Avro]: https://github.com/flavray/avro-rs
//! [JSON5]: https://github.com/callum-oakley/json5-rs
//! [Postcard]: https://github.com/jamesmunns/postcard
//! [URL]: https://github.com/nox/serde_urlencoded
//! [Envy]: https://github.com/softprops/envy
//! [Envy Store]: https://github.com/softprops/envy-store
//! [Cargo]: http://doc.crates.io/manifest.html
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html
//! [S-expressions]: https://github.com/rotty/lexpr-rs
//! [D-Bus]: https://docs.rs/zvariant

////////////////////////////////////////////////////////////////////////////////

// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.112")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
//    https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(specialization, never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy and clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
        unnested_or_patterns,
        // not available in our oldest supported compiler
        checked_conversions,
        empty_enum,
        redundant_field_names,
        redundant_static_lifetimes,
        // integer and float ser/de requires these sorts of casts
        cast_possible_truncation,
        cast_possible_wrap,
        cast_sign_loss,
        // things are often more readable this way
        cast_lossless,
        module_name_repetitions,
        single_match_else,
        type_complexity,
        use_self,
        zero_prefixed_literal,
        // correctly used
        enum_glob_use,
        wildcard_imports,
        // not practical
        needless_pass_by_value,
        similar_names,
        too_many_lines,
        // preference
        doc_markdown,
        unseparated_literal_suffix,
        // false positive
        needless_doctest_main,
        // noisy
        missing_errors_doc,
        must_use_candidate,
    )
)]
// Rustc lints.
#![forbid(unsafe_code)]
#![deny(missing_docs, unused_imports)]

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "alloc")]
extern crate alloc;

/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
    mod core {
        #[cfg(not(feature = "std"))]
        pub use core::*;
        #[cfg(feature = "std")]
        pub use std::*;
    }

    pub use self::core::{cmp, iter, mem, num, slice, str};
    pub use self::core::{f32, f64};
    pub use self::core::{i16, i32, i64, i8, isize};
    pub use self::core::{u16, u32, u64, u8, usize};

    pub use self::core::cell::{Cell, RefCell};
    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::ops::Range;
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::borrow::{Cow, ToOwned};
    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::string::{String, ToString};
    #[cfg(feature = "std")]
    pub use std::string::{String, ToString};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::vec::Vec;
    #[cfg(feature = "std")]
    pub use std::vec::Vec;

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;
    #[cfg(feature = "std")]
    pub use std::boxed::Box;

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::{Rc, Weak as RcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::{Rc, Weak as RcWeak};

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::sync::{Arc, Weak as ArcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::{Arc, Weak as ArcWeak};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
    #[cfg(feature = "std")]
    pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CStr, CString, OsStr, OsString};
    #[cfg(feature = "std")]
    pub use std::hash::{BuildHasher, Hash};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::num::Wrapping;
    #[cfg(feature = "std")]
    pub use std::path::{Path, PathBuf};
    #[cfg(feature = "std")]
    pub use std::sync::{Mutex, RwLock};
    #[cfg(feature = "std")]
    pub use std::time::{SystemTime, UNIX_EPOCH};

    #[cfg(all(feature = "std", collections_bound))]
    pub use std::collections::Bound;

    #[cfg(core_reverse)]
    pub use self::core::cmp::Reverse;

    #[cfg(ops_bound)]
    pub use self::core::ops::Bound;

    #[cfg(range_inclusive)]
    pub use self::core::ops::RangeInclusive;

    #[cfg(all(feature = "std", std_atomic))]
    pub use std::sync::atomic::{
        AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
        AtomicUsize, Ordering,
    };
    #[cfg(all(feature = "std", std_atomic64))]
    pub use std::sync::atomic::{AtomicI64, AtomicU64};

    #[cfg(any(core_duration, feature = "std"))]
    pub use self::core::time::Duration;
}

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
mod macros;

#[macro_use]
mod integer128;

pub mod de;
pub mod ser;

#[doc(inline)]
pub use de::{Deserialize, Deserializer};
#[doc(inline)]
pub use ser::{Serialize, Serializer};

// Generated code uses these to support no_std. Not public API.
#[doc(hidden)]
pub mod export;

// Helpers used by generated code and doc tests. Not public API.
#[doc(hidden)]
pub mod private;

#[cfg(not(feature = "std"))]
mod std_error;

// Re-export #[derive(Serialize, Deserialize)].
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
<commit_msg>Add FlexBuffers to serde ecosystem list<commit_after>//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website [https://serde.rs/] for additional documentation and
//! usage examples.
//!
//! [https://serde.rs/]: https://serde.rs/
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Bincode], a compact binary format
//!   used for IPC within the Servo rendering engine.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a popular human-friendly configuration language that ain't markup
//!   language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [RON], a Rusty Object Notation.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
//!   definition.
//! - [JSON5], A superset of JSON including some productions from ES5.
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
//! - [URL], the x-www-form-urlencoded format.
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
//!   Rust structs. *(deserialization only)*
//! - [S-expressions], the textual representation of code and data used by the
//!   Lisp language family.
//! - [D-Bus]'s binary wire format.
//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format.
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Bincode]: https://github.com/TyOverby/bincode
//! [CBOR]: https://github.com/pyfisch/cbor
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/alexcrichton/toml-rs
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [RON]: https://github.com/ron-rs/ron
//! [BSON]: https://github.com/zonyitoo/bson-rs
//! [Avro]: https://github.com/flavray/avro-rs
//! [JSON5]: https://github.com/callum-oakley/json5-rs
//! [Postcard]: https://github.com/jamesmunns/postcard
//! [URL]: https://github.com/nox/serde_urlencoded
//! [Envy]: https://github.com/softprops/envy
//! [Envy Store]: https://github.com/softprops/envy-store
//! [Cargo]: http://doc.crates.io/manifest.html
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html
//! [S-expressions]: https://github.com/rotty/lexpr-rs
//! [D-Bus]: https://docs.rs/zvariant
//! [FlexBuffers]: https://github.com/google/flatbuffers/tree/master/rust/flexbuffers

////////////////////////////////////////////////////////////////////////////////

// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.112")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
//    https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(specialization, never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy and clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
        unnested_or_patterns,
        // not available in our oldest supported compiler
        checked_conversions,
        empty_enum,
        redundant_field_names,
        redundant_static_lifetimes,
        // integer and float ser/de requires these sorts of casts
        cast_possible_truncation,
        cast_possible_wrap,
        cast_sign_loss,
        // things are often more readable this way
        cast_lossless,
        module_name_repetitions,
        single_match_else,
        type_complexity,
        use_self,
        zero_prefixed_literal,
        // correctly used
        enum_glob_use,
        wildcard_imports,
        // not practical
        needless_pass_by_value,
        similar_names,
        too_many_lines,
        // preference
        doc_markdown,
        unseparated_literal_suffix,
        // false positive
        needless_doctest_main,
        // noisy
        missing_errors_doc,
        must_use_candidate,
    )
)]
// Rustc lints.
#![forbid(unsafe_code)]
#![deny(missing_docs, unused_imports)]

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "alloc")]
extern crate alloc;

/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
    mod core {
        #[cfg(not(feature = "std"))]
        pub use core::*;
        #[cfg(feature = "std")]
        pub use std::*;
    }

    pub use self::core::{cmp, iter, mem, num, slice, str};
    pub use self::core::{f32, f64};
    pub use self::core::{i16, i32, i64, i8, isize};
    pub use self::core::{u16, u32, u64, u8, usize};

    pub use self::core::cell::{Cell, RefCell};
    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::ops::Range;
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::borrow::{Cow, ToOwned};
    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::string::{String, ToString};
    #[cfg(feature = "std")]
    pub use std::string::{String, ToString};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::vec::Vec;
    #[cfg(feature = "std")]
    pub use std::vec::Vec;

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;
    #[cfg(feature = "std")]
    pub use std::boxed::Box;

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::{Rc, Weak as RcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::{Rc, Weak as RcWeak};

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::sync::{Arc, Weak as ArcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::{Arc, Weak as ArcWeak};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
    #[cfg(feature = "std")]
    pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CStr, CString, OsStr, OsString};
    #[cfg(feature = "std")]
    pub use std::hash::{BuildHasher, Hash};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::num::Wrapping;
    #[cfg(feature = "std")]
    pub use std::path::{Path, PathBuf};
    #[cfg(feature = "std")]
    pub use std::sync::{Mutex, RwLock};
    #[cfg(feature = "std")]
    pub use std::time::{SystemTime, UNIX_EPOCH};

    #[cfg(all(feature = "std", collections_bound))]
    pub use std::collections::Bound;

    #[cfg(core_reverse)]
    pub use self::core::cmp::Reverse;

    #[cfg(ops_bound)]
    pub use self::core::ops::Bound;

    #[cfg(range_inclusive)]
    pub use self::core::ops::RangeInclusive;

    #[cfg(all(feature = "std", std_atomic))]
    pub use std::sync::atomic::{
        AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
        AtomicUsize, Ordering,
    };
    #[cfg(all(feature = "std", std_atomic64))]
    pub use std::sync::atomic::{AtomicI64, AtomicU64};

    #[cfg(any(core_duration, feature = "std"))]
    pub use self::core::time::Duration;
}

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
mod macros;

#[macro_use]
mod integer128;

pub mod de;
pub mod ser;

#[doc(inline)]
pub use de::{Deserialize, Deserializer};
#[doc(inline)]
pub use ser::{Serialize, Serializer};

// Generated code uses these to support no_std. Not public API.
#[doc(hidden)]
pub mod export;

// Helpers used by generated code and doc tests. Not public API.
#[doc(hidden)]
pub mod private;

#[cfg(not(feature = "std"))]
mod std_error;

// Re-export #[derive(Serialize, Deserialize)].
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
<|endoftext|>


<commit_before>//!  Decoding of DDS images
//!
//!  DDS (DirectDraw Surface) is a container format for storing DXT (S3TC) compressed images.
//!
//!  # Related Links
//!  * <https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide> - Description of the DDS format.

use std::io::Read;

use byteorder::{LittleEndian, ReadBytesExt};

use crate::color::ColorType;
use crate::dxt::{DxtDecoder, DXTReader, DXTVariant};
use crate::error::{ImageError, ImageResult};
use crate::image::ImageDecoder;

/// Header used by DDS image files
#[derive(Debug)]
struct Header {
    flags: u32,
    height: u32,
    width: u32,
    pitch_or_linear_size: u32,
    depth: u32,
    mipmap_count: u32,
    pixel_format: PixelFormat,
    caps: u32,
    caps2: u32,
}

/// DDS pixel format
#[derive(Debug)]
struct PixelFormat {
    flags: u32,
    fourcc: [u8; 4],
    rgb_bit_count: u32,
    r_bit_mask: u32,
    g_bit_mask: u32,
    b_bit_mask: u32,
    a_bit_mask: u32,
}

impl PixelFormat {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 32 {
            return Err(ImageError::FormatError("Invalid DDS PixelFormat size".to_string()))
        }

        Ok(Self {
            flags: r.read_u32::<LittleEndian>()?,
            fourcc: {
                let mut v = [0; 4];
                r.read_exact(&mut v)?;
                v
            },
            rgb_bit_count: r.read_u32::<LittleEndian>()?,
            r_bit_mask: r.read_u32::<LittleEndian>()?,
            g_bit_mask: r.read_u32::<LittleEndian>()?,
            b_bit_mask: r.read_u32::<LittleEndian>()?,
            a_bit_mask: r.read_u32::<LittleEndian>()?,
        })
    }
}

impl Header {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 124 {
            return Err(ImageError::FormatError("Invalid DDS header size".to_string()))
        }

        const REQUIRED_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x1000;
        const VALID_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x8 | 0x1000 | 0x20000 | 0x80000 | 0x800000;
        let flags = r.read_u32::<LittleEndian>()?;
        if flags & (REQUIRED_FLAGS | !VALID_FLAGS) != REQUIRED_FLAGS {
            return Err(ImageError::FormatError("Invalid DDS header flags".to_string()))
        }

        let height = r.read_u32::<LittleEndian>()?;
        let width = r.read_u32::<LittleEndian>()?;
        let pitch_or_linear_size = r.read_u32::<LittleEndian>()?;
        let depth = r.read_u32::<LittleEndian>()?;
        let mipmap_count = r.read_u32::<LittleEndian>()?;
        // Skip `dwReserved1`
        {
            let mut skipped = [0; 4 * 11];
            r.read_exact(&mut skipped)?;
        }
        let pixel_format = PixelFormat::from_reader(r)?;
        let caps = r.read_u32::<LittleEndian>()?;
        let caps2 = r.read_u32::<LittleEndian>()?;
        // Skip `dwCaps3`, `dwCaps4`, `dwReserved2` (unused)
        {
            let mut skipped = [0; 4 + 4 + 4];
            r.read_exact(&mut skipped)?;
        }

        Ok(Self {
            flags,
            height,
            width,
            pitch_or_linear_size,
            depth,
            mipmap_count,
            pixel_format,
            caps,
            caps2,
        })
    }
}

/// The representation of a DDS decoder
pub struct DdsDecoder<R: Read> {
    inner: DxtDecoder<R>,
}

impl<R: Read> DdsDecoder<R> {
    /// Create a new decoder that decodes from the stream `r`
    pub fn new(mut r: R) -> ImageResult<Self> {
        let mut magic = [0; 4];
        r.read_exact(&mut magic)?;
        if magic != b"DDS "[..] {
            return Err(ImageError::FormatError("DDS signature not found".to_string()))
        }

        let header = Header::from_reader(&mut r)?;

        if header.pixel_format.flags & 0x4 != 0 {
            let variant = match &header.pixel_format.fourcc {
                b"DXT1" => DXTVariant::DXT1,
                b"DXT3" => DXTVariant::DXT3,
                b"DXT5" => DXTVariant::DXT5,
                _ => return Err(ImageError::FormatError("Unsupported DDS FourCC".to_string())),
            };
            let inner = DxtDecoder::new(r, header.width, header.height, variant)?;
            Ok(Self { inner })
        } else {
            // For now, supports only DXT variants
            Err(ImageError::FormatError("DDS format not supported".to_string()))
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for DdsDecoder<R> {
    type Reader = DXTReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        self.inner.dimensions()
    }

    fn color_type(&self) -> ColorType {
        self.inner.color_type()
    }

    fn scanline_bytes(&self) -> u64 {
        self.inner.scanline_bytes()
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        self.inner.into_reader()
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        self.inner.read_image(buf)
    }
}

<commit_msg>Use detailed errors for DDS decoder<commit_after>//!  Decoding of DDS images
//!
//!  DDS (DirectDraw Surface) is a container format for storing DXT (S3TC) compressed images.
//!
//!  # Related Links
//!  * <https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide> - Description of the DDS format.

use std::io::Read;

use byteorder::{LittleEndian, ReadBytesExt};

use crate::color::ColorType;
use crate::dxt::{DxtDecoder, DXTReader, DXTVariant};
use crate::error::{
    DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
};
use crate::image::{ImageDecoder, ImageFormat};

/// Header used by DDS image files
#[derive(Debug)]
struct Header {
    flags: u32,
    height: u32,
    width: u32,
    pitch_or_linear_size: u32,
    depth: u32,
    mipmap_count: u32,
    pixel_format: PixelFormat,
    caps: u32,
    caps2: u32,
}

/// DDS pixel format
#[derive(Debug)]
struct PixelFormat {
    flags: u32,
    fourcc: [u8; 4],
    rgb_bit_count: u32,
    r_bit_mask: u32,
    g_bit_mask: u32,
    b_bit_mask: u32,
    a_bit_mask: u32,
}

impl PixelFormat {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 32 {
            return Err(ImageError::Decoding(DecodingError::with_message(
                ImageFormat::Dds.into(),
                "Invalid DDS PixelFormat size".to_string(),
            )));
        }

        Ok(Self {
            flags: r.read_u32::<LittleEndian>()?,
            fourcc: {
                let mut v = [0; 4];
                r.read_exact(&mut v)?;
                v
            },
            rgb_bit_count: r.read_u32::<LittleEndian>()?,
            r_bit_mask: r.read_u32::<LittleEndian>()?,
            g_bit_mask: r.read_u32::<LittleEndian>()?,
            b_bit_mask: r.read_u32::<LittleEndian>()?,
            a_bit_mask: r.read_u32::<LittleEndian>()?,
        })
    }
}

impl Header {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 124 {
            return Err(ImageError::Decoding(DecodingError::with_message(
                ImageFormat::Dds.into(),
                "Invalid DDS header size".to_string(),
            )));
        }

        const REQUIRED_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x1000;
        const VALID_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x8 | 0x1000 | 0x20000 | 0x80000 | 0x800000;
        let flags = r.read_u32::<LittleEndian>()?;
        if flags & (REQUIRED_FLAGS | !VALID_FLAGS) != REQUIRED_FLAGS {
            return Err(ImageError::Decoding(DecodingError::with_message(
                ImageFormat::Dds.into(),
                "Invalid DDS header flags".to_string(),
            )));
        }

        let height = r.read_u32::<LittleEndian>()?;
        let width = r.read_u32::<LittleEndian>()?;
        let pitch_or_linear_size = r.read_u32::<LittleEndian>()?;
        let depth = r.read_u32::<LittleEndian>()?;
        let mipmap_count = r.read_u32::<LittleEndian>()?;
        // Skip `dwReserved1`
        {
            let mut skipped = [0; 4 * 11];
            r.read_exact(&mut skipped)?;
        }
        let pixel_format = PixelFormat::from_reader(r)?;
        let caps = r.read_u32::<LittleEndian>()?;
        let caps2 = r.read_u32::<LittleEndian>()?;
        // Skip `dwCaps3`, `dwCaps4`, `dwReserved2` (unused)
        {
            let mut skipped = [0; 4 + 4 + 4];
            r.read_exact(&mut skipped)?;
        }

        Ok(Self {
            flags,
            height,
            width,
            pitch_or_linear_size,
            depth,
            mipmap_count,
            pixel_format,
            caps,
            caps2,
        })
    }
}

/// The representation of a DDS decoder
pub struct DdsDecoder<R: Read> {
    inner: DxtDecoder<R>,
}

impl<R: Read> DdsDecoder<R> {
    /// Create a new decoder that decodes from the stream `r`
    pub fn new(mut r: R) -> ImageResult<Self> {
        let mut magic = [0; 4];
        r.read_exact(&mut magic)?;
        if magic != b"DDS "[..] {
            return Err(ImageError::Decoding(DecodingError::with_message(
                ImageFormat::Dds.into(),
                "DDS signature not found".to_string(),
            )));
        }

        let header = Header::from_reader(&mut r)?;

        if header.pixel_format.flags & 0x4 != 0 {
            let variant = match &header.pixel_format.fourcc {
                b"DXT1" => DXTVariant::DXT1,
                b"DXT3" => DXTVariant::DXT3,
                b"DXT5" => DXTVariant::DXT5,
                fourcc => {
                    return Err(ImageError::Unsupported(
                        UnsupportedError::from_format_and_kind(
                            ImageFormat::Dds.into(),
                            UnsupportedErrorKind::GenericFeature(format!(
                                "Unsupported DDS FourCC {:?}",
                                fourcc
                            )),
                        ),
                    ))
                }
            };
            let inner = DxtDecoder::new(r, header.width, header.height, variant)?;
            Ok(Self { inner })
        } else {
            // For now, supports only DXT variants
            Err(ImageError::Unsupported(
                UnsupportedError::from_format_and_kind(
                    ImageFormat::Dds.into(),
                    UnsupportedErrorKind::GenericFeature("DDS format not supported".to_string()),
                ),
            ))
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for DdsDecoder<R> {
    type Reader = DXTReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        self.inner.dimensions()
    }

    fn color_type(&self) -> ColorType {
        self.inner.color_type()
    }

    fn scanline_bytes(&self) -> u64 {
        self.inner.scanline_bytes()
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        self.inner.into_reader()
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        self.inner.read_image(buf)
    }
}

<|endoftext|>


<commit_before>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

//! Unwind stack frames for a thread.

mod amd64;
mod arm;
mod arm64;
mod arm64_old;
mod unwind;
mod x86;

use crate::process_state::*;
use crate::{FrameWalker, SymbolProvider};
use log::trace;
use minidump::*;
use scroll::ctx::{SizeWith, TryFromCtx};

use self::unwind::Unwind;
use std::collections::HashSet;
use std::convert::TryFrom;

struct CfiStackWalker<'a, C: CpuContext> {
    instruction: u64,
    grand_callee_parameter_size: u32,

    callee_ctx: &'a C,
    callee_validity: &'a MinidumpContextValidity,

    caller_ctx: C,
    caller_validity: HashSet<&'static str>,

    stack_memory: &'a MinidumpMemory<'a>,
}

impl<'a, C> FrameWalker for CfiStackWalker<'a, C>
where
    C: CpuContext,
    C::Register: TryFrom<u64>,
    u64: TryFrom<C::Register>,
    C::Register: TryFromCtx<'a, Endian, [u8], Error = scroll::Error> + SizeWith<Endian>,
{
    fn get_instruction(&self) -> u64 {
        self.instruction
    }
    fn get_grand_callee_parameter_size(&self) -> u32 {
        self.grand_callee_parameter_size
    }
    fn get_register_at_address(&self, address: u64) -> Option<u64> {
        let result: Option<C::Register> = self.stack_memory.get_memory_at_address(address);
        result.and_then(|val| u64::try_from(val).ok())
    }
    fn get_callee_register(&self, name: &str) -> Option<u64> {
        self.callee_ctx
            .get_register(name, self.callee_validity)
            .and_then(|val| u64::try_from(val).ok())
    }
    fn set_caller_register(&mut self, name: &str, val: u64) -> Option<()> {
        let memoized = self.caller_ctx.memoize_register(name)?;
        let val = C::Register::try_from(val).ok()?;
        self.caller_validity.insert(memoized);
        self.caller_ctx.set_register(name, val)
    }
    fn clear_caller_register(&mut self, name: &str) {
        self.caller_validity.remove(name);
    }
    fn set_cfa(&mut self, val: u64) -> Option<()> {
        // NOTE: some things have alluded to architectures where this isn't
        // how the CFA should be handled, but we apparently don't support them yet?
        let stack_pointer_reg = self.caller_ctx.stack_pointer_register_name();
        let val = C::Register::try_from(val).ok()?;
        self.caller_validity.insert(stack_pointer_reg);
        self.caller_ctx.set_register(stack_pointer_reg, val)
    }
    fn set_ra(&mut self, val: u64) -> Option<()> {
        let instruction_pointer_reg = self.caller_ctx.instruction_pointer_register_name();
        let val = C::Register::try_from(val).ok()?;
        self.caller_validity.insert(instruction_pointer_reg);
        self.caller_ctx.set_register(instruction_pointer_reg, val)
    }
}

async fn get_caller_frame<P>(
    callee_frame: &StackFrame,
    grand_callee_frame: Option<&StackFrame>,
    stack_memory: Option<&MinidumpMemory<'_>>,
    modules: &MinidumpModuleList,
    symbol_provider: &P,
) -> Option<StackFrame>
where
    P: SymbolProvider + Sync,
{
    match callee_frame.context.raw {
        /*
        MinidumpRawContext::PPC(ctx) => ctx.get_caller_frame(stack_memory),
        MinidumpRawContext::PPC64(ctx) => ctx.get_caller_frame(stack_memory),
        MinidumpRawContext::SPARC(ctx) => ctx.get_caller_frame(stack_memory),
        MinidumpRawContext::MIPS(ctx) => ctx.get_caller_frame(stack_memory),
         */
        MinidumpRawContext::Arm(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        MinidumpRawContext::Arm64(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        MinidumpRawContext::OldArm64(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        MinidumpRawContext::Amd64(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        MinidumpRawContext::X86(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        _ => None,
    }
}

async fn fill_source_line_info<P>(
    frame: &mut StackFrame,
    modules: &MinidumpModuleList,
    symbol_provider: &P,
) where
    P: SymbolProvider + Sync,
{
    // Find the module whose address range covers this frame's instruction.
    if let Some(module) = modules.module_at_address(frame.instruction) {
        // FIXME: this shouldn't need to clone, we should be able to use
        // the same lifetime as the module list that's passed in.
        frame.module = Some(module.clone());

        // This is best effort, so ignore any errors.
        let _ = symbol_provider.fill_symbol(module, frame).await;
    }
}

pub async fn walk_stack<P>(
    maybe_context: &Option<&MinidumpContext>,
    stack_memory: Option<&MinidumpMemory<'_>>,
    modules: &MinidumpModuleList,
    symbol_provider: &P,
) -> CallStack
where
    P: SymbolProvider + Sync,
{
    // Begin with the context frame, and keep getting callers until there are
    // no more.
    let mut frames = vec![];
    let mut info = CallStackInfo::Ok;
    if let Some(context) = *maybe_context {
        trace!("unwind: starting stack unwind");
        let ctx = context.clone();
        let mut maybe_frame = Some(StackFrame::from_context(ctx, FrameTrust::Context));
        while let Some(mut frame) = maybe_frame {
            fill_source_line_info(&mut frame, modules, symbol_provider).await;
            trace!(
                "unwind: unwinding {}",
                frame
                    .function_name
                    .clone()
                    .unwrap_or_else(|| frame.instruction.to_string())
            );
            frames.push(frame);
            let callee_frame = &frames.last().unwrap();
            let grand_callee_frame = frames.len().checked_sub(2).and_then(|idx| frames.get(idx));
            maybe_frame = get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await;
        }
        trace!("unwind: finished stack unwind\n");
    } else {
        info = CallStackInfo::MissingContext;
    }
    CallStack {
        frames,
        info,
        thread_id: 0,
        thread_name: None,
        last_error_value: None,
    }
}

/// Checks if we can dismiss the validity of an instruction based on our symbols,
/// to refine the quality of each unwinder's instruction_seems_valid implementation.
async fn instruction_seems_valid_by_symbols<P>(
    instruction: u64,
    modules: &MinidumpModuleList,
    symbol_provider: &P,
) -> bool
where
    P: SymbolProvider + Sync,
{
    if let Some(module) = modules.module_at_address(instruction as u64) {
        // Create a dummy frame symbolizing implementation to feed into
        // our symbol provider with the address we're interested in. If
        // it tries to set a non-empty function name, then we can reasonably
        // assume the instruction address is valid.
        use crate::FrameSymbolizer;

        struct DummyFrame {
            instruction: u64,
            has_name: bool,
        }
        impl FrameSymbolizer for DummyFrame {
            fn get_instruction(&self) -> u64 {
                self.instruction
            }
            fn set_function(&mut self, name: &str, _base: u64, _parameter_size: u32) {
                self.has_name = !name.is_empty();
            }
            fn set_source_file(&mut self, _file: &str, _line: u32, _base: u64) {
                // Do nothing
            }
        }

        let mut frame = DummyFrame {
            instruction: instruction as u64,
            has_name: false,
        };

        if symbol_provider
            .fill_symbol(module, &mut frame)
            .await
            .is_ok()
        {
            frame.has_name
        } else {
            // If the symbol provider returns an Error, this means that we
            // didn't have any symbols for the *module*. Just assume the
            // instruction is valid in this case so that scanning works
            // when we have no symbols.
            true
        }
    } else {
        // We couldn't even map this address to a module. Reject the pointer
        // so that we have *some* way to distinguish "normal" pointers
        // from instruction address.
        //
        // FIXME: this will reject any pointer into JITed code which otherwise
        // isn't part of a normal well-defined module. We can potentially use
        // MemoryInfoListStream (windows) and /proc/self/maps (linux) to refine
        // this analysis and allow scans to walk through JITed code.
        false
    }
}

#[cfg(test)]
mod amd64_unittest;
#[cfg(test)]
mod arm64_unittest;
#[cfg(test)]
mod arm_unittest;
#[cfg(test)]
mod x86_unittest;
<commit_msg>Stack scanning: decrement address before lookup (#446)<commit_after>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

//! Unwind stack frames for a thread.

mod amd64;
mod arm;
mod arm64;
mod arm64_old;
mod unwind;
mod x86;

use crate::process_state::*;
use crate::{FrameWalker, SymbolProvider};
use log::trace;
use minidump::*;
use scroll::ctx::{SizeWith, TryFromCtx};

use self::unwind::Unwind;
use std::collections::HashSet;
use std::convert::TryFrom;

struct CfiStackWalker<'a, C: CpuContext> {
    instruction: u64,
    grand_callee_parameter_size: u32,

    callee_ctx: &'a C,
    callee_validity: &'a MinidumpContextValidity,

    caller_ctx: C,
    caller_validity: HashSet<&'static str>,

    stack_memory: &'a MinidumpMemory<'a>,
}

impl<'a, C> FrameWalker for CfiStackWalker<'a, C>
where
    C: CpuContext,
    C::Register: TryFrom<u64>,
    u64: TryFrom<C::Register>,
    C::Register: TryFromCtx<'a, Endian, [u8], Error = scroll::Error> + SizeWith<Endian>,
{
    fn get_instruction(&self) -> u64 {
        self.instruction
    }
    fn get_grand_callee_parameter_size(&self) -> u32 {
        self.grand_callee_parameter_size
    }
    fn get_register_at_address(&self, address: u64) -> Option<u64> {
        let result: Option<C::Register> = self.stack_memory.get_memory_at_address(address);
        result.and_then(|val| u64::try_from(val).ok())
    }
    fn get_callee_register(&self, name: &str) -> Option<u64> {
        self.callee_ctx
            .get_register(name, self.callee_validity)
            .and_then(|val| u64::try_from(val).ok())
    }
    fn set_caller_register(&mut self, name: &str, val: u64) -> Option<()> {
        let memoized = self.caller_ctx.memoize_register(name)?;
        let val = C::Register::try_from(val).ok()?;
        self.caller_validity.insert(memoized);
        self.caller_ctx.set_register(name, val)
    }
    fn clear_caller_register(&mut self, name: &str) {
        self.caller_validity.remove(name);
    }
    fn set_cfa(&mut self, val: u64) -> Option<()> {
        // NOTE: some things have alluded to architectures where this isn't
        // how the CFA should be handled, but we apparently don't support them yet?
        let stack_pointer_reg = self.caller_ctx.stack_pointer_register_name();
        let val = C::Register::try_from(val).ok()?;
        self.caller_validity.insert(stack_pointer_reg);
        self.caller_ctx.set_register(stack_pointer_reg, val)
    }
    fn set_ra(&mut self, val: u64) -> Option<()> {
        let instruction_pointer_reg = self.caller_ctx.instruction_pointer_register_name();
        let val = C::Register::try_from(val).ok()?;
        self.caller_validity.insert(instruction_pointer_reg);
        self.caller_ctx.set_register(instruction_pointer_reg, val)
    }
}

async fn get_caller_frame<P>(
    callee_frame: &StackFrame,
    grand_callee_frame: Option<&StackFrame>,
    stack_memory: Option<&MinidumpMemory<'_>>,
    modules: &MinidumpModuleList,
    symbol_provider: &P,
) -> Option<StackFrame>
where
    P: SymbolProvider + Sync,
{
    match callee_frame.context.raw {
        /*
        MinidumpRawContext::PPC(ctx) => ctx.get_caller_frame(stack_memory),
        MinidumpRawContext::PPC64(ctx) => ctx.get_caller_frame(stack_memory),
        MinidumpRawContext::SPARC(ctx) => ctx.get_caller_frame(stack_memory),
        MinidumpRawContext::MIPS(ctx) => ctx.get_caller_frame(stack_memory),
         */
        MinidumpRawContext::Arm(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        MinidumpRawContext::Arm64(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        MinidumpRawContext::OldArm64(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        MinidumpRawContext::Amd64(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        MinidumpRawContext::X86(ref ctx) => {
            ctx.get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await
        }
        _ => None,
    }
}

async fn fill_source_line_info<P>(
    frame: &mut StackFrame,
    modules: &MinidumpModuleList,
    symbol_provider: &P,
) where
    P: SymbolProvider + Sync,
{
    // Find the module whose address range covers this frame's instruction.
    if let Some(module) = modules.module_at_address(frame.instruction) {
        // FIXME: this shouldn't need to clone, we should be able to use
        // the same lifetime as the module list that's passed in.
        frame.module = Some(module.clone());

        // This is best effort, so ignore any errors.
        let _ = symbol_provider.fill_symbol(module, frame).await;
    }
}

pub async fn walk_stack<P>(
    maybe_context: &Option<&MinidumpContext>,
    stack_memory: Option<&MinidumpMemory<'_>>,
    modules: &MinidumpModuleList,
    symbol_provider: &P,
) -> CallStack
where
    P: SymbolProvider + Sync,
{
    // Begin with the context frame, and keep getting callers until there are
    // no more.
    let mut frames = vec![];
    let mut info = CallStackInfo::Ok;
    if let Some(context) = *maybe_context {
        trace!("unwind: starting stack unwind");
        let ctx = context.clone();
        let mut maybe_frame = Some(StackFrame::from_context(ctx, FrameTrust::Context));
        while let Some(mut frame) = maybe_frame {
            fill_source_line_info(&mut frame, modules, symbol_provider).await;
            trace!(
                "unwind: unwinding {}",
                frame
                    .function_name
                    .clone()
                    .unwrap_or_else(|| frame.instruction.to_string())
            );
            frames.push(frame);
            let callee_frame = &frames.last().unwrap();
            let grand_callee_frame = frames.len().checked_sub(2).and_then(|idx| frames.get(idx));
            maybe_frame = get_caller_frame(
                callee_frame,
                grand_callee_frame,
                stack_memory,
                modules,
                symbol_provider,
            )
            .await;
        }
        trace!("unwind: finished stack unwind\n");
    } else {
        info = CallStackInfo::MissingContext;
    }
    CallStack {
        frames,
        info,
        thread_id: 0,
        thread_name: None,
        last_error_value: None,
    }
}

/// Checks if we can dismiss the validity of an instruction based on our symbols,
/// to refine the quality of each unwinder's instruction_seems_valid implementation.
async fn instruction_seems_valid_by_symbols<P>(
    instruction: u64,
    modules: &MinidumpModuleList,
    symbol_provider: &P,
) -> bool
where
    P: SymbolProvider + Sync,
{
    // Our input is a candidate return address, but we *really* want to validate the address
    // of the call instruction *before* the return address. In theory this symbol-based
    // analysis shouldn't *care* whether we're looking at the call or the instruction
    // after it, but there is one corner case where the return address can be invalid
    // but the instruction before it isn't: noreturn.
    //
    // If the *callee* is noreturn, then the caller has no obligation to have any instructions
    // after the call! So e.g. on x86 if you CALL a noreturn function, the return address
    // that's implicitly pushed *could* be one-past-the-end of the "function".
    //
    // This has been observed in practice with `+[NSThread exit]`!
    //
    // We don't otherwise need the instruction pointer to be terribly precise, so
    // subtracting 1 from the address should be sufficient to handle this corner case.
    let instruction = instruction.saturating_sub(1);

    // NULL pointer is definitely not valid
    if instruction == 0 {
        return false;
    }

    if let Some(module) = modules.module_at_address(instruction as u64) {
        // Create a dummy frame symbolizing implementation to feed into
        // our symbol provider with the address we're interested in. If
        // it tries to set a non-empty function name, then we can reasonably
        // assume the instruction address is valid.
        use crate::FrameSymbolizer;

        struct DummyFrame {
            instruction: u64,
            has_name: bool,
        }
        impl FrameSymbolizer for DummyFrame {
            fn get_instruction(&self) -> u64 {
                self.instruction
            }
            fn set_function(&mut self, name: &str, _base: u64, _parameter_size: u32) {
                self.has_name = !name.is_empty();
            }
            fn set_source_file(&mut self, _file: &str, _line: u32, _base: u64) {
                // Do nothing
            }
        }

        let mut frame = DummyFrame {
            instruction: instruction as u64,
            has_name: false,
        };

        if symbol_provider
            .fill_symbol(module, &mut frame)
            .await
            .is_ok()
        {
            frame.has_name
        } else {
            // If the symbol provider returns an Error, this means that we
            // didn't have any symbols for the *module*. Just assume the
            // instruction is valid in this case so that scanning works
            // when we have no symbols.
            true
        }
    } else {
        // We couldn't even map this address to a module. Reject the pointer
        // so that we have *some* way to distinguish "normal" pointers
        // from instruction address.
        //
        // FIXME: this will reject any pointer into JITed code which otherwise
        // isn't part of a normal well-defined module. We can potentially use
        // MemoryInfoListStream (windows) and /proc/self/maps (linux) to refine
        // this analysis and allow scans to walk through JITed code.
        false
    }
}

#[cfg(test)]
mod amd64_unittest;
#[cfg(test)]
mod arm64_unittest;
#[cfg(test)]
mod arm_unittest;
#[cfg(test)]
mod x86_unittest;
<|endoftext|>


<commit_before>use js::function::{NativeFunction, NativeFunc};
use js::value::{Value, ResultValue, VFunction, VString, VUndefined, to_value};
use url::{encode, decode, encode_component, decode_component};
use std::cell::RefCell;
use std::gc::Gc;

/// Encode a URI
pub fn encode_uri(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(encode(args.get(0).borrow().to_str()))
	}))
}
/// Encode a URI component
pub fn encode_uri_component(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(encode_component(args.get(0).borrow().to_str()))
	}))
}
/// Decode a URI
pub fn decode_uri(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(decode(args.get(0).borrow().to_str()))
	}))
}
/// Decode a URI component
pub fn decode_uri_component(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(decode_component(args.get(0).borrow().to_str()))
	}))
}
/// Initialise the URI functions on a global object
pub fn init(obj:Value) {
	obj.borrow().set_field(~"encodeURI", to_value(encode_uri));
	obj.borrow().set_field(~"encodeURIComponent", to_value(encode_uri_component));
	obj.borrow().set_field(~"decodeURI", to_value(decode_uri));
	obj.borrow().set_field(~"decodeURIComponent", to_value(decode_uri_component));
}<commit_msg>Remove unused imports from URI module<commit_after>use js::value::{Value, ResultValue, VString, VUndefined, to_value};
use url::{encode, decode, encode_component, decode_component};
use std::cell::RefCell;
use std::gc::Gc;

/// Encode a URI
pub fn encode_uri(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(encode(args.get(0).borrow().to_str()))
	}))
}
/// Encode a URI component
pub fn encode_uri_component(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(encode_component(args.get(0).borrow().to_str()))
	}))
}
/// Decode a URI
pub fn decode_uri(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(decode(args.get(0).borrow().to_str()))
	}))
}
/// Decode a URI component
pub fn decode_uri_component(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(if args.len() == 0 {
		VUndefined
	} else {
		VString(decode_component(args.get(0).borrow().to_str()))
	}))
}
/// Initialise the URI functions on a global object
pub fn init(obj:Value) {
	obj.borrow().set_field(~"encodeURI", to_value(encode_uri));
	obj.borrow().set_field(~"encodeURIComponent", to_value(encode_uri_component));
	obj.borrow().set_field(~"decodeURI", to_value(decode_uri));
	obj.borrow().set_field(~"decodeURIComponent", to_value(decode_uri_component));
}<|endoftext|>