<commit_before>use std::{convert};
use std::io::{Cursor, Read};

use byteorder::{self, ReadBytesExt};

use utils::{ObjectIdentifier};

#[derive(Debug, PartialEq, Eq)]
pub enum DeserializationError {
    UnexpectedTag,
    ShortData,
    ExtraData,
    IntegerOverflow,
    InvalidValue,
}

impl convert::From<byteorder::Error> for DeserializationError {
    fn from(e: byteorder::Error) -> DeserializationError {
        return match e {
            byteorder::Error::UnexpectedEOF => DeserializationError::ShortData,
            _ => panic!("Unexpected error!"),
        }
    }
}

pub type DeserializationResult<T> = Result<T, DeserializationError>;

pub struct Deserializer {
    reader: Cursor<Vec<u8>>,
}

impl Deserializer {
    pub fn new(data: Vec<u8>) -> Deserializer {
        return Deserializer{
            reader: Cursor::new(data),
        }
    }

    fn _read_length(&mut self) -> DeserializationResult<usize> {
        let b = try!(self.reader.read_u8());
        // TODO: handle lengths greater than 128
        assert!(b & 0x80 == 0);
        return Ok((b & 0x7f) as usize);
    }

    fn _read_with_tag<T, F>(&mut self, expected_tag: u8, body: F) -> DeserializationResult<T>
            where F: Fn(Vec<u8>) -> DeserializationResult<T> {
        let tag = try!(self.reader.read_u8());
        // TODO: only some of the bits in the first byte are for the tag
        if tag != expected_tag {
            return Err(DeserializationError::UnexpectedTag);
        }
        let length = try!(self._read_length());
        let mut data = vec![0; length];
        let n = self.reader.read(&mut data).unwrap();
        if n != length {
            return Err(DeserializationError::ShortData);
        }
        return body(data);
    }

    pub fn finish(self) -> DeserializationResult<()> {
        if self.reader.position() as usize != self.reader.get_ref().len() {
            return Err(DeserializationError::ExtraData);
        }
        return Ok(());
    }

    pub fn read_bool(&mut self) -> DeserializationResult<bool> {
        return self._read_with_tag(1, |data| {
            if data == b"\x00" {
                return Ok(false);
            } else if data == b"\xff" {
                return Ok(true)
            } else {
                return Err(DeserializationError::InvalidValue);
            }
        });
    }

    pub fn read_int(&mut self) -> DeserializationResult<i64> {
        return self._read_with_tag(2, |data| {
            if data.len() > 8 {
                return Err(DeserializationError::IntegerOverflow);
            }
            if data.len() > 1 {
                match (data[0], data[1] & 0x80) {
                    (0xff, 0x80) | (0x00, 0x00) => return Err(DeserializationError::InvalidValue),
                    _ => {},
                }
            }
            let mut ret = 0;
            for b in data.iter() {
                ret <<= 8;
                ret |= *b as i64;
            }
            // Shift up and down in order to sign extend the result.
            ret <<= 64 - data.len() * 8;
            ret >>= 64 - data.len() * 8;
            return Ok(ret);
        });
    }

    pub fn read_octet_string(&mut self) -> DeserializationResult<Vec<u8>> {
        return self._read_with_tag(4, |data| {
            return Ok(data);
        });
    }

    pub fn read_object_identifier(&mut self) -> DeserializationResult<ObjectIdentifier> {
        return self._read_with_tag(6, |data| {
            if data.is_empty() {
                return Err(DeserializationError::InvalidValue);
            }
            let s = vec![];

            return Ok(ObjectIdentifier::new(s).unwrap());
        });
    }

    pub fn read_sequence<F, T>(&mut self, v: F) -> DeserializationResult<T>
            where F: Fn(&mut Deserializer) -> DeserializationResult<T> {
        return self._read_with_tag(48, |data| {
            return from_vec(data, &v);
        });
    }
}

pub fn from_vec<F, T>(data: Vec<u8>, f: F) -> DeserializationResult<T>
        where F: Fn(&mut Deserializer) -> DeserializationResult<T> {
    let mut deserializer = Deserializer::new(data);
    let result = try!(f(&mut deserializer));
    try!(deserializer.finish());
    return Ok(result);
}

#[cfg(test)]
mod tests {
    use std;
    use std::{fmt};

    use utils::{ObjectIdentifier};
    use super::{Deserializer, DeserializationError, DeserializationResult, from_vec};

    fn assert_deserializes<T, F>(values: Vec<(DeserializationResult<T>, Vec<u8>)>, f: F)
            where T: Eq + fmt::Debug, F: Fn(&mut Deserializer) -> DeserializationResult<T> {
        for (expected, value) in values {
            let result = from_vec(value, &f);
            assert_eq!(result, expected);
        }
    }
    #[test]
    fn test_read_extra_data() {
        assert_deserializes(vec![
            (Err(DeserializationError::ExtraData), b"\x00".to_vec()),
        ], |_| {
            return Ok(());
        });
    }

    #[test]
    fn test_read_bool() {
        assert_deserializes(vec![
            (Ok(true), b"\x01\x01\xff".to_vec()),
            (Ok(false), b"\x01\x01\x00".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x00".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x01\x01".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x02\x00\x00".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x02\xff\x01".to_vec()),
        ], |deserializer| {
            return deserializer.read_bool();
        });
    }

    #[test]
    fn test_read_int() {
        assert_deserializes(vec![
            (Ok(0), b"\x02\x01\x00".to_vec()),
            (Ok(127), b"\x02\x01\x7f".to_vec()),
            (Ok(128), b"\x02\x02\x00\x80".to_vec()),
            (Ok(256), b"\x02\x02\x01\x00".to_vec()),
            (Ok(-128), b"\x02\x01\x80".to_vec()),
            (Ok(-129), b"\x02\x02\xff\x7f".to_vec()),
            (Ok(-256), b"\x02\x02\xff\x00".to_vec()),
            (Ok(std::i64::MAX), b"\x02\x08\x7f\xff\xff\xff\xff\xff\xff\xff".to_vec()),
            (Err(DeserializationError::UnexpectedTag), b"\x03".to_vec()),
            (Err(DeserializationError::ShortData), b"\x02\x02\x00".to_vec()),
            (Err(DeserializationError::ShortData), b"".to_vec()),
            (Err(DeserializationError::ShortData), b"\x02".to_vec()),
            (
                Err(DeserializationError::IntegerOverflow),
                b"\x02\x09\x02\x00\x00\x00\x00\x00\x00\x00\x00".to_vec()
            ),
            (Err(DeserializationError::InvalidValue), b"\x02\x05\x00\x00\x00\x00\x01".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x02\x02\xff\x80".to_vec()),
        ], |deserializer| {
            return deserializer.read_int();
        });
    }

    #[test]
    fn test_read_octet_string() {
        assert_deserializes(vec![
            (Ok(b"".to_vec()), b"\x04\x00".to_vec()),
            (Ok(b"\x01\x02\x03".to_vec()), b"\x04\x03\x01\x02\x03".to_vec()),
            (Err(DeserializationError::ShortData), b"\x04\x03\x01\x02".to_vec()),
        ], |deserializer| {
            return deserializer.read_octet_string();
        });
    }

    #[test]
    fn test_read_object_identifier() {
        assert_deserializes(vec![
            (
                Ok(ObjectIdentifier::new(vec![1, 2, 840, 113549]).unwrap()),
                b"\x06\x06\x2a\x86\x48\x86\xf7\x0d".to_vec()
            ),
            (
                Ok(ObjectIdentifier::new(vec![1, 2, 3, 4]).unwrap()),
                b"\x06\x03\x2a\x03\x04".to_vec(),
            ),
            (
                Ok(ObjectIdentifier::new(vec![1, 2, 840, 133549, 1, 1, 5]).unwrap()),
                b"\x06\x09\x2a\x86\x48\x88\x93\x2d\x01\x01\x05".to_vec(),
            ),
            (
                Ok(ObjectIdentifier::new(vec![2, 100, 3]).unwrap()),
                b"\x06\x03\x81\x34\x03".to_vec(),
            ),
            (Err(DeserializationError::InvalidValue), b"\x06\x00".to_vec()),
        ], |deserializer| {
            return deserializer.read_object_identifier();
        });
    }

    #[test]
    fn test_read_sequence() {
        assert_deserializes(vec![
            (Ok((1, 2)), b"\x30\x06\x02\x01\x01\x02\x01\x02".to_vec()),
            (Err(DeserializationError::ShortData), b"\x30\x03\x02\x01\x01".to_vec()),
            (
                Err(DeserializationError::ExtraData),
                b"\x30\x07\x02\x01\x01\x02\x01\x02\x00".to_vec()
            ),
        ], |deserializer| {
            return deserializer.read_sequence(|deserializer| {
                return Ok((
                    try!(deserializer.read_int()),
                    try!(deserializer.read_int())
                ));
            });
        });
    }
}
<commit_msg>vaguely working<commit_after>use std::{convert};
use std::io::{Cursor, Read};

use byteorder::{self, ReadBytesExt};

use utils::{ObjectIdentifier};

#[derive(Debug, PartialEq, Eq)]
pub enum DeserializationError {
    UnexpectedTag,
    ShortData,
    ExtraData,
    IntegerOverflow,
    InvalidValue,
}

impl convert::From<byteorder::Error> for DeserializationError {
    fn from(e: byteorder::Error) -> DeserializationError {
        return match e {
            byteorder::Error::UnexpectedEOF => DeserializationError::ShortData,
            _ => panic!("Unexpected error!"),
        }
    }
}

pub type DeserializationResult<T> = Result<T, DeserializationError>;

fn _read_base128_int(reader: &mut Cursor<Vec<u8>>) -> DeserializationResult<u32> {
    let mut ret = 0u32;
    for _ in 0..4 {
        let b = try!(reader.read_u8());
        ret <<= 7;
        ret |= (b & 0x7f) as u32;
        if b & 0x80 == 0 {
            return Ok(ret);
        }
    }
    return Err(DeserializationError::InvalidValue);
}

pub struct Deserializer {
    reader: Cursor<Vec<u8>>,
}

impl Deserializer {
    pub fn new(data: Vec<u8>) -> Deserializer {
        return Deserializer{
            reader: Cursor::new(data),
        }
    }

    fn _read_length(&mut self) -> DeserializationResult<usize> {
        let b = try!(self.reader.read_u8());
        // TODO: handle lengths greater than 128
        assert!(b & 0x80 == 0);
        return Ok((b & 0x7f) as usize);
    }

    fn _read_with_tag<T, F>(&mut self, expected_tag: u8, body: F) -> DeserializationResult<T>
            where F: Fn(Vec<u8>) -> DeserializationResult<T> {
        let tag = try!(self.reader.read_u8());
        // TODO: only some of the bits in the first byte are for the tag
        if tag != expected_tag {
            return Err(DeserializationError::UnexpectedTag);
        }
        let length = try!(self._read_length());
        let mut data = vec![0; length];
        let n = self.reader.read(&mut data).unwrap();
        if n != length {
            return Err(DeserializationError::ShortData);
        }
        return body(data);
    }

    pub fn finish(self) -> DeserializationResult<()> {
        if self.reader.position() as usize != self.reader.get_ref().len() {
            return Err(DeserializationError::ExtraData);
        }
        return Ok(());
    }

    pub fn read_bool(&mut self) -> DeserializationResult<bool> {
        return self._read_with_tag(1, |data| {
            if data == b"\x00" {
                return Ok(false);
            } else if data == b"\xff" {
                return Ok(true)
            } else {
                return Err(DeserializationError::InvalidValue);
            }
        });
    }

    pub fn read_int(&mut self) -> DeserializationResult<i64> {
        return self._read_with_tag(2, |data| {
            if data.len() > 8 {
                return Err(DeserializationError::IntegerOverflow);
            }
            if data.len() > 1 {
                match (data[0], data[1] & 0x80) {
                    (0xff, 0x80) | (0x00, 0x00) => return Err(DeserializationError::InvalidValue),
                    _ => {},
                }
            }
            let mut ret = 0;
            for b in data.iter() {
                ret <<= 8;
                ret |= *b as i64;
            }
            // Shift up and down in order to sign extend the result.
            ret <<= 64 - data.len() * 8;
            ret >>= 64 - data.len() * 8;
            return Ok(ret);
        });
    }

    pub fn read_octet_string(&mut self) -> DeserializationResult<Vec<u8>> {
        return self._read_with_tag(4, |data| {
            return Ok(data);
        });
    }

    pub fn read_object_identifier(&mut self) -> DeserializationResult<ObjectIdentifier> {
        return self._read_with_tag(6, |data| {
            if data.is_empty() {
                return Err(DeserializationError::InvalidValue);
            }
            let mut reader = Cursor::new(data);
            let mut s = vec![];
            let v = try!(_read_base128_int(&mut reader));

            if v < 80 {
                s.push(v / 40);
                s.push(v % 40);
            } else {
                s.push(2);
                s.push(v - 80);
            }

            while (reader.position() as usize) < reader.get_ref().len() {
                s.push(try!(_read_base128_int(&mut reader)));
            }

            return match ObjectIdentifier::new(s) {
                Some(oid) => Ok(oid),
                None => Err(DeserializationError::InvalidValue),
            };
        });
    }

    pub fn read_sequence<F, T>(&mut self, v: F) -> DeserializationResult<T>
            where F: Fn(&mut Deserializer) -> DeserializationResult<T> {
        return self._read_with_tag(48, |data| {
            return from_vec(data, &v);
        });
    }
}

pub fn from_vec<F, T>(data: Vec<u8>, f: F) -> DeserializationResult<T>
        where F: Fn(&mut Deserializer) -> DeserializationResult<T> {
    let mut deserializer = Deserializer::new(data);
    let result = try!(f(&mut deserializer));
    try!(deserializer.finish());
    return Ok(result);
}

#[cfg(test)]
mod tests {
    use std;
    use std::{fmt};

    use utils::{ObjectIdentifier};
    use super::{Deserializer, DeserializationError, DeserializationResult, from_vec};

    fn assert_deserializes<T, F>(values: Vec<(DeserializationResult<T>, Vec<u8>)>, f: F)
            where T: Eq + fmt::Debug, F: Fn(&mut Deserializer) -> DeserializationResult<T> {
        for (expected, value) in values {
            let result = from_vec(value, &f);
            assert_eq!(result, expected);
        }
    }
    #[test]
    fn test_read_extra_data() {
        assert_deserializes(vec![
            (Err(DeserializationError::ExtraData), b"\x00".to_vec()),
        ], |_| {
            return Ok(());
        });
    }

    #[test]
    fn test_read_bool() {
        assert_deserializes(vec![
            (Ok(true), b"\x01\x01\xff".to_vec()),
            (Ok(false), b"\x01\x01\x00".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x00".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x01\x01".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x02\x00\x00".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x01\x02\xff\x01".to_vec()),
        ], |deserializer| {
            return deserializer.read_bool();
        });
    }

    #[test]
    fn test_read_int() {
        assert_deserializes(vec![
            (Ok(0), b"\x02\x01\x00".to_vec()),
            (Ok(127), b"\x02\x01\x7f".to_vec()),
            (Ok(128), b"\x02\x02\x00\x80".to_vec()),
            (Ok(256), b"\x02\x02\x01\x00".to_vec()),
            (Ok(-128), b"\x02\x01\x80".to_vec()),
            (Ok(-129), b"\x02\x02\xff\x7f".to_vec()),
            (Ok(-256), b"\x02\x02\xff\x00".to_vec()),
            (Ok(std::i64::MAX), b"\x02\x08\x7f\xff\xff\xff\xff\xff\xff\xff".to_vec()),
            (Err(DeserializationError::UnexpectedTag), b"\x03".to_vec()),
            (Err(DeserializationError::ShortData), b"\x02\x02\x00".to_vec()),
            (Err(DeserializationError::ShortData), b"".to_vec()),
            (Err(DeserializationError::ShortData), b"\x02".to_vec()),
            (
                Err(DeserializationError::IntegerOverflow),
                b"\x02\x09\x02\x00\x00\x00\x00\x00\x00\x00\x00".to_vec()
            ),
            (Err(DeserializationError::InvalidValue), b"\x02\x05\x00\x00\x00\x00\x01".to_vec()),
            (Err(DeserializationError::InvalidValue), b"\x02\x02\xff\x80".to_vec()),
        ], |deserializer| {
            return deserializer.read_int();
        });
    }

    #[test]
    fn test_read_octet_string() {
        assert_deserializes(vec![
            (Ok(b"".to_vec()), b"\x04\x00".to_vec()),
            (Ok(b"\x01\x02\x03".to_vec()), b"\x04\x03\x01\x02\x03".to_vec()),
            (Err(DeserializationError::ShortData), b"\x04\x03\x01\x02".to_vec()),
        ], |deserializer| {
            return deserializer.read_octet_string();
        });
    }

    #[test]
    fn test_read_object_identifier() {
        assert_deserializes(vec![
            (
                Ok(ObjectIdentifier::new(vec![1, 2, 840, 113549]).unwrap()),
                b"\x06\x06\x2a\x86\x48\x86\xf7\x0d".to_vec()
            ),
            (
                Ok(ObjectIdentifier::new(vec![1, 2, 3, 4]).unwrap()),
                b"\x06\x03\x2a\x03\x04".to_vec(),
            ),
            (
                Ok(ObjectIdentifier::new(vec![1, 2, 840, 133549, 1, 1, 5]).unwrap()),
                b"\x06\x09\x2a\x86\x48\x88\x93\x2d\x01\x01\x05".to_vec(),
            ),
            (
                Ok(ObjectIdentifier::new(vec![2, 100, 3]).unwrap()),
                b"\x06\x03\x81\x34\x03".to_vec(),
            ),
            (Err(DeserializationError::InvalidValue), b"\x06\x00".to_vec()),
        ], |deserializer| {
            return deserializer.read_object_identifier();
        });
    }

    #[test]
    fn test_read_sequence() {
        assert_deserializes(vec![
            (Ok((1, 2)), b"\x30\x06\x02\x01\x01\x02\x01\x02".to_vec()),
            (Err(DeserializationError::ShortData), b"\x30\x03\x02\x01\x01".to_vec()),
            (
                Err(DeserializationError::ExtraData),
                b"\x30\x07\x02\x01\x01\x02\x01\x02\x00".to_vec()
            ),
        ], |deserializer| {
            return deserializer.read_sequence(|deserializer| {
                return Ok((
                    try!(deserializer.read_int()),
                    try!(deserializer.read_int())
                ));
            });
        });
    }
}
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, LittleEndian};

use opcodes::{AddressingMode, OpCode};

pub struct Disassembler {
    /// Determines whether byte offsets are generated
    /// in the Assembly output
    disable_offsets: bool,
}

/// A 6502 instruction disassembler
impl Disassembler {
    /// Creates a new, default instance of the Disassembler
    pub fn new() -> Disassembler {
        Disassembler { disable_offsets: false }
    }

    /// Creates an instance of the Disassembler where no
    /// byte offsets are generated in the Assembly output
    pub fn with_code_only() -> Disassembler {
        Disassembler { disable_offsets: true }
    }

    /// Accepts a slice of 6502 bytecodes and translates them
    /// into an assembly String representation
    ///
    /// # Example
    /// ```
    /// use rs6502::Disassembler;
    ///
    /// let dasm = Disassembler::new();
    ///
    /// let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
    /// let asm = dasm.disassemble(&code);
    ///
    /// assert_eq!(Disassembler::clean_asm("
    ///
    ///     0000 LDA #$20
    ///     0002 STA $4400
    ///
    /// "), Disassembler::clean_asm(asm));
    /// ```
    pub fn disassemble(&self, raw: &[u8]) -> String {
        let mut result = String::new();

        let mut i: usize = 0;
        while i < raw.len() {
            let opcode = OpCode::from_raw_byte(raw[i]);
            let val = match opcode.mode {
                AddressingMode::Immediate => format!(" #${:02X}", raw[i + 0x01]),
                AddressingMode::Indirect => {
                    format!(" (${:04X})", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::Relative => {
                    let mut offset = raw[i + 0x01] as i8;
                    let addr = if offset < 0 {
                        i - (-offset - 0x02) as usize
                    } else {
                        i + (offset as usize) + 0x02
                    };
                    format!(" ${:04X}", addr)
                }
                AddressingMode::ZeroPage => format!(" ${:02X}", raw[i + 0x01]),
                AddressingMode::ZeroPageX => format!(" ${:02X},X", raw[i + 0x01]),
                AddressingMode::ZeroPageY => format!(" ${:02X},Y", raw[i + 0x01]),
                AddressingMode::Absolute => {
                    format!(" ${:04X}", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteX => {
                    format!(" ${:04X},X", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::AbsoluteY => {
                    format!(" ${:04X},Y", LittleEndian::read_u16(&raw[i + 0x01..]))
                }
                AddressingMode::IndirectX => format!(" (${:02X},X)", raw[i + 0x01]),
                AddressingMode::IndirectY => format!(" (${:02X}),Y", raw[i + 0x01]),
                _ => "".into(),
            };
            let opcode_text = if self.disable_offsets {
                format!("{}{}\n", opcode.mnemonic, val)
            } else {
                format!("{:04X} {}{}\n", i, opcode.mnemonic, val)
            };
            result.push_str(&opcode_text);
            i += opcode.length as usize;
        }

        result
    }

    /// Returns a Vector of Strings where each entry
    /// is a non-empty line of assembly instructions, with
    /// all leading and trailing whitespace removed.
    ///
    /// # Example
    ///
    /// ```
    /// use rs6502::Disassembler;
    ///
    /// assert_eq!(Disassembler::clean_asm("
    ///
    ///     0000 LDA #$20
    ///     0002 STA $4400
    ///
    /// "), &["0000 LDA #$20", "0002 STA $4400"]);
    /// ```
    pub fn clean_asm<I>(input: I) -> Vec<String>
        where I: Into<String>
    {
        input.into()
            .lines()
            .map(|line| line.trim())
            .map(String::from)
            .filter(|line| line.len() > 0)
            .collect()
    }
}

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

    #[test]
    fn can_disassemble_basic_instructions() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_jmp() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x6C, 0x00, 0x44];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 JMP ($4400)

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_relative_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA9, 0x20, 0x69, 0x10, 0xD0, 0xFA];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 ADC #$10
            0004 BNE $0000

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA5, 0x35];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA $35

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_indexed_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x95, 0x44, 0x96, 0xFE];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $44,X
            0002 STX $FE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x8D, 0x00, 0x44];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_indexed_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x9D, 0x00, 0x44, 0x99, 0xFE, 0xFF];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400,X
            0003 STA $FFFE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_indexed_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x81, 0x44, 0x91, 0xFE];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA ($44,X)
            0002 STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_without_byte_offsets() {
        let dasm = Disassembler::with_code_only();
        let code: Vec<u8> = vec![0x81, 0x35, 0x91, 0xFE];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA ($35,X)
            STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn move_memory_down_test() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA0, 0x00, 0xAE, 0x00, 0x00, 0xF0, 0x10, 0xB1, 0x02, 0x91, 0x03,
                                 0xC8, 0xD0, 0xF9, 0xEE, 0x02, 0x00, 0xEE, 0x03, 0x00, 0xCA, 0xD0,
                                 0xF0, 0xAE, 0x01, 0x00, 0xF0, 0x08, 0xB1, 0x02, 0x91, 0x03, 0xC8,
                                 0xCA, 0xD0, 0xF8, 0x60];

        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDY #$00
            0002 LDX $0000
            0005 BEQ $0017
            0007 LDA ($02),Y
            0009 STA ($03),Y
            000B INY
            000C BNE $0007
            000E INC $0002
            0011 INC $0003
            0014 DEX
            0015 BNE $0007
            0017 LDX $0001
            001A BEQ $0024
            001C LDA ($02),Y
            001E STA ($03),Y
            0020 INY
            0021 DEX
            0022 BNE $001C
            0024 RTS

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn test_memset_implementation() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA9, 0x00, 0xA8, 0x91, 0xFF, 0xC8, 0xCA, 0xD0, 0xFA, 0x60];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$00
            0002 TAY
            0003 STA ($FF),Y
            0005 INY
            0006 DEX
            0007 BNE $0003
            0009 RTS

        "),
                   Disassembler::clean_asm(asm));
    }
}
<commit_msg>Add verbose output flag and tests<commit_after>use byteorder::{ByteOrder, LittleEndian};

use opcodes::{AddressingMode, OpCode};

pub struct Disassembler {
    /// Determines whether byte offsets are generated
    /// in the Assembly output
    disable_offsets: bool,

    /// Determines whether opcodes are generated
    /// in the Assembly output
    disable_opcodes: bool,
}

/// A 6502 instruction disassembler
impl Disassembler {
    /// Creates a new, default instance of the Disassembler
    ///
    /// # Example
    /// ```
    /// use rs6502::Disassembler;
    ///
    /// let dasm = Disassembler::new();
    ///
    /// let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
    /// let asm = dasm.disassemble(&code);
    ///
    /// assert_eq!(Disassembler::clean_asm("
    ///
    ///     0000 LDA #$20
    ///     0002 STA $4400
    ///
    /// "), Disassembler::clean_asm(asm));
    /// ```
    pub fn new() -> Disassembler {
        Disassembler {
            disable_offsets: false,
            disable_opcodes: true,
        }
    }

    /// Creates an instance of the Disassembler where no
    /// byte offsets are generated in the Assembly output
    ///
    /// # Example
    /// ```
    /// use rs6502::Disassembler;
    ///
    /// let dasm = Disassembler::with_code_only();
    ///
    /// let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
    /// let asm = dasm.disassemble(&code);
    ///
    /// assert_eq!(Disassembler::clean_asm("
    ///
    ///     LDA #$20
    ///     STA $4400
    ///
    /// "), Disassembler::clean_asm(asm));
    /// ```
    pub fn with_code_only() -> Disassembler {
        Disassembler {
            disable_offsets: true,
            disable_opcodes: true,
        }
    }

    /// Creates an instance of the Disassembler with all
    /// available information generated into the output
    ///
    /// # Example
    /// ```
    /// use rs6502::Disassembler;
    ///
    /// let dasm = Disassembler::with_verbose_output();
    ///
    /// let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
    /// let asm = dasm.disassemble(&code);
    ///
    /// assert_eq!(Disassembler::clean_asm("
    ///
    ///     0000 A9 20    LDA #$20
    ///     0002 8D 00 44 STA $4400
    ///
    /// "), Disassembler::clean_asm(asm));
    /// ```
    pub fn with_verbose_output() -> Disassembler {
        Disassembler {
            disable_offsets: false,
            disable_opcodes: false,
        }
    }

    /// Accepts a slice of 6502 bytecodes and translates them
    /// into an assembly String representation
    ///
    /// # Example
    /// ```
    /// use rs6502::Disassembler;
    ///
    /// let dasm = Disassembler::new();
    ///
    /// let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
    /// let asm = dasm.disassemble(&code);
    ///
    /// assert_eq!(Disassembler::clean_asm("
    ///
    ///     0000 LDA #$20
    ///     0002 STA $4400
    ///
    /// "), Disassembler::clean_asm(asm));
    /// ```
    pub fn disassemble(&self, raw: &[u8]) -> String {
        let mut result = String::new();

        let mut i: usize = 0;
        while i < raw.len() {
            let opcode = OpCode::from_raw_byte(raw[i]);

            // Each branch returns the opcode output and the
            // disassembled output
            let val = match opcode.mode {
                AddressingMode::Immediate => {
                    let imm = raw[i + 0x01];
                    (format!("{:02X} {:02X}", opcode.code, imm), format!(" #${:02X}", imm))
                }
                AddressingMode::Indirect => {
                    let b1 = raw[i + 0x01];
                    let b2 = raw[i + 0x02];

                    let addr = LittleEndian::read_u16(&[b1, b2]);

                    (format!("{:02X} {:02X} {:02X}", opcode.code, b1, b2),
                     format!(" (${:04X})", addr))
                }
                AddressingMode::Relative => {
                    let b1 = raw[i + 0x01];
                    let mut offset = b1 as i8;
                    let addr = if offset < 0 {
                        i - (-offset - 0x02) as usize
                    } else {
                        i + (offset as usize) + 0x02
                    };

                    (format!(" {:02X} {:02X}", opcode.code, b1), format!(" ${:04X}", addr))
                }
                AddressingMode::ZeroPage => {
                    let b1 = raw[i + 0x01];
                    (format!("{:02X} {:02X}", opcode.code, b1), format!(" ${:02X}", b1))
                }
                AddressingMode::ZeroPageX => {
                    let b1 = raw[i + 0x01];
                    (format!("{:02X} {:02X}", opcode.code, b1), format!(" ${:02X},X", b1))
                }
                AddressingMode::ZeroPageY => {
                    let b1 = raw[i + 0x01];
                    (format!("{:02X} {:02X}", opcode.code, b1), format!(" ${:02X},Y", b1))
                }
                AddressingMode::Absolute => {
                    let b1 = raw[i + 0x01];
                    let b2 = raw[i + 0x02];
                    let addr = LittleEndian::read_u16(&[b1, b2]);
                    (format!("{:02X} {:02X} {:02X}", opcode.code, b1, b2),
                     format!(" ${:04X}", addr))
                }
                AddressingMode::AbsoluteX => {
                    let b1 = raw[i + 0x01];
                    let b2 = raw[i + 0x02];
                    let addr = LittleEndian::read_u16(&[b1, b2]);
                    (format!("{:02X} {:02X} {:02X}", opcode.code, b1, b2),
                     format!(" ${:04X},X", addr))
                }
                AddressingMode::AbsoluteY => {
                    let b1 = raw[i + 0x01];
                    let b2 = raw[i + 0x02];
                    let addr = LittleEndian::read_u16(&[b1, b2]);
                    (format!("{:02X} {:02X} {:02X}", opcode.code, b1, b2),
                     format!(" ${:04X},Y", addr))
                }
                AddressingMode::IndirectX => {
                    let b1 = raw[i + 0x01];
                    (format!("{:02X} {:02X}", opcode.code, b1), format!(" (${:02X},X)", b1))
                }
                AddressingMode::IndirectY => {
                    let b1 = raw[i + 0x01];
                    (format!(" {:02X} {:02X}", opcode.code, b1), format!(" (${:02X}),Y", b1))
                }
                _ => ("".into(), "".into()),
            };

            let opcode_text = if self.disable_offsets {
                if self.disable_opcodes {
                    format!("{}{}\n", opcode.mnemonic, val.1)
                } else {
                    format!("{:<8} {}{}\n", val.0, opcode.mnemonic, val.1)
                }
            } else {
                if self.disable_opcodes {
                    format!("{:04X} {}{}\n", i, opcode.mnemonic, val.1)
                } else {
                    format!("{:04X} {:<8} {}{}\n", i, val.0, opcode.mnemonic, val.1)
                }
            };
            result.push_str(&opcode_text);
            i += opcode.length as usize;
        }

        result
    }

    /// Returns a Vector of Strings where each entry
    /// is a non-empty line of assembly instructions, with
    /// all leading and trailing whitespace removed.
    ///
    /// # Example
    ///
    /// ```
    /// use rs6502::Disassembler;
    ///
    /// assert_eq!(Disassembler::clean_asm("
    ///
    ///     0000 LDA #$20
    ///     0002 STA $4400
    ///
    /// "), &["0000 LDA #$20", "0002 STA $4400"]);
    /// ```
    pub fn clean_asm<I>(input: I) -> Vec<String>
        where I: Into<String>
    {
        input.into()
            .lines()
            .map(|line| line.trim())
            .map(String::from)
            .filter(|line| line.len() > 0)
            .collect()
    }
}

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

    #[test]
    fn can_disassemble_basic_instructions() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA9, 0x20, 0x8D, 0x00, 0x44];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_jmp() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x6C, 0x00, 0x44];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 JMP ($4400)

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_relative_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA9, 0x20, 0x69, 0x10, 0xD0, 0xFA];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$20
            0002 ADC #$10
            0004 BNE $0000

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA5, 0x35];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA $35

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_zero_page_indexed_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x95, 0x44, 0x96, 0xFE];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $44,X
            0002 STX $FE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x8D, 0x00, 0x44];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_absolute_indexed_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x9D, 0x00, 0x44, 0x99, 0xFE, 0xFF];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA $4400,X
            0003 STA $FFFE,Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_indirect_indexed_addressing() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0x81, 0x44, 0x91, 0xFE];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 STA ($44,X)
            0002 STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn can_disassemble_without_byte_offsets() {
        let dasm = Disassembler::with_code_only();
        let code: Vec<u8> = vec![0x81, 0x35, 0x91, 0xFE];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            STA ($35,X)
            STA ($FE),Y

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn move_memory_down_test() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA0, 0x00, 0xAE, 0x00, 0x00, 0xF0, 0x10, 0xB1, 0x02, 0x91, 0x03,
                                 0xC8, 0xD0, 0xF9, 0xEE, 0x02, 0x00, 0xEE, 0x03, 0x00, 0xCA, 0xD0,
                                 0xF0, 0xAE, 0x01, 0x00, 0xF0, 0x08, 0xB1, 0x02, 0x91, 0x03, 0xC8,
                                 0xCA, 0xD0, 0xF8, 0x60];

        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDY #$00
            0002 LDX $0000
            0005 BEQ $0017
            0007 LDA ($02),Y
            0009 STA ($03),Y
            000B INY
            000C BNE $0007
            000E INC $0002
            0011 INC $0003
            0014 DEX
            0015 BNE $0007
            0017 LDX $0001
            001A BEQ $0024
            001C LDA ($02),Y
            001E STA ($03),Y
            0020 INY
            0021 DEX
            0022 BNE $001C
            0024 RTS

        "),
                   Disassembler::clean_asm(asm));
    }

    #[test]
    fn test_memset_implementation() {
        let dasm = Disassembler::new();
        let code: Vec<u8> = vec![0xA9, 0x00, 0xA8, 0x91, 0xFF, 0xC8, 0xCA, 0xD0, 0xFA, 0x60];
        let asm = dasm.disassemble(&code);

        assert_eq!(Disassembler::clean_asm("

            0000 LDA #$00
            0002 TAY
            0003 STA ($FF),Y
            0005 INY
            0006 DEX
            0007 BNE $0003
            0009 RTS

        "),
                   Disassembler::clean_asm(asm));
    }
}
<|endoftext|>


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

use cargo;
use config::ServiceConfig;
use botocore::{ServiceDefinition, Value, Member, Shape, ShapeType, Operation};

#[derive(Debug)]
pub struct Service<'a> {
    config: &'a ::ServiceConfig,
    definition: ServiceDefinition
}

impl <'b> Service <'b> {
    pub fn new(config: &'b ServiceConfig, definition: ServiceDefinition) -> Self {
        Service {
            config: config,
            definition: definition
        }
    }

    pub fn name(&self) -> &str {
        match self.definition.metadata.service_abbreviation {
            Some(ref service_abbreviation) => service_abbreviation.as_str(),
            None => self.definition.metadata.service_full_name.as_ref()
        }
    }

    pub fn full_name(&self) -> &str {
        &self.definition.metadata.service_full_name
    }

    pub fn service_id(&self) -> Option<&str> {
        self.definition.metadata.service_id.as_ref().map(|service_id| service_id.as_str())
    }

    pub fn documentation(&self) -> Option<&String> {
        self.definition.documentation.as_ref()
    }

    pub fn protocol(&self) -> &str {
        &self.definition.metadata.protocol
    }

    pub fn client_type_name(&self) -> String {
        format!("{}Client", self.service_type_name())
    }

    pub fn service_type_name(&self) -> &str {
        &self.config.base_type_name
    }

    pub fn endpoint_prefix(&self) -> &str {
        &self.definition.metadata.endpoint_prefix
    }

    pub fn api_version(&self) -> &str {
        &self.definition.metadata.api_version
    }

    pub fn target_prefix(&self) -> Option<&String> {
        self.definition.metadata.target_prefix.as_ref()
    }

    pub fn json_version(&self) -> Option<&String> {
        self.definition.metadata.json_version.as_ref()
    }

    pub fn shapes(&self) -> &BTreeMap<String, Shape> {
        &self.definition.shapes
    }

    pub fn get_shape(&self, name: &str) -> Option<&Shape> {
        self.definition.shapes.get(name)
    }

    pub fn operations(&self) -> &BTreeMap<String, Operation> {
        &self.definition.operations
    }

    pub fn shape_for_value<'a>(&'a self, value: &Value) -> Option<&'a Shape> {
        self.definition.shapes.get(&value.shape)
    }

    pub fn shape_for_member<'a>(&'a self, member: &Member) -> Option<&'a Shape> {
        self.definition.shapes.get(&member.shape)
    }

    pub fn shape_type_for_member<'a>(&'a self, member: &Member) -> Option<ShapeType> {
        self.definition.shapes.get(&member.shape).map(|shape| shape.shape_type)
    }

    pub fn signing_name(&self) -> String {
        match self.definition.metadata.signing_name {
            Some(ref signing_name) => signing_name.to_string(),
            None => self.definition.metadata.endpoint_prefix.to_string(),
        }
    }

    pub fn get_dependencies(&self) -> BTreeMap<String, cargo::Dependency> {
        let mut dependencies = BTreeMap::new();

        dependencies.insert("futures".to_owned(), cargo::Dependency::Simple("0.1.16".into()));
        dependencies.insert("rusoto_core".to_owned(), cargo::Dependency::Extended {
            path: Some("../../core".into()),
            version: Some(self.config.core_version.clone()),
            optional: None,
            default_features: None,
            features: None
        });

        match self.protocol() {
            "json" => {
                dependencies.insert("serde".to_owned(), cargo::Dependency::Simple("1.0.2".into()));
                dependencies.insert("serde_derive".to_owned(), cargo::Dependency::Simple("1.0.2".into()));
                dependencies.insert("serde_json".to_owned(), cargo::Dependency::Simple("1.0.1".into()));
            },
            "query" | "ec2" | "rest-xml" => {
                dependencies.insert("xml-rs".to_owned(), cargo::Dependency::Simple("0.7".into()));
            },
            "rest-json" => {
                dependencies.insert("log".to_owned(), cargo::Dependency::Simple("0.4.1".into()));
                dependencies.insert("serde".to_owned(), cargo::Dependency::Simple("1.0.2".into()));
                dependencies.insert("serde_derive".to_owned(), cargo::Dependency::Simple("1.0.2".into()));
                dependencies.insert("serde_json".to_owned(), cargo::Dependency::Simple("1.0.1".into()));
            },
            protocol => panic!("Unknown protocol {}", protocol),
        }

        if let Some(ref custom_dependencies) = self.config.custom_dependencies {
            dependencies.extend(custom_dependencies.clone());
        }

        dependencies
    }

    pub fn get_dev_dependencies(&self) -> BTreeMap<String, cargo::Dependency> {
        let mut dev_dependencies = BTreeMap::new();

        dev_dependencies.insert("rusoto_mock".to_owned(), cargo::Dependency::Extended {
            path: Some("../../../mock".into()),
            version: Some("0.26.0".into()),
            optional: None,
            default_features: None,
            features: None
        });

        if let Some(ref custom_dev_dependencies) = self.config.custom_dev_dependencies {
            dev_dependencies.extend(custom_dev_dependencies.clone());
        }

        dev_dependencies
    }
}
<commit_msg>Update version of rusoto_mock<commit_after>use std::collections::BTreeMap;

use cargo;
use config::ServiceConfig;
use botocore::{ServiceDefinition, Value, Member, Shape, ShapeType, Operation};

#[derive(Debug)]
pub struct Service<'a> {
    config: &'a ::ServiceConfig,
    definition: ServiceDefinition
}

impl <'b> Service <'b> {
    pub fn new(config: &'b ServiceConfig, definition: ServiceDefinition) -> Self {
        Service {
            config: config,
            definition: definition
        }
    }

    pub fn name(&self) -> &str {
        match self.definition.metadata.service_abbreviation {
            Some(ref service_abbreviation) => service_abbreviation.as_str(),
            None => self.definition.metadata.service_full_name.as_ref()
        }
    }

    pub fn full_name(&self) -> &str {
        &self.definition.metadata.service_full_name
    }

    pub fn service_id(&self) -> Option<&str> {
        self.definition.metadata.service_id.as_ref().map(|service_id| service_id.as_str())
    }

    pub fn documentation(&self) -> Option<&String> {
        self.definition.documentation.as_ref()
    }

    pub fn protocol(&self) -> &str {
        &self.definition.metadata.protocol
    }

    pub fn client_type_name(&self) -> String {
        format!("{}Client", self.service_type_name())
    }

    pub fn service_type_name(&self) -> &str {
        &self.config.base_type_name
    }

    pub fn endpoint_prefix(&self) -> &str {
        &self.definition.metadata.endpoint_prefix
    }

    pub fn api_version(&self) -> &str {
        &self.definition.metadata.api_version
    }

    pub fn target_prefix(&self) -> Option<&String> {
        self.definition.metadata.target_prefix.as_ref()
    }

    pub fn json_version(&self) -> Option<&String> {
        self.definition.metadata.json_version.as_ref()
    }

    pub fn shapes(&self) -> &BTreeMap<String, Shape> {
        &self.definition.shapes
    }

    pub fn get_shape(&self, name: &str) -> Option<&Shape> {
        self.definition.shapes.get(name)
    }

    pub fn operations(&self) -> &BTreeMap<String, Operation> {
        &self.definition.operations
    }

    pub fn shape_for_value<'a>(&'a self, value: &Value) -> Option<&'a Shape> {
        self.definition.shapes.get(&value.shape)
    }

    pub fn shape_for_member<'a>(&'a self, member: &Member) -> Option<&'a Shape> {
        self.definition.shapes.get(&member.shape)
    }

    pub fn shape_type_for_member<'a>(&'a self, member: &Member) -> Option<ShapeType> {
        self.definition.shapes.get(&member.shape).map(|shape| shape.shape_type)
    }

    pub fn signing_name(&self) -> String {
        match self.definition.metadata.signing_name {
            Some(ref signing_name) => signing_name.to_string(),
            None => self.definition.metadata.endpoint_prefix.to_string(),
        }
    }

    pub fn get_dependencies(&self) -> BTreeMap<String, cargo::Dependency> {
        let mut dependencies = BTreeMap::new();

        dependencies.insert("futures".to_owned(), cargo::Dependency::Simple("0.1.16".into()));
        dependencies.insert("rusoto_core".to_owned(), cargo::Dependency::Extended {
            path: Some("../../core".into()),
            version: Some(self.config.core_version.clone()),
            optional: None,
            default_features: None,
            features: None
        });

        match self.protocol() {
            "json" => {
                dependencies.insert("serde".to_owned(), cargo::Dependency::Simple("1.0.2".into()));
                dependencies.insert("serde_derive".to_owned(), cargo::Dependency::Simple("1.0.2".into()));
                dependencies.insert("serde_json".to_owned(), cargo::Dependency::Simple("1.0.1".into()));
            },
            "query" | "ec2" | "rest-xml" => {
                dependencies.insert("xml-rs".to_owned(), cargo::Dependency::Simple("0.7".into()));
            },
            "rest-json" => {
                dependencies.insert("log".to_owned(), cargo::Dependency::Simple("0.4.1".into()));
                dependencies.insert("serde".to_owned(), cargo::Dependency::Simple("1.0.2".into()));
                dependencies.insert("serde_derive".to_owned(), cargo::Dependency::Simple("1.0.2".into()));
                dependencies.insert("serde_json".to_owned(), cargo::Dependency::Simple("1.0.1".into()));
            },
            protocol => panic!("Unknown protocol {}", protocol),
        }

        if let Some(ref custom_dependencies) = self.config.custom_dependencies {
            dependencies.extend(custom_dependencies.clone());
        }

        dependencies
    }

    pub fn get_dev_dependencies(&self) -> BTreeMap<String, cargo::Dependency> {
        let mut dev_dependencies = BTreeMap::new();

        dev_dependencies.insert("rusoto_mock".to_owned(), cargo::Dependency::Extended {
            path: Some("../../../mock".into()),
            version: Some("0.27.0".into()),
            optional: None,
            default_features: None,
            features: None
        });

        if let Some(ref custom_dev_dependencies) = self.config.custom_dev_dependencies {
            dev_dependencies.extend(custom_dev_dependencies.clone());
        }

        dev_dependencies
    }
}
<|endoftext|>


<commit_before>use self::build_tables::build_tables;
use self::parse_grammar::parse_grammar;
use self::prepare_grammar::prepare_grammar;
use self::render::render_c_code;
use crate::error::{Error, Result};
use lazy_static::lazy_static;
use regex::{Regex, RegexBuilder};
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

mod build_tables;
mod grammars;
mod nfa;
mod npm_files;
mod parse_grammar;
mod prepare_grammar;
mod render;
mod rules;
mod tables;

lazy_static! {
    static ref JSON_COMMENT_REGEX: Regex = RegexBuilder::new("^\\s*//.*")
        .multi_line(true)
        .build()
        .unwrap();
}

pub fn generate_parser_in_directory(
    repo_path: &PathBuf,
    grammar_path: Option<&str>,
    minimize: bool,
    state_ids_to_log: Vec<usize>,
) -> Result<()> {
    let repo_src_path = repo_path.join("src");

    let grammar_json;
    match grammar_path {
        Some(path) => {
            grammar_json = load_grammar_file(path.as_ref())?;
        }
        None => {
            let grammar_js_path = grammar_path.map_or(repo_path.join("grammar.js"), |s| s.into());
            grammar_json = load_grammar_file(&grammar_js_path)?;
            fs::write(&repo_src_path.join("grammar.json"), &grammar_json)?;
        }
    }

    let (language_name, c_code) =
        generate_parser_for_grammar_with_opts(&grammar_json, minimize, state_ids_to_log)?;
    let repo_header_path = repo_src_path.join("tree_sitter");
    fs::create_dir_all(&repo_src_path)?;
    fs::create_dir_all(&repo_header_path)?;
    fs::write(&repo_src_path.join("parser.c"), c_code)
        .map_err(|e| format!("Failed to write parser.c: {}", e))?;
    fs::write(
        &repo_header_path.join("parser.h"),
        tree_sitter::PARSER_HEADER,
    )
    .map_err(|e| format!("Failed to write parser.h: {}", e))?;
    ensure_file(&repo_src_path.join("binding.cc"), || {
        npm_files::binding_cc(&language_name)
    })?;
    ensure_file(&repo_path.join("binding.gyp"), || {
        npm_files::binding_gyp(&language_name)
    })?;
    ensure_file(&repo_path.join("index.js"), || {
        npm_files::index_js(&language_name)
    })?;
    Ok(())
}

pub fn generate_parser_for_grammar(grammar_json: &str) -> Result<(String, String)> {
    let grammar_json = JSON_COMMENT_REGEX.replace_all(grammar_json, "\n");
    generate_parser_for_grammar_with_opts(&grammar_json, true, Vec::new())
}

fn generate_parser_for_grammar_with_opts(
    grammar_json: &str,
    minimize: bool,
    state_ids_to_log: Vec<usize>,
) -> Result<(String, String)> {
    let input_grammar = parse_grammar(grammar_json)?;
    let (syntax_grammar, lexical_grammar, inlines, simple_aliases) =
        prepare_grammar(&input_grammar)?;
    let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables(
        &syntax_grammar,
        &lexical_grammar,
        &simple_aliases,
        &inlines,
        minimize,
        state_ids_to_log,
    )?;
    let c_code = render_c_code(
        &input_grammar.name,
        parse_table,
        main_lex_table,
        keyword_lex_table,
        keyword_capture_token,
        syntax_grammar,
        lexical_grammar,
        simple_aliases,
    );
    Ok((input_grammar.name, c_code))
}

fn load_grammar_file(grammar_path: &Path) -> Result<String> {
    match grammar_path.extension().and_then(|e| e.to_str()) {
        Some("js") => Ok(load_js_grammar_file(grammar_path)?),
        Some("json") => Ok(fs::read_to_string(grammar_path)?),
        _ => Err(Error(format!(
            "Unknown grammar file extension: {:?}",
            grammar_path
        ))),
    }
}

fn load_js_grammar_file(grammar_path: &Path) -> Result<String> {
    let mut node_process = Command::new("node")
        .env("TREE_SITTER_GRAMMAR_PATH", grammar_path)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .expect("Failed to run `node`");

    let mut node_stdin = node_process
        .stdin
        .take()
        .expect("Failed to open stdin for node");
    let javascript_code = include_bytes!("./dsl.js");
    node_stdin
        .write(javascript_code)
        .expect("Failed to write to node's stdin");
    drop(node_stdin);
    let output = node_process
        .wait_with_output()
        .expect("Failed to read output from node");
    match output.status.code() {
        None => panic!("Node process was killed"),
        Some(0) => {}
        Some(code) => return Err(Error(format!("Node process exited with status {}", code))),
    }

    Ok(String::from_utf8(output.stdout).expect("Got invalid UTF8 from node"))
}

fn ensure_file<T: AsRef<[u8]>>(path: &PathBuf, f: impl Fn() -> T) -> Result<()> {
    if path.exists() {
        Ok(())
    } else {
        fs::write(path, f().as_ref())
            .map_err(|e| Error(format!("Failed to write file {:?}: {}", path, e)))
    }
}
<commit_msg>cli: Create src directory before writing grammar.json<commit_after>use self::build_tables::build_tables;
use self::parse_grammar::parse_grammar;
use self::prepare_grammar::prepare_grammar;
use self::render::render_c_code;
use crate::error::{Error, Result};
use lazy_static::lazy_static;
use regex::{Regex, RegexBuilder};
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

mod build_tables;
mod grammars;
mod nfa;
mod npm_files;
mod parse_grammar;
mod prepare_grammar;
mod render;
mod rules;
mod tables;

lazy_static! {
    static ref JSON_COMMENT_REGEX: Regex = RegexBuilder::new("^\\s*//.*")
        .multi_line(true)
        .build()
        .unwrap();
}

pub fn generate_parser_in_directory(
    repo_path: &PathBuf,
    grammar_path: Option<&str>,
    minimize: bool,
    state_ids_to_log: Vec<usize>,
) -> Result<()> {
    let repo_src_path = repo_path.join("src");
    let repo_header_path = repo_src_path.join("tree_sitter");

    fs::create_dir_all(&repo_src_path)?;
    fs::create_dir_all(&repo_header_path)?;

    let grammar_json;
    match grammar_path {
        Some(path) => {
            grammar_json = load_grammar_file(path.as_ref())?;
        }
        None => {
            let grammar_js_path = grammar_path.map_or(repo_path.join("grammar.js"), |s| s.into());
            grammar_json = load_grammar_file(&grammar_js_path)?;
            fs::write(&repo_src_path.join("grammar.json"), &grammar_json)?;
        }
    }

    let (language_name, c_code) =
        generate_parser_for_grammar_with_opts(&grammar_json, minimize, state_ids_to_log)?;
    fs::write(&repo_src_path.join("parser.c"), c_code)
        .map_err(|e| format!("Failed to write parser.c: {}", e))?;
    fs::write(
        &repo_header_path.join("parser.h"),
        tree_sitter::PARSER_HEADER,
    )
    .map_err(|e| format!("Failed to write parser.h: {}", e))?;
    ensure_file(&repo_src_path.join("binding.cc"), || {
        npm_files::binding_cc(&language_name)
    })?;
    ensure_file(&repo_path.join("binding.gyp"), || {
        npm_files::binding_gyp(&language_name)
    })?;
    ensure_file(&repo_path.join("index.js"), || {
        npm_files::index_js(&language_name)
    })?;
    Ok(())
}

pub fn generate_parser_for_grammar(grammar_json: &str) -> Result<(String, String)> {
    let grammar_json = JSON_COMMENT_REGEX.replace_all(grammar_json, "\n");
    generate_parser_for_grammar_with_opts(&grammar_json, true, Vec::new())
}

fn generate_parser_for_grammar_with_opts(
    grammar_json: &str,
    minimize: bool,
    state_ids_to_log: Vec<usize>,
) -> Result<(String, String)> {
    let input_grammar = parse_grammar(grammar_json)?;
    let (syntax_grammar, lexical_grammar, inlines, simple_aliases) =
        prepare_grammar(&input_grammar)?;
    let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables(
        &syntax_grammar,
        &lexical_grammar,
        &simple_aliases,
        &inlines,
        minimize,
        state_ids_to_log,
    )?;
    let c_code = render_c_code(
        &input_grammar.name,
        parse_table,
        main_lex_table,
        keyword_lex_table,
        keyword_capture_token,
        syntax_grammar,
        lexical_grammar,
        simple_aliases,
    );
    Ok((input_grammar.name, c_code))
}

fn load_grammar_file(grammar_path: &Path) -> Result<String> {
    match grammar_path.extension().and_then(|e| e.to_str()) {
        Some("js") => Ok(load_js_grammar_file(grammar_path)?),
        Some("json") => Ok(fs::read_to_string(grammar_path)?),
        _ => Err(Error(format!(
            "Unknown grammar file extension: {:?}",
            grammar_path
        ))),
    }
}

fn load_js_grammar_file(grammar_path: &Path) -> Result<String> {
    let mut node_process = Command::new("node")
        .env("TREE_SITTER_GRAMMAR_PATH", grammar_path)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .expect("Failed to run `node`");

    let mut node_stdin = node_process
        .stdin
        .take()
        .expect("Failed to open stdin for node");
    let javascript_code = include_bytes!("./dsl.js");
    node_stdin
        .write(javascript_code)
        .expect("Failed to write to node's stdin");
    drop(node_stdin);
    let output = node_process
        .wait_with_output()
        .expect("Failed to read output from node");
    match output.status.code() {
        None => panic!("Node process was killed"),
        Some(0) => {}
        Some(code) => return Err(Error(format!("Node process exited with status {}", code))),
    }

    Ok(String::from_utf8(output.stdout).expect("Got invalid UTF8 from node"))
}

fn ensure_file<T: AsRef<[u8]>>(path: &PathBuf, f: impl Fn() -> T) -> Result<()> {
    if path.exists() {
        Ok(())
    } else {
        fs::write(path, f().as_ref())
            .map_err(|e| Error(format!("Failed to write file {:?}: {}", path, e)))
    }
}
<|endoftext|>


<commit_before>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/*
 * Position
 * GeoJSON Format Specification § 2.1.1
 * http://geojson.org/geojson-spec.html#positions
 */
pub struct Position(Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

/*
 * Point
 * GeoJSON Format Specification § 2.1.2
 * http://geojson.org/geojson-spec.html#point
 */
pub struct Point {
    coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), json::String("Point".to_string()));
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/*
 * MultiPoint
 * GeoJSON Format Specification § 2.1.3
 * http://geojson.org/geojson-spec.html#multipoint
 */
pub struct MultiPoint {
    coordinates: Vec<Position>,
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<commit_msg>Implement ToJson for MultiPoint<commit_after>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/*
 * Position
 * GeoJSON Format Specification § 2.1.1
 * http://geojson.org/geojson-spec.html#positions
 */
pub struct Position(Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

/*
 * Point
 * GeoJSON Format Specification § 2.1.2
 * http://geojson.org/geojson-spec.html#point
 */
pub struct Point {
    coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), json::String("Point".to_string()));
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/*
 * MultiPoint
 * GeoJSON Format Specification § 2.1.3
 * http://geojson.org/geojson-spec.html#multipoint
 */
pub struct MultiPoint {
    coordinates: Vec<Position>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), json::String("MultiPoint".to_string()));
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 - 2016, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of yabs, distributed under the BSD
// 3-Clause license. For full terms please see the LICENSE file.

#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate walkdir;
extern crate ansi_term;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate log;

pub mod build;
pub mod error;
pub mod ext;
pub mod profile;
pub mod new;
pub mod logger;
mod desc;
<commit_msg>Remove unneeded macro_use<commit_after>// Copyright (c) 2015 - 2016, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of yabs, distributed under the BSD
// 3-Clause license. For full terms please see the LICENSE file.

#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate walkdir;
extern crate ansi_term;
extern crate serde;
extern crate serde_json;
extern crate log;

pub mod build;
pub mod error;
pub mod ext;
pub mod profile;
pub mod new;
pub mod logger;
mod desc;
<|endoftext|>


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

use std::io::{self, Write};
use std::sync::Arc;
use std::time::Instant;

use crate::detect::Detected;
use crate::res;
use crate::task;

use crate::error::{BuildError, Error};

use super::traits::{EventLogger, LogResult, TaskLogger};

use termcolor::{self as tc, WriteColor};

pub struct ConsoleTask {
    verbose: bool,
    bufwriter: Arc<tc::BufferWriter>,
    header: String,
    body: Vec<u8>,
    start_time: Instant,
}

impl ConsoleTask {
    pub fn new(
        verbose: bool,
        thread: usize,
        task: &task::Any,
        bufwriter: Arc<tc::BufferWriter>,
    ) -> Result<ConsoleTask, Error> {
        Ok(ConsoleTask {
            verbose,
            bufwriter,
            header: format!("[{}] {}", thread, task),
            body: Vec::new(),
            start_time: Instant::now(),
        })
    }
}

impl io::Write for ConsoleTask {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.body.write(buf)
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.body.write_all(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl TaskLogger for ConsoleTask {
    fn finish(self, result: &Result<Detected, Error>) -> LogResult<()> {
        let ConsoleTask {
            verbose,
            bufwriter,
            header,
            body,
            start_time,
        } = self;

        let mut buf = bufwriter.buffer();

        let color = if result.is_ok() {
            tc::Color::Green
        } else {
            tc::Color::Red
        };

        buf.set_color(tc::ColorSpec::new().set_fg(Some(color)).set_bold(true))?;
        buf.write_all(header.as_ref())?;
        buf.reset()?;
        buf.write_all(b"\n")?;
        buf.write_all(&body)?;

        let duration = start_time.elapsed();

        // TODO: Convert \r\n to \n on Windows.
        // TODO: Convert ASCII color codes to real colors on Windows.

        // Add a new line to the end if there isn't one.
        if !buf.as_slice().ends_with(b"\n") {
            buf.write_all(b"\n")?;
        }

        if verbose {
            buf.set_color(tc::ColorSpec::new().set_fg(Some(tc::Color::Blue)))?;
            write!(&mut buf, "Task duration")?;
            buf.reset()?;
            writeln!(&mut buf, ": {:.4?}", duration)?;
        }

        if let Err(err) = result {
            let mut red_fg = tc::ColorSpec::new();
            red_fg.set_fg(Some(tc::Color::Red));

            // Print out the chain of errors.
            let mut errors = err.iter_chain();

            if let Some(err) = errors.next() {
                buf.set_color(&red_fg)?;
                write!(&mut buf, "    Error")?;
                buf.reset()?;
                writeln!(&mut buf, ": {}", err)?;
            }

            for err in errors {
                buf.set_color(&red_fg)?;
                write!(&mut buf, "Caused by")?;
                buf.reset()?;
                writeln!(&mut buf, ": {}", err)?;
            }
        }

        bufwriter.print(&buf)?;

        Ok(())
    }
}

/// Log text to the console.
///
/// This buffers task output and prints out the task once it has finished.
pub struct Console {
    verbose: bool,
    start_time: Instant,
    bufwriter: Arc<tc::BufferWriter>,
}

impl Console {
    pub fn new(verbose: bool, color: tc::ColorChoice) -> Console {
        Console {
            verbose,
            bufwriter: Arc::new(tc::BufferWriter::stdout(color)),
            start_time: Instant::now(),
        }
    }
}

impl EventLogger for Console {
    type TaskLogger = ConsoleTask;

    fn begin_build(&mut self, _threads: usize) -> LogResult<()> {
        self.start_time = Instant::now();

        Ok(())
    }

    fn end_build(&mut self, _result: &Result<(), BuildError>) -> LogResult<()> {
        println!("---");
        println!("Build complete. Took {:.4?}", self.start_time.elapsed());

        Ok(())
    }

    fn start_task(
        &self,
        thread: usize,
        task: &task::Any,
    ) -> LogResult<ConsoleTask> {
        ConsoleTask::new(self.verbose, thread, task, self.bufwriter.clone())
    }

    fn delete(
        &self,
        thread: usize,
        resource: &res::Any,
        result: &Result<(), Error>,
    ) -> LogResult<()> {
        if let Err(err) = result {
            println!("[{}] Failed to delete: {} ({})", thread, resource, err);
        } else {
            println!("[{}] Deleted: {}", thread, resource);
        }

        Ok(())
    }

    fn checksum_error(
        &self,
        thread: usize,
        resource: &res::Any,
        error: &Error,
    ) -> LogResult<()> {
        println!(
            "[{}] Failed computing checksum for: {} ({})",
            thread, resource, error
        );
        Ok(())
    }
}
<commit_msg>Make errors highly visible<commit_after>// Copyright (c) 2018 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io::{self, Write};
use std::sync::Arc;
use std::time::Instant;

use crate::detect::Detected;
use crate::res;
use crate::task;

use crate::error::{BuildError, Error};

use super::traits::{EventLogger, LogResult, TaskLogger};

use termcolor::{self as tc, WriteColor};

pub struct ConsoleTask {
    verbose: bool,
    bufwriter: Arc<tc::BufferWriter>,
    thread: usize,
    task_name: String,
    body: Vec<u8>,
    start_time: Instant,
}

impl ConsoleTask {
    pub fn new(
        verbose: bool,
        thread: usize,
        task: &task::Any,
        bufwriter: Arc<tc::BufferWriter>,
    ) -> Result<ConsoleTask, Error> {
        Ok(ConsoleTask {
            verbose,
            bufwriter,
            thread,
            task_name: task.to_string(),
            body: Vec::new(),
            start_time: Instant::now(),
        })
    }
}

impl io::Write for ConsoleTask {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.body.write(buf)
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.body.write_all(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl TaskLogger for ConsoleTask {
    fn finish(self, result: &Result<Detected, Error>) -> LogResult<()> {
        let ConsoleTask {
            verbose,
            bufwriter,
            thread,
            task_name,
            body,
            start_time,
        } = self;

        let mut buf = bufwriter.buffer();

        let mut color = tc::ColorSpec::new();
        let color = if result.is_ok() {
            color.set_fg(Some(tc::Color::Green)).set_bold(true)
        } else {
            // Make errors highly-visible.
            color
                .set_fg(Some(tc::Color::White))
                .set_bold(true)
                .set_bg(Some(tc::Color::Red))
                .set_intense(true)
        };

        buf.set_color(color)?;
        write!(buf, "[{}] {}", thread, task_name)?;
        buf.reset()?;
        buf.write_all(b"\n")?;
        buf.write_all(&body)?;

        let duration = start_time.elapsed();

        // TODO: Convert \r\n to \n on Windows.
        // TODO: Convert ASCII color codes to real colors on Windows.

        // Add a new line to the end if there isn't one.
        if !buf.as_slice().ends_with(b"\n") {
            buf.write_all(b"\n")?;
        }

        if verbose {
            buf.set_color(tc::ColorSpec::new().set_fg(Some(tc::Color::Blue)))?;
            write!(&mut buf, "Task duration")?;
            buf.reset()?;
            writeln!(&mut buf, ": {:.4?}", duration)?;
        }

        if let Err(err) = result {
            let mut red_fg = tc::ColorSpec::new();
            red_fg.set_fg(Some(tc::Color::Red));

            // Print out the chain of errors.
            let mut errors = err.iter_chain();

            if let Some(err) = errors.next() {
                buf.set_color(&red_fg)?;
                write!(&mut buf, "    Error")?;
                buf.reset()?;
                writeln!(&mut buf, ": {}", err)?;
            }

            for err in errors {
                buf.set_color(&red_fg)?;
                write!(&mut buf, "Caused by")?;
                buf.reset()?;
                writeln!(&mut buf, ": {}", err)?;
            }
        }

        bufwriter.print(&buf)?;

        Ok(())
    }
}

/// Log text to the console.
///
/// This buffers task output and prints out the task once it has finished.
pub struct Console {
    verbose: bool,
    start_time: Instant,
    bufwriter: Arc<tc::BufferWriter>,
}

impl Console {
    pub fn new(verbose: bool, color: tc::ColorChoice) -> Console {
        Console {
            verbose,
            bufwriter: Arc::new(tc::BufferWriter::stdout(color)),
            start_time: Instant::now(),
        }
    }
}

impl EventLogger for Console {
    type TaskLogger = ConsoleTask;

    fn begin_build(&mut self, _threads: usize) -> LogResult<()> {
        self.start_time = Instant::now();

        Ok(())
    }

    fn end_build(&mut self, _result: &Result<(), BuildError>) -> LogResult<()> {
        println!("---");
        println!("Build complete. Took {:.4?}", self.start_time.elapsed());

        Ok(())
    }

    fn start_task(
        &self,
        thread: usize,
        task: &task::Any,
    ) -> LogResult<ConsoleTask> {
        ConsoleTask::new(self.verbose, thread, task, self.bufwriter.clone())
    }

    fn delete(
        &self,
        thread: usize,
        resource: &res::Any,
        result: &Result<(), Error>,
    ) -> LogResult<()> {
        if let Err(err) = result {
            println!("[{}] Failed to delete: {} ({})", thread, resource, err);
        } else {
            println!("[{}] Deleted: {}", thread, resource);
        }

        Ok(())
    }

    fn checksum_error(
        &self,
        thread: usize,
        resource: &res::Any,
        error: &Error,
    ) -> LogResult<()> {
        println!(
            "[{}] Failed computing checksum for: {} ({})",
            thread, resource, error
        );
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io::fs::{rmdir_recursive};
use core::{SourceId};
use util::{CargoResult, human, ChainError};
use ops::{read_manifest};
use std::io::{File};
use util::toml::{project_layout};

/// Cleans the project from build artifacts.

pub fn clean(manifest_path: &Path) -> CargoResult<()>
{
    let mut file = try!(File::open(manifest_path));
    let data = try!(file.read_to_end());
    let layout = project_layout(&manifest_path.dir_path());
    let (manifest, _) = try!(read_manifest(data.as_slice(),
                                           layout,
                                           &SourceId::for_path(manifest_path)));

    let build_dir = manifest.get_target_dir();

    if build_dir.exists() {
      return rmdir_recursive(build_dir).chain_error(|| human("Could not remove build directory"))
    }

    Ok(())
}
<commit_msg>auto merge of #199 : jdeseno/cargo/cleanup, r=alexcrichton<commit_after>use std::io::fs::{rmdir_recursive};
use core::{SourceId};
use util::{CargoResult, human, ChainError};
use ops::{read_manifest};
use std::io::{File};
use util::toml::{project_layout};

/// Cleans the project from build artifacts.

pub fn clean(manifest_path: &Path) -> CargoResult<()>
{
    let mut file = try!(File::open(manifest_path));
    let data = try!(file.read_to_end());
    let layout = project_layout(&manifest_path.dir_path());
    let (manifest, _) = try!(read_manifest(data.as_slice(),
                                           layout,
                                           &SourceId::for_path(manifest_path)));

    let build_dir = manifest.get_target_dir();

    if build_dir.exists() {
      rmdir_recursive(build_dir).chain_error(|| human("Could not remove build directory"))
    } else {
      Ok(())
    }
}
<|endoftext|>


<commit_before>//! Entry point for the dummy project.
//! This comment block tests `rust doc`;
//! you should be able to see it from the documentation
//! folder after running the project's rustDoc task
//! in Gradle.

/// Prints a message to test documentation of
/// functions.
///
/// # Parameters
/// * `message`: The message to print.
/// # Examples
///
/// This prints "Hi!":
/// ```
/// sayHello("Hi!");
/// ```
fn sayHello(message: &str) {
	println!("{}", message);
}

/// Entry point for the program.
fn main() {
	sayHello("Rust works!");
}<commit_msg>Make sayHello() public since we want to test documenting module members.<commit_after>//! Entry point for the dummy project.
//! This comment block tests `rust doc`;
//! you should be able to see it from the documentation
//! folder after running the project's rustDoc task
//! in Gradle.

/// Prints a message to test documentation of
/// functions.
///
/// # Parameters
/// * `message`: The message to print.
/// # Examples
///
/// This prints "Hi!":
/// ```
/// sayHello("Hi!");
/// ```
pub fn sayHello(message: &str) {
	println!("{}", message);
}

/// Entry point for the program.
fn main() {
	sayHello("Rust works!");
}<|endoftext|>


<commit_before>use super::{Core, Result};
use std::num::Wrapping;
use ram::ADDRBUS_MASK;

pub fn absolute_word(core: &mut Core) -> Result<u32> {
    let ea = try!(core.read_imm_i16()) as u32;
    Ok(ea & ADDRBUS_MASK)
}
pub fn absolute_long(core: &mut Core) -> Result<u32> {
    let ea = try!(core.read_imm_u32());
    Ok(ea & ADDRBUS_MASK)
}
pub fn predecrement_ay_8(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    predecrement_8(core, reg_ndx)
}
pub fn postincrement_ay_8(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    postincrement_8(core, reg_ndx)
}
pub fn predecrement_ay_16(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    predecrement_16(core, reg_ndx)
}
pub fn postincrement_ay_16(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    postincrement_16(core, reg_ndx)
}
pub fn predecrement_ay_32(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    predecrement_32(core, reg_ndx)
}
pub fn postincrement_ay_32(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    postincrement_32(core, reg_ndx)
}
pub fn address_indirect_ay(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    core.dar[reg_ndx] & ADDRBUS_MASK
}
pub fn displacement_ay(core: &mut Core) -> Result<u32> {
    let reg_val = core.dar[ir_ay!(core)];
    displacement(core, reg_val)
}
pub fn displacement_pc(core: &mut Core) -> Result<u32> {
    let old_pc = core.pc;
    displacement(core, old_pc)
}
pub fn index_ay(core: &mut Core) -> Result<u32> {
    let reg_val = core.dar[ir_ay!(core)];
    index(core, reg_val)
}
pub fn index_pc(core: &mut Core) -> Result<u32> {
    let pc = core.pc;
    index(core, pc)
}
pub fn predecrement_ax_8(core: &mut Core) -> u32 {
    let reg_ndx = ir_ax!(core);
    predecrement_8(core, reg_ndx)
}
pub fn predecrement_ax_16(core: &mut Core) -> u32 {
       let reg_ndx = ir_ax!(core);
       predecrement_16(core, reg_ndx)
}
pub fn predecrement_ax_32(core: &mut Core) -> u32 {
       let reg_ndx = ir_ax!(core);
       predecrement_32(core, reg_ndx)
}

fn predecrement_8(core: &mut Core, reg_ndx: usize) -> u32 {
    // pre-decrement
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) - match reg_ndx {
        15 => Wrapping(2), // A7 is kept even
         _ => Wrapping(1)
    }).0;
    core.dar[reg_ndx] & ADDRBUS_MASK
}
fn postincrement_8(core: &mut Core, reg_ndx: usize) -> u32 {
    // post-increment
    let ea = core.dar[reg_ndx];
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) + match reg_ndx {
        15 => Wrapping(2), // A7 is kept even
         _ => Wrapping(1)
    }).0;
    ea & ADDRBUS_MASK
}
fn predecrement_16(core: &mut Core, reg_ndx: usize) -> u32 {
    // pre-decrement
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) - Wrapping(2)).0;
    core.dar[reg_ndx] & ADDRBUS_MASK
}
fn postincrement_16(core: &mut Core, reg_ndx: usize) -> u32 {
    // post-increment
    let ea = core.dar[reg_ndx];
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) + Wrapping(2)).0;
    ea & ADDRBUS_MASK
}
fn predecrement_32(core: &mut Core, reg_ndx: usize) -> u32 {
    // pre-decrement
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) - Wrapping(4)).0;
    core.dar[reg_ndx] & ADDRBUS_MASK
}
fn postincrement_32(core: &mut Core, reg_ndx: usize) -> u32 {
    // post-increment
    let ea = core.dar[reg_ndx];
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) + Wrapping(4)).0;
    ea & ADDRBUS_MASK
}
fn displacement(core: &mut Core, reg_val: u32) -> Result<u32> {
    let displacement = try!(core.read_imm_i16());
    let ea = (Wrapping(reg_val) + Wrapping(displacement as u32)).0;
    Ok(ea & ADDRBUS_MASK)
}
// Brief Extension Word format (see M68000 PRM section 2.1)
const LONG_INDEX_MASK: u16 = 0x0800;
fn index(core: &mut Core, reg_val: u32) -> Result<u32> {
    let extension = try!(core.read_imm_u16());
    // top four bits = (D/A RRR) matches our register array layout
    let xreg_ndx = (extension>>12) as usize;
    let xn = core.dar[xreg_ndx];
    let xn = if (extension & LONG_INDEX_MASK) > 0 {xn} else {(xn as i16) as u32};

      let index = extension as i8;
    let ea = (Wrapping(reg_val) + Wrapping(xn) + Wrapping(index as u32)).0;
    Ok(ea & ADDRBUS_MASK)
}

#[cfg(test)]
mod tests {
    use super::super::Core;
    use super::super::effective_address::{predecrement_8, postincrement_8};
    use ram::{ADDRBUS_MASK};

    #[test]
    fn predecrement_wraps() {
        let mut core = Core::new(0x40);
        for i in 0..8 {
            // pre-decrement should wrap to 0xFFFFFFFF
            // but the following read should be from address 0x00FFFFFF
            // i.e. limited by the 24-bit address bus width
            core.dar[8+i as usize] = 0;
        }
        let ea = predecrement_8(&mut core, 8+0);
        assert_eq!(0x00FFFFFF, ea);
    }
    #[test]
    fn predecrement_8_wraps_a7_by_two() {
        let mut core = Core::new(0x40);
        for i in 0..8 {
            // pre-decrement should wrap to 0xFFFFFFFF
            // but the following read should be from address 0x00FFFFFF
            // i.e. limited by the 24-bit address bus width
            core.dar[8+i as usize] = 0;
        }
        let ea = predecrement_8(&mut core, 8+7);
        // a7 is kept even
        assert_eq!(0x00FFFFFE, ea);
    }
    #[test]
    fn postincrement_wraps() {
        let mut core = Core::new(0x40);
        for i in 0..8 {
            // pre-decrement should wrap to 0xFFFFFFFF
            // but the following read should be from address 0x00FFFFFF
            // i.e. limited by the 24-bit address bus width
            core.dar[8+i as usize] = 0xFFFFFFFF;
        }
        let ea = postincrement_8(&mut core, 8+0);
        assert_eq!(0xFFFFFFFF & ADDRBUS_MASK, ea);
        assert_eq!(0x0, core.dar[8+0]);
    }
    #[test]
    fn postincrement_8_wraps_a7_by_two() {
        let mut core = Core::new(0x40);
        for i in 0..8 {
            // pre-decrement should wrap to 0xFFFFFFFF
            // but the following read should be from address 0x00FFFFFF
            // i.e. limited by the 24-bit address bus width
            core.dar[8+i as usize] = 0xFFFFFFFE;
        }
        let ea = postincrement_8(&mut core, 8+7);
        // a7 is kept even
        assert_eq!(0xFFFFFFFE & ADDRBUS_MASK, ea);
        assert_eq!(0x0, core.dar[8+7]);
    }
}
<commit_msg>Add 8/16/32 bit postincrement_ax ea calculation<commit_after>use super::{Core, Result};
use std::num::Wrapping;
use ram::ADDRBUS_MASK;

pub fn absolute_word(core: &mut Core) -> Result<u32> {
    let ea = try!(core.read_imm_i16()) as u32;
    Ok(ea & ADDRBUS_MASK)
}
pub fn absolute_long(core: &mut Core) -> Result<u32> {
    let ea = try!(core.read_imm_u32());
    Ok(ea & ADDRBUS_MASK)
}
pub fn predecrement_ay_8(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    predecrement_8(core, reg_ndx)
}
pub fn postincrement_ay_8(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    postincrement_8(core, reg_ndx)
}
pub fn predecrement_ay_16(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    predecrement_16(core, reg_ndx)
}
pub fn postincrement_ay_16(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    postincrement_16(core, reg_ndx)
}
pub fn predecrement_ay_32(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    predecrement_32(core, reg_ndx)
}
pub fn postincrement_ay_32(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    postincrement_32(core, reg_ndx)
}
pub fn address_indirect_ay(core: &mut Core) -> u32 {
    let reg_ndx = ir_ay!(core);
    core.dar[reg_ndx] & ADDRBUS_MASK
}
pub fn displacement_ay(core: &mut Core) -> Result<u32> {
    let reg_val = core.dar[ir_ay!(core)];
    displacement(core, reg_val)
}
pub fn displacement_pc(core: &mut Core) -> Result<u32> {
    let old_pc = core.pc;
    displacement(core, old_pc)
}
pub fn index_ay(core: &mut Core) -> Result<u32> {
    let reg_val = core.dar[ir_ay!(core)];
    index(core, reg_val)
}
pub fn index_pc(core: &mut Core) -> Result<u32> {
    let pc = core.pc;
    index(core, pc)
}
pub fn predecrement_ax_8(core: &mut Core) -> u32 {
    let reg_ndx = ir_ax!(core);
    predecrement_8(core, reg_ndx)
}
pub fn predecrement_ax_16(core: &mut Core) -> u32 {
    let reg_ndx = ir_ax!(core);
    predecrement_16(core, reg_ndx)
}
pub fn predecrement_ax_32(core: &mut Core) -> u32 {
    let reg_ndx = ir_ax!(core);
    predecrement_32(core, reg_ndx)
}
pub fn postincrement_ax_8(core: &mut Core) -> u32 {
    let reg_ndx = ir_ax!(core);
    postincrement_8(core, reg_ndx)
}
pub fn postincrement_ax_16(core: &mut Core) -> u32 {
    let reg_ndx = ir_ax!(core);
    postincrement_16(core, reg_ndx)
}
pub fn postincrement_ax_32(core: &mut Core) -> u32 {
    let reg_ndx = ir_ax!(core);
    postincrement_32(core, reg_ndx)
}

fn predecrement_8(core: &mut Core, reg_ndx: usize) -> u32 {
    // pre-decrement
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) - match reg_ndx {
        15 => Wrapping(2), // A7 is kept even
         _ => Wrapping(1)
    }).0;
    core.dar[reg_ndx] & ADDRBUS_MASK
}
fn postincrement_8(core: &mut Core, reg_ndx: usize) -> u32 {
    // post-increment
    let ea = core.dar[reg_ndx];
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) + match reg_ndx {
        15 => Wrapping(2), // A7 is kept even
         _ => Wrapping(1)
    }).0;
    ea & ADDRBUS_MASK
}
fn predecrement_16(core: &mut Core, reg_ndx: usize) -> u32 {
    // pre-decrement
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) - Wrapping(2)).0;
    core.dar[reg_ndx] & ADDRBUS_MASK
}
fn postincrement_16(core: &mut Core, reg_ndx: usize) -> u32 {
    // post-increment
    let ea = core.dar[reg_ndx];
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) + Wrapping(2)).0;
    ea & ADDRBUS_MASK
}
fn predecrement_32(core: &mut Core, reg_ndx: usize) -> u32 {
    // pre-decrement
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) - Wrapping(4)).0;
    core.dar[reg_ndx] & ADDRBUS_MASK
}
fn postincrement_32(core: &mut Core, reg_ndx: usize) -> u32 {
    // post-increment
    let ea = core.dar[reg_ndx];
    core.dar[reg_ndx] = (Wrapping(core.dar[reg_ndx]) + Wrapping(4)).0;
    ea & ADDRBUS_MASK
}
fn displacement(core: &mut Core, reg_val: u32) -> Result<u32> {
    let displacement = try!(core.read_imm_i16());
    let ea = (Wrapping(reg_val) + Wrapping(displacement as u32)).0;
    Ok(ea & ADDRBUS_MASK)
}
// Brief Extension Word format (see M68000 PRM section 2.1)
const LONG_INDEX_MASK: u16 = 0x0800;
fn index(core: &mut Core, reg_val: u32) -> Result<u32> {
    let extension = try!(core.read_imm_u16());
    // top four bits = (D/A RRR) matches our register array layout
    let xreg_ndx = (extension>>12) as usize;
    let xn = core.dar[xreg_ndx];
    let xn = if (extension & LONG_INDEX_MASK) > 0 {xn} else {(xn as i16) as u32};

      let index = extension as i8;
    let ea = (Wrapping(reg_val) + Wrapping(xn) + Wrapping(index as u32)).0;
    Ok(ea & ADDRBUS_MASK)
}

#[cfg(test)]
mod tests {
    use super::super::Core;
    use super::super::effective_address::{predecrement_8, postincrement_8};
    use ram::{ADDRBUS_MASK};

    #[test]
    fn predecrement_wraps() {
        let mut core = Core::new(0x40);
        for i in 0..8 {
            // pre-decrement should wrap to 0xFFFFFFFF
            // but the following read should be from address 0x00FFFFFF
            // i.e. limited by the 24-bit address bus width
            core.dar[8+i as usize] = 0;
        }
        let ea = predecrement_8(&mut core, 8+0);
        assert_eq!(0x00FFFFFF, ea);
    }
    #[test]
    fn predecrement_8_wraps_a7_by_two() {
        let mut core = Core::new(0x40);
        for i in 0..8 {
            // pre-decrement should wrap to 0xFFFFFFFF
            // but the following read should be from address 0x00FFFFFF
            // i.e. limited by the 24-bit address bus width
            core.dar[8+i as usize] = 0;
        }
        let ea = predecrement_8(&mut core, 8+7);
        // a7 is kept even
        assert_eq!(0x00FFFFFE, ea);
    }
    #[test]
    fn postincrement_wraps() {
        let mut core = Core::new(0x40);
        for i in 0..8 {
            // pre-decrement should wrap to 0xFFFFFFFF
            // but the following read should be from address 0x00FFFFFF
            // i.e. limited by the 24-bit address bus width
            core.dar[8+i as usize] = 0xFFFFFFFF;
        }
        let ea = postincrement_8(&mut core, 8+0);
        assert_eq!(0xFFFFFFFF & ADDRBUS_MASK, ea);
        assert_eq!(0x0, core.dar[8+0]);
    }
    #[test]
    fn postincrement_8_wraps_a7_by_two() {
        let mut core = Core::new(0x40);
        for i in 0..8 {
            // pre-decrement should wrap to 0xFFFFFFFF
            // but the following read should be from address 0x00FFFFFF
            // i.e. limited by the 24-bit address bus width
            core.dar[8+i as usize] = 0xFFFFFFFE;
        }
        let ea = postincrement_8(&mut core, 8+7);
        // a7 is kept even
        assert_eq!(0xFFFFFFFE & ADDRBUS_MASK, ea);
        assert_eq!(0x0, core.dar[8+7]);
    }
}
<|endoftext|>