<commit_before>//! Operations on manifest files.

use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, BufRead};
use std::path::{Path, PathBuf};
use std::str;

/// Manifest file info.
pub struct Manifest {
    hostname: String,
    local_dir: PathBuf,
    volumes: Vec<Option<Volume>>,
}

/// Volume info.
pub struct Volume {
    start_path: PathBuf,
    end_path: PathBuf,
    hash_type: String,
    hash: Vec<u8>,
}

/// wip
#[derive(Debug)]
pub enum ParseError {
    /// wip
    Io(io::Error),
    /// wip
    MissingHostname,
    /// wip
    MissingLocaldir,
}

struct ManifestParser<R> {
    input: R,
    buf: Vec<u8>,
    hostname: String,
    local_dir: Option<PathBuf>,
    volumes: Vec<Option<Volume>>,
}

impl Manifest {
    /// Parses a stream to get a manifest.
    pub fn parse<R: BufRead>(m: &mut R) -> Result<Self, ParseError> {
        let parser = ManifestParser::new(m);
        parser.parse()
    }

    /// wip
    pub fn hostname(&self) -> Option<&str> {
        Some(&self.hostname)
    }

    /// wip
    pub fn local_dir(&self) -> Option<&Path> {
        Some(&self.local_dir)
    }

    /// wip
    pub fn max_vol_num(&self) -> usize {
        self.volumes.len()
    }

    /// wip
    pub fn volume(&self, num: usize) -> Option<&Volume> {
        self.volumes.get(num).and_then(|v| v.as_ref())
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::Io(ref err) => err.description(),
            ParseError::MissingHostname => "missing 'Hostname' keyword",
            ParseError::MissingLocaldir => "missing 'Localdir' keyword",
        }
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::Io(ref e) => write!(fmt, "{}", e),
            _ => write!(fmt, "{}", self.description()),
        }
    }
}

impl From<io::Error> for ParseError {
    fn from(err: io::Error) -> ParseError {
        ParseError::Io(err)
    }
}

impl<R: BufRead> ManifestParser<R> {
    pub fn new(input: R) -> Self {
        ManifestParser {
            input: input,
            buf: vec![],
            hostname: String::new(),
            local_dir: None,
            volumes: vec![],
        }
    }

    pub fn parse(mut self) -> Result<Manifest, ParseError> {
        // parse hostname
        if !try!(self.consume_keyword("Hostname")) {
            return Err(ParseError::MissingHostname);
        }
        try!(self.consume_whitespace());
        try!(self.input.read_line(&mut self.hostname));

        // parse localdir
        if !try!(self.consume_keyword("Localdir")) {
            return Err(ParseError::MissingLocaldir);
        }
        try!(self.consume_whitespace());

        // make result
        Ok(Manifest {
            hostname: self.hostname,
            local_dir: self.local_dir.unwrap(),
            volumes: self.volumes,
        })
    }

    fn consume_keyword(&mut self, key: &str) -> io::Result<bool> {
        try!(self.input.read_until(b' ', &mut self.buf));
        Ok(match_keyword(&self.buf, key))
    }

    fn consume_whitespace(&mut self) -> io::Result<()> {
        loop {
            let (pos, end) = {
                let buf = try!(self.input.fill_buf());
                match buf.iter().cloned().position(|b| b != b' ') {
                    Some(p) => (p, true),
                    None => (buf.len(), buf.is_empty()),
                }
            };
            self.input.consume(pos);
            if end {
                return Ok(());
            }
        }
    }

    fn read_param(&mut self) -> io::Result<Vec<u8>> {
        if try!(self.consume_byte(b'"')) {
            try!(self.input.read_until(b'"', &mut self.buf));
        } else {
            try!(self.input.read_until(b'\n', &mut self.buf));
        }
        let mut result = Vec::with_capacity(self.buf.len());
        // unescape
        for (i, b) in self.buf.iter().cloned().enumerate() {
            if b != b'\\' {
                result.push(b);
            } else {
                let rest = self.buf.split_at(i).1;
                if rest.starts_with(b"\\") {
                    result.push(b'\\');
                } else if rest.starts_with(b"%20") {
                    result.push(b' ');
                } else if rest.starts_with(b"\"") {
                    result.push(b'"');
                }
            }
        }
        Ok(result)
    }

    fn consume_byte(&mut self, expected: u8) -> io::Result<bool> {
        let found = {
            let buf = try!(self.input.fill_buf());
            buf.first().map_or(false, |b| *b == expected)
        };
        if found {
            self.input.consume(1);
        }
        Ok(found)
    }
}

#[inline]
fn match_keyword(buf: &[u8], key: &str) -> bool {
    str::from_utf8(&buf).ok().map_or(false, |s| s == key)
}
<commit_msg>Fixed read manifest param<commit_after>//! Operations on manifest files.

use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, BufRead};
use std::path::{Path, PathBuf};
use std::str;

/// Manifest file info.
pub struct Manifest {
    hostname: String,
    local_dir: PathBuf,
    volumes: Vec<Option<Volume>>,
}

/// Volume info.
pub struct Volume {
    start_path: PathBuf,
    end_path: PathBuf,
    hash_type: String,
    hash: Vec<u8>,
}

/// wip
#[derive(Debug)]
pub enum ParseError {
    /// wip
    Io(io::Error),
    /// wip
    MissingHostname,
    /// wip
    MissingLocaldir,
}

struct ManifestParser<R> {
    input: R,
    buf: Vec<u8>,
    hostname: String,
    local_dir: Option<PathBuf>,
    volumes: Vec<Option<Volume>>,
}

impl Manifest {
    /// Parses a stream to get a manifest.
    pub fn parse<R: BufRead>(m: &mut R) -> Result<Self, ParseError> {
        let parser = ManifestParser::new(m);
        parser.parse()
    }

    /// wip
    pub fn hostname(&self) -> Option<&str> {
        Some(&self.hostname)
    }

    /// wip
    pub fn local_dir(&self) -> Option<&Path> {
        Some(&self.local_dir)
    }

    /// wip
    pub fn max_vol_num(&self) -> usize {
        self.volumes.len()
    }

    /// wip
    pub fn volume(&self, num: usize) -> Option<&Volume> {
        self.volumes.get(num).and_then(|v| v.as_ref())
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::Io(ref err) => err.description(),
            ParseError::MissingHostname => "missing 'Hostname' keyword",
            ParseError::MissingLocaldir => "missing 'Localdir' keyword",
        }
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::Io(ref e) => write!(fmt, "{}", e),
            _ => write!(fmt, "{}", self.description()),
        }
    }
}

impl From<io::Error> for ParseError {
    fn from(err: io::Error) -> ParseError {
        ParseError::Io(err)
    }
}

impl<R: BufRead> ManifestParser<R> {
    pub fn new(input: R) -> Self {
        ManifestParser {
            input: input,
            buf: vec![],
            hostname: String::new(),
            local_dir: None,
            volumes: vec![],
        }
    }

    pub fn parse(mut self) -> Result<Manifest, ParseError> {
        // parse hostname
        if !try!(self.consume_keyword("Hostname")) {
            return Err(ParseError::MissingHostname);
        }
        try!(self.consume_whitespace());
        try!(self.input.read_line(&mut self.hostname));

        // parse localdir
        if !try!(self.consume_keyword("Localdir")) {
            return Err(ParseError::MissingLocaldir);
        }
        try!(self.consume_whitespace());

        // make result
        Ok(Manifest {
            hostname: self.hostname,
            local_dir: self.local_dir.unwrap(),
            volumes: self.volumes,
        })
    }

    fn consume_keyword(&mut self, key: &str) -> io::Result<bool> {
        try!(self.input.read_until(b' ', &mut self.buf));
        Ok(match_keyword(&self.buf, key))
    }

    fn consume_whitespace(&mut self) -> io::Result<()> {
        loop {
            let (pos, end) = {
                let buf = try!(self.input.fill_buf());
                match buf.iter().cloned().position(|b| b != b' ') {
                    Some(p) => (p, true),
                    None => (buf.len(), buf.is_empty()),
                }
            };
            self.input.consume(pos);
            if end {
                return Ok(());
            }
        }
    }

    fn read_param(&mut self) -> io::Result<Vec<u8>> {
        if try!(self.consume_byte(b'"')) {
            try!(self.input.read_until(b'"', &mut self.buf));
        } else {
            try!(self.input.read_until(b'\n', &mut self.buf));
        }
        let mut result = Vec::with_capacity(self.buf.len());
        // unescape
        for (i, b) in self.buf.iter().cloned().enumerate() {
            if b != b'\\' {
                result.push(b);
            } else {
                // expects a \xNN where NN is a number string representing the escaped char
                // e.g. \x20 is the space ' '
                if self.buf.len() - i >= 4 && self.buf[i + 1] == b'x' {
                    let num = (self.buf[i + 2] - b'0') << 4 + self.buf[i + 3] - b'0';
                    result.push(b);
                }
            }
        }
        Ok(result)
    }

    fn consume_byte(&mut self, expected: u8) -> io::Result<bool> {
        let found = {
            let buf = try!(self.input.fill_buf());
            buf.first().map_or(false, |b| *b == expected)
        };
        if found {
            self.input.consume(1);
        }
        Ok(found)
    }
}

#[inline]
fn match_keyword(buf: &[u8], key: &str) -> bool {
    str::from_utf8(&buf).ok().map_or(false, |s| s == key)
}
<|endoftext|>


<commit_before>//! ICWS '94 draft
//!

use std::ops::{Index, IndexMut};

// #[derive(Clone, Copy, Debug, Default)]
// pub struct Address(u32);
pub type Address = u32;

#[derive(Clone, Copy, Debug)]
pub enum Opcode {
    DAT, // terminate process
    MOV, // move from A to B
    ADD, // add A to B, store result in B
    SUB, // subtract A from B, store result in B
    MUL, // multiply A by B, store result in B
    DIV, // divide B by A, store result in B if A <> 0, else terminate
    MOD, // divide B by A, store remainder in B if A <> 0, else terminate
    JMP, // transfer execution to A
    JMZ, // transfer execution to A if B is zero
    JMN, // transfer execution to A if B is non-zero
    DJN, // decrement B, if B is non-zero, transfer execution to A
    CMP, // same as SEQ
    SLT, // skip next instruction if A is less than B
    SPL, // split off process to A
    SEQ, // (*) Skip next instruction if A is equal to B
    SNE, // (*) Skip next instruction if A is not equal to B
    NOP, // (*) No operation
    LDP, // (+) Load P-space cell A into core address B
    STP, // (+) Store A-number into P-space cell B
}

impl Default for Opcode {
    fn default() -> Self {
        Opcode::DAT
    }
}

#[derive(Clone, Copy, Debug)]
pub enum Modifier {
    A,
    B,
    AB,
    BA,
    F,
    X,
    I,
}

impl Default for Modifier {
    fn default() -> Self {
        Modifier::A
    }
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Mode {
    IMMEDIATE, // #
    DIRECT, // $ (Default)
    INDIRECT, // @
    DECREMENT, // <
    INCREMENT, // >
}

impl Default for Mode {
    fn default() -> Self {
        Mode::IMMEDIATE
    }
}

#[derive(Clone, Copy, Debug, Default)]
pub struct Instruction {
    pub opcode: Opcode,
    pub modifier: Modifier,
    pub a_mode: Mode,
    pub a_number: Address,
    pub b_mode: Mode,
    pub b_number: Address,
}

impl Instruction {
    pub fn random() -> Self {
        Instruction::default()  // XXX Need real random implementation
    }
}

#[derive(Clone, Copy, Debug, Default)]
pub struct Warrior(u32);

#[derive(Debug)]
pub struct TaskQueue {
    task_limit: usize,
    task_pointer: Vec<Address>,
}

impl TaskQueue {
    fn new(limit: usize) -> Self {
        TaskQueue {
            task_limit: limit,
            task_pointer: Vec::<Address>::with_capacity(limit),
        }
    }

    pub fn queue(&mut self, addr: Address) {
        if self.task_pointer.len() < self.task_limit {
            self.task_pointer.push(addr);
        }
    }

    pub fn next(&mut self) -> Option<Address> {
        if self.task_pointer.len() > 0 {
            Some(self.task_pointer.remove(0))
        } else {
            None
        }
    }
}

#[derive(Debug)]
struct CoreMemory(Vec<Instruction>);

impl Index<Address> for CoreMemory {
    type Output = Instruction;

    fn index<'a>(&'a self, _index: Address) -> &'a Instruction {
        &self.0[_index as usize]
    }
}

impl IndexMut<Address> for CoreMemory {
    fn index_mut<'a>(&'a mut self, _index: Address) -> &'a mut Instruction {
        &mut self.0[_index as usize]
    }
}

#[derive(Debug)]
pub struct Core {
    core_size: Address,
    core: CoreMemory,
    warrior: [TaskQueue; 2],
    // pc: Address,
    read_limit: Address,
    write_limit: Address,
}

impl Core {
    pub fn queue(&mut self, warrior: usize, task_pointer: Address) {
        self.warrior[warrior].queue(task_pointer)
    }

    fn fold(&self, pointer: Address, limit: Address) -> Address {
        let mut result = pointer % limit;
        if result > limit / 2 {
            result += self.core_size - limit;
        }
        result
    }

    fn direct(&self, number: Address) -> (Address, Address) {
        (self.fold(number, self.read_limit),
         self.fold(number, self.write_limit))
    }

    fn indirect_pointer(&self, pc: Address, number: Address, limit: Address) -> Address {
        let p = self.fold(number, limit);
        let i = p + self.core[((pc + p) % self.core_size)].b_number;
        self.fold(i, limit)
    }

    fn indirect(&self, pc: Address, number: Address) -> (Address, Address) {
        (self.indirect_pointer(pc, number, self.read_limit),
         self.indirect_pointer(pc, number, self.write_limit))
    }

    pub fn evaluate(&mut self, pc: Address, mode: Mode, number: Address) -> (Address, Address) {
        // let mut rp: Address;
        // let mut wp: Address;
        let rlim = self.read_limit;
        let wlim = self.write_limit;

        match mode {
            Mode::IMMEDIATE => (0, 0),
            Mode::DIRECT => self.direct(number),
            Mode::INDIRECT => self.indirect(pc, number),
            Mode::DECREMENT => (self.fold(number, rlim), self.fold(number, wlim)),
            Mode::INCREMENT => (self.fold(number, rlim), self.fold(number, wlim)),
        }
    }

    pub fn emi94(&mut self, pc: Address) {
        let ir: Instruction;
        let ira: Instruction;
        let irb: Instruction;
        let mut rpa: Address;
        let mut wpa: Address;
        let rpb: Address;
        let wpb: Address;
        let mut pip: Address = 0;

        ir = self.core[pc];

        // Evaluate A-operand
        //
        if ir.a_mode == Mode::IMMEDIATE {
            // For instructions with an Immediate A-mode, the Pointer A
            // points to the source of the current instruction.
            rpa = 0;
            wpa = 0;
        } else {
            // For instructions with a Direct A-mode, the Pointer A
            // points to the instruction IR.ANumber away, relative to
            // the Program Counter.
            rpa = self.fold(ir.a_number, self.read_limit);
            wpa = self.fold(ir.a_number, self.write_limit);

            if ir.a_mode != Mode::DIRECT {
                if ir.a_mode == Mode::DECREMENT {
                    self.core[((pc + wpa) % self.core_size)].b_number =
                        (self.core[((pc + wpa) % self.core_size)].b_number + self.core_size - 1) %
                        self.core_size;
                }

                if ir.a_mode == Mode::INCREMENT {
                    pip = (pc + wpa) % self.core_size;
                }

                rpa = self.fold((rpa + self.core[((pc + rpa) % self.core_size)].b_number),
                                self.read_limit);
                wpa = self.fold((wpa + self.core[((pc + wpa) % self.core_size)].b_number),
                                self.write_limit);
            }
        }

        ira = self.core[((pc + rpa) % self.core_size)];

        if ir.a_mode == Mode::INCREMENT {
            self.core[pip].b_number = (self.core[pip].b_number + 1) % self.core_size;
        }

    }
}

#[derive(Debug)]
pub enum InitialInstruction {
    Default,
    Random,
    Instruction(Instruction),
}

#[derive(Debug)]
pub struct CoreBuilder {
    core_size: u32,
    initial_instruction: InitialInstruction,
    task_limit: usize,
}

impl CoreBuilder {
    pub fn new() -> Self {
        CoreBuilder {
            core_size: 8192,
            initial_instruction: InitialInstruction::Default,
            task_limit: 64,
        }
    }

    pub fn coresize(&mut self, size: u32) -> &Self {
        self.core_size = size;
        self
    }

    pub fn initial_instruction(&mut self, insn: InitialInstruction) -> &Self {
        self.initial_instruction = insn;
        self
    }

    pub fn task_limit(&mut self, limit: usize) -> &Self {
        self.task_limit = limit;
        self
    }

    pub fn build(&self) -> Core {
        let mut instructions = Vec::<Instruction>::new();
        for _ in 0..self.core_size {
            instructions.push(match self.initial_instruction {
                InitialInstruction::Default => Instruction::default(),
                InitialInstruction::Random => Instruction::random(),
                InitialInstruction::Instruction(insn) => insn,
            })
        }

        Core {
            core_size: self.core_size,
            core: CoreMemory(instructions),
            warrior: [TaskQueue::new(self.task_limit), TaskQueue::new(self.task_limit)],
            read_limit: 300,
            write_limit: 300,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn task_queue_simple() {
        let mut tq = TaskQueue::new(2);
        tq.queue(1);
        tq.queue(3);
        assert_eq!(tq.next(), Some(1));
        assert_eq!(tq.next(), Some(3));
        assert_eq!(tq.next(), None);
    }

    #[test]
    fn task_queue_limit() {
        let mut tq = TaskQueue::new(3);
        tq.queue(100);
        tq.queue(200);
        tq.queue(300);
        tq.queue(400);

        assert_eq!(tq.next(), Some(100));
        assert_eq!(tq.next(), Some(200));
        assert_eq!(tq.next(), Some(300));
        assert_eq!(tq.next(), None);
    }

    #[test]
    fn task_queue_empty() {
        let mut tq = TaskQueue::new(100);

        assert_eq!(tq.next(), None);
    }
}
<commit_msg>Make CoreMemory indexing take wrapping into account<commit_after>//! ICWS '94 draft
//!

use std::ops::{Index, IndexMut};

// #[derive(Clone, Copy, Debug, Default)]
// pub struct Address(u32);
pub type Address = u32;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Opcode {
    DAT, // terminate process
    MOV, // move from A to B
    ADD, // add A to B, store result in B
    SUB, // subtract A from B, store result in B
    MUL, // multiply A by B, store result in B
    DIV, // divide B by A, store result in B if A <> 0, else terminate
    MOD, // divide B by A, store remainder in B if A <> 0, else terminate
    JMP, // transfer execution to A
    JMZ, // transfer execution to A if B is zero
    JMN, // transfer execution to A if B is non-zero
    DJN, // decrement B, if B is non-zero, transfer execution to A
    CMP, // same as SEQ
    SLT, // skip next instruction if A is less than B
    SPL, // split off process to A
    SEQ, // (*) Skip next instruction if A is equal to B
    SNE, // (*) Skip next instruction if A is not equal to B
    NOP, // (*) No operation
    LDP, // (+) Load P-space cell A into core address B
    STP, // (+) Store A-number into P-space cell B
}

impl Default for Opcode {
    fn default() -> Self {
        Opcode::DAT
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Modifier {
    A,
    B,
    AB,
    BA,
    F,
    X,
    I,
}

impl Default for Modifier {
    fn default() -> Self {
        Modifier::A
    }
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Mode {
    IMMEDIATE, // #
    DIRECT, // $ (Default)
    INDIRECT, // @
    DECREMENT, // <
    INCREMENT, // >
}

impl Default for Mode {
    fn default() -> Self {
        Mode::IMMEDIATE
    }
}

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Instruction {
    pub opcode: Opcode,
    pub modifier: Modifier,
    pub a_mode: Mode,
    pub a_number: Address,
    pub b_mode: Mode,
    pub b_number: Address,
}

impl Instruction {
    pub fn random() -> Self {
        Instruction::default()  // XXX Need real random implementation
    }
}

#[derive(Clone, Copy, Debug, Default)]
pub struct Warrior(u32);

#[derive(Debug)]
pub struct TaskQueue {
    task_limit: usize,
    task_pointer: Vec<Address>,
}

impl TaskQueue {
    fn new(limit: usize) -> Self {
        TaskQueue {
            task_limit: limit,
            task_pointer: Vec::<Address>::with_capacity(limit),
        }
    }

    pub fn queue(&mut self, addr: Address) {
        if self.task_pointer.len() < self.task_limit {
            self.task_pointer.push(addr);
        }
    }

    pub fn next(&mut self) -> Option<Address> {
        if self.task_pointer.len() > 0 {
            Some(self.task_pointer.remove(0))
        } else {
            None
        }
    }
}

#[derive(Debug)]
pub struct CoreMemory(Address, Vec<Instruction>);

impl Index<Address> for CoreMemory {
    type Output = Instruction;

    fn index<'a>(&'a self, _index: Address) -> &'a Instruction {
        &self.1[(_index % self.0) as usize]
    }
}

impl IndexMut<Address> for CoreMemory {
    fn index_mut<'a>(&'a mut self, _index: Address) -> &'a mut Instruction {
        &mut self.1[(_index % self.0) as usize]
    }
}

impl CoreMemory {
    fn new(size: Address, initial_instruction: InitialInstruction) -> Self {
        let mut instructions = Vec::<Instruction>::new();
        for _ in 0..size {
            instructions.push(match initial_instruction {
                InitialInstruction::Default => Instruction::default(),
                InitialInstruction::Random => Instruction::random(),
                InitialInstruction::Instruction(insn) => insn,
            })
        }

        CoreMemory(size, instructions)
    }

    fn size(&self) -> Address {
        self.0
    }
}

#[derive(Debug)]
pub struct Core {
    core: CoreMemory,
    warrior: [TaskQueue; 2],
    read_limit: Address,
    write_limit: Address,
}

impl Core {
    pub fn queue(&mut self, warrior: usize, task_pointer: Address) {
        self.warrior[warrior].queue(task_pointer)
    }

    fn fold(&self, pointer: Address, limit: Address) -> Address {
        let mut result = pointer % limit;
        if result > limit / 2 {
            result += self.core.size() - limit;
        }
        result
    }

    fn direct(&self, number: Address) -> (Address, Address) {
        (self.fold(number, self.read_limit),
         self.fold(number, self.write_limit))
    }

    fn indirect_pointer(&self, pc: Address, number: Address, limit: Address) -> Address {
        let p = self.fold(number, limit);
        let i = p + self.core[pc + p].b_number;
        self.fold(i, limit)
    }

    fn indirect(&self, pc: Address, number: Address) -> (Address, Address) {
        (self.indirect_pointer(pc, number, self.read_limit),
         self.indirect_pointer(pc, number, self.write_limit))
    }

    pub fn evaluate(&mut self, pc: Address, mode: Mode, number: Address) -> (Address, Address) {
        // let mut rp: Address;
        // let mut wp: Address;
        let rlim = self.read_limit;
        let wlim = self.write_limit;

        match mode {
            Mode::IMMEDIATE => (0, 0),
            Mode::DIRECT => self.direct(number),
            Mode::INDIRECT => self.indirect(pc, number),
            Mode::DECREMENT => (self.fold(number, rlim), self.fold(number, wlim)),
            Mode::INCREMENT => (self.fold(number, rlim), self.fold(number, wlim)),
        }
    }

    pub fn emi94(&mut self, pc: Address) {
        let ir: Instruction;
        let ira: Instruction;
        let irb: Instruction;
        let mut rpa: Address;
        let mut wpa: Address;
        let rpb: Address;
        let wpb: Address;
        let mut pip: Address = 0;
        let size = self.core.size();

        ir = self.core[pc];

        // Evaluate A-operand
        //
        if ir.a_mode == Mode::IMMEDIATE {
            // For instructions with an Immediate A-mode, the Pointer A
            // points to the source of the current instruction.
            rpa = 0;
            wpa = 0;
        } else {
            // For instructions with a Direct A-mode, the Pointer A
            // points to the instruction IR.ANumber away, relative to
            // the Program Counter.
            rpa = self.fold(ir.a_number, self.read_limit);
            wpa = self.fold(ir.a_number, self.write_limit);

            if ir.a_mode != Mode::DIRECT {
                if ir.a_mode == Mode::DECREMENT {
                    self.core[pc + wpa].b_number = (self.core[pc + wpa].b_number + size - 1) % size;
                }

                if ir.a_mode == Mode::INCREMENT {
                    pip = (pc + wpa) % size;
                }

                rpa = self.fold((rpa + self.core[pc + rpa].b_number), self.read_limit);
                wpa = self.fold((wpa + self.core[pc + wpa].b_number), self.write_limit);
            }
        }

        ira = self.core[pc + rpa];

        if ir.a_mode == Mode::INCREMENT {
            self.core[pip].b_number = (self.core[pip].b_number + 1) % size;
        }

    }
}

#[derive(Clone, Copy, Debug)]
pub enum InitialInstruction {
    Default,
    Random,
    Instruction(Instruction),
}

#[derive(Debug)]
pub struct CoreBuilder {
    core_size: u32,
    initial_instruction: InitialInstruction,
    task_limit: usize,
}

impl CoreBuilder {
    pub fn new() -> Self {
        CoreBuilder {
            core_size: 8192,
            initial_instruction: InitialInstruction::Default,
            task_limit: 64,
        }
    }

    pub fn coresize(&mut self, size: u32) -> &Self {
        self.core_size = size;
        self
    }

    pub fn initial_instruction(&mut self, insn: InitialInstruction) -> &Self {
        self.initial_instruction = insn;
        self
    }

    pub fn task_limit(&mut self, limit: usize) -> &Self {
        self.task_limit = limit;
        self
    }

    pub fn build(&self) -> Core {
        let mut instructions = Vec::<Instruction>::new();
        for _ in 0..self.core_size {
            instructions.push(match self.initial_instruction {
                InitialInstruction::Default => Instruction::default(),
                InitialInstruction::Random => Instruction::random(),
                InitialInstruction::Instruction(insn) => insn,
            })
        }

        Core {
            core: CoreMemory::new(self.core_size, self.initial_instruction),
            warrior: [TaskQueue::new(self.task_limit), TaskQueue::new(self.task_limit)],
            read_limit: 300,
            write_limit: 300,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn task_queue_simple() {
        let mut tq = TaskQueue::new(2);
        tq.queue(1);
        tq.queue(3);
        assert_eq!(tq.next(), Some(1));
        assert_eq!(tq.next(), Some(3));
        assert_eq!(tq.next(), None);
    }

    #[test]
    fn task_queue_limit() {
        let mut tq = TaskQueue::new(3);
        tq.queue(100);
        tq.queue(200);
        tq.queue(300);
        tq.queue(400);

        assert_eq!(tq.next(), Some(100));
        assert_eq!(tq.next(), Some(200));
        assert_eq!(tq.next(), Some(300));
        assert_eq!(tq.next(), None);
    }

    #[test]
    fn task_queue_empty() {
        let mut tq = TaskQueue::new(100);

        assert_eq!(tq.next(), None);
    }

    #[test]
    fn core_mem_size() {
        let core = CoreMemory::new(2, InitialInstruction::Default);
        assert_eq!(core.size(), 2);
    }

    #[test]
    fn core_mem_wrap() {
        let core = CoreMemory::new(2, InitialInstruction::Default);
        assert_eq!(core[0], core[2]);
    }
}
<|endoftext|>


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

use std::collections::HashMap;
use std::error;
use std::path::{Path, PathBuf};
use std::result;
use std::str::{self, FromStr};

use libarchive::writer;
use libarchive::reader::{self, Reader};
use libarchive::archive::{Entry, ReadFilter, ReadFormat, ExtractOption, ExtractOptions};
use regex::Regex;

use error::{Error, Result};
use crypto::{artifact, hash};
use package::{Identifiable, PackageIdent, MetaFile};

lazy_static! {
    static ref METAFILE_REGXS: HashMap<MetaFile, Regex> = {
        let mut map = HashMap::new();
        map.insert(MetaFile::CFlags, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::CFlags)).unwrap());
        map.insert(MetaFile::Config, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Config)).unwrap());
        map.insert(MetaFile::Deps, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Deps)).unwrap());
        map.insert(MetaFile::TDeps, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::TDeps)).unwrap());
        map.insert(MetaFile::Exposes, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Exposes)).unwrap());
        map.insert(MetaFile::Ident, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Ident)).unwrap());
        map.insert(MetaFile::LdRunPath, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::LdRunPath)).unwrap());
        map.insert(MetaFile::LdFlags, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::LdFlags)).unwrap());
        map.insert(MetaFile::Manifest, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Manifest)).unwrap());
        map.insert(MetaFile::Path, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Path)).unwrap());
        map
    };
}

type Metadata = HashMap<MetaFile, String>;

#[derive(Debug)]
pub struct PackageArchive {
    pub path: PathBuf,
    metadata: Option<Metadata>,
}

impl PackageArchive {
    pub fn new<P: Into<PathBuf>>(path: P) -> Self {
        PackageArchive {
            path: path.into(),
            metadata: None,
        }
    }

    /// Calculate and return the checksum of the package archive in base64 format.
    ///
    /// # Failures
    ///
    /// * If the archive cannot be read
    pub fn checksum(&self) -> Result<String> {
        hash::hash_file(&self.path)
    }

    pub fn cflags(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::CFlags) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn config(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::Config) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    /// Returns a list of package identifiers representing the runtime package dependencies for
    /// this archive.
    ///
    /// # Failures
    ///
    /// * If a `DEPS` metafile is not found in the archive
    /// * If the archive cannot be read
    /// * If the archive cannot be verified
    pub fn deps(&mut self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::Deps)
    }

    /// Returns a list of package identifiers representing the transitive runtime package
    /// dependencies for this archive.
    ///
    /// # Failures
    ///
    /// * If a `TDEPS` metafile is not found in the archive
    /// * If the archive cannot be read
    /// * If the archive cannot be verified
    pub fn tdeps(&mut self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::TDeps)
    }

    pub fn exposes(&mut self) -> Result<Vec<u16>> {
        match self.read_metadata(MetaFile::Exposes) {
            Ok(Some(data)) => {
                let ports: Vec<u16> = data.split(" ")
                    .filter_map(|port| port.parse::<u16>().ok())
                    .collect();
                Ok(ports)
            }
            Ok(None) => Ok(vec![]),
            Err(e) => Err(e),
        }
    }

    pub fn ident(&mut self) -> Result<PackageIdent> {
        match self.read_metadata(MetaFile::Ident) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Ident)),
            Ok(Some(data)) => PackageIdent::from_str(&data),
            Err(e) => Err(e),
        }
    }

    pub fn ld_run_path(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::LdRunPath) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn ldflags(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::LdFlags) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn manifest(&mut self) -> Result<String> {
        match self.read_metadata(MetaFile::Manifest) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Manifest)),
            Ok(Some(data)) => Ok(data.clone()),
            Err(e) => Err(e),
        }
    }

    pub fn path(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::Path) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    /// A plain string representation of the archive's file name.
    pub fn file_name(&self) -> String {
        self.path.file_name().unwrap().to_string_lossy().into_owned()
    }

    /// Given a package name and a path to a file as an `&str`, verify
    /// the files signature.
    ///
    /// # Failures
    ///
    /// * Fails if it cannot verify the signature for any reason
    pub fn verify<P: AsRef<Path>>(&self, cache_key_path: &P) -> Result<(String, String)> {
        artifact::verify(&self.path, cache_key_path)
    }

    /// Given a package name and a path to a file as an `&str`, unpack
    /// the package.
    ///
    /// # Failures
    ///
    /// * If the package cannot be unpacked
    pub fn unpack(&self, fs_root_path: Option<&Path>) -> Result<()> {
        let root = fs_root_path.unwrap_or(Path::new("/"));
        let tar_reader = try!(artifact::get_archive_reader(&self.path));
        let mut builder = reader::Builder::new();
        try!(builder.support_format(ReadFormat::Gnutar));
        try!(builder.support_filter(ReadFilter::Xz));
        let mut reader = try!(builder.open_stream(tar_reader));
        let writer = writer::Disk::new();
        let mut extract_options = ExtractOptions::new();
        extract_options.add(ExtractOption::Time);
        try!(writer.set_options(&extract_options));
        try!(writer.set_standard_lookup());
        try!(writer.write(&mut reader, Some(root.to_string_lossy().as_ref())));
        try!(writer.close());
        Ok(())
    }

    fn read_deps(&mut self, file: MetaFile) -> Result<Vec<PackageIdent>> {
        let mut deps: Vec<PackageIdent> = vec![];
        match self.read_metadata(file) {
            Ok(Some(body)) => {
                debug!("body = [{}]", &body);
                let ids: Vec<String> = body.split("\n").map(|d| d.to_string()).collect();
                for id in &ids {
                    debug!("id = [{}]", &id);
                    let package = try!(PackageIdent::from_str(id));
                    if !package.fully_qualified() {
                        // JW TODO: use a more appropriate erorr to describe the invalid
                        // user input here. (user because a package was generated by a user
                        // and read into program)
                        return Err(Error::InvalidPackageIdent(package.to_string()));
                    }
                    deps.push(package);
                }
                Ok(deps)
            }
            Ok(None) => Ok(vec![]),
            Err(Error::MetaFileNotFound(_)) => Ok(deps),
            Err(e) => Err(e),
        }
    }

    fn read_metadata(&mut self, file: MetaFile) -> Result<Option<&String>> {
        if let Some(ref files) = self.metadata {
            return Ok(files.get(&file));
        }
        let mut metadata = Metadata::new();
        let mut matched_count = 0u8;
        let tar_reader = try!(artifact::get_archive_reader(&self.path));
        let mut builder = reader::Builder::new();
        try!(builder.support_format(ReadFormat::Gnutar));
        try!(builder.support_filter(ReadFilter::Xz));
        let mut reader = try!(builder.open_stream(tar_reader));
        loop {
            let mut matched_type: Option<MetaFile> = None;
            if let Some(entry) = reader.next_header() {
                for (matched, regx) in METAFILE_REGXS.iter() {
                    if regx.is_match(entry.pathname()) {
                        matched_type = Some((*matched).clone());
                        matched_count += 1;
                        break;
                    }
                }
            } else {
                break;
            }

            if matched_type.is_none() {
                continue;
            }

            let mut buf = String::new();
            loop {
                match reader.read_block() {
                    Ok(Some(bytes)) => {
                        match str::from_utf8(bytes) {
                            Ok(content) => {
                                buf.push_str(content.trim());
                            }
                            Err(_) => return Err(Error::MetaFileMalformed(matched_type.unwrap())),
                        }
                    }
                    Ok(None) => {
                        debug!("content = {}", &buf);
                        metadata.insert(matched_type.unwrap(), buf);
                        break;
                    }
                    Err(_) => return Err(Error::MetaFileMalformed(matched_type.unwrap())),
                }
            }//inner loop

            if matched_count == METAFILE_REGXS.len() as u8 {
                break;
            }
        }
        self.metadata = Some(metadata);
        Ok(self.metadata.as_ref().unwrap().get(&file))
    }
}

pub trait FromArchive: Sized {
    type Error: error::Error;

    fn from_archive(archive: &mut PackageArchive) -> result::Result<Self, Self::Error>;
}

#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use super::*;

    #[test]
    fn reading_artifact_metadata() {
        let mut hart = PackageArchive::new(fixtures()
            .join("happyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let ident = hart.ident().unwrap();
        assert_eq!(ident.origin, "happyhumans");
        assert_eq!(ident.name, "possums");
        assert_eq!(ident.version, Some("8.1.4".to_string()));
        assert_eq!(ident.release, Some("20160427165340".to_string()));
    }

    pub fn root() -> PathBuf {
        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests")
    }

    pub fn fixtures() -> PathBuf {
        root().join("fixtures")
    }

    #[test]
    fn reading_artifact_deps() {
        let mut hart = PackageArchive::new(fixtures()
            .join("happyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let _ = hart.deps().unwrap();
        let _ = hart.tdeps().unwrap();
    }

    #[test]
    fn reading_artifact_large_tdeps() {
        let mut hart = PackageArchive::new(fixtures()
            .join("unhappyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let tdeps = hart.tdeps().unwrap();
        assert_eq!(1024, tdeps.len());
    }

}
<commit_msg>[core] Use 'Owner' and 'Permissions' during unpack<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::error;
use std::path::{Path, PathBuf};
use std::result;
use std::str::{self, FromStr};

use libarchive::writer;
use libarchive::reader::{self, Reader};
use libarchive::archive::{Entry, ReadFilter, ReadFormat, ExtractOption, ExtractOptions};
use regex::Regex;

use error::{Error, Result};
use crypto::{artifact, hash};
use package::{Identifiable, PackageIdent, MetaFile};

lazy_static! {
    static ref METAFILE_REGXS: HashMap<MetaFile, Regex> = {
        let mut map = HashMap::new();
        map.insert(MetaFile::CFlags, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::CFlags)).unwrap());
        map.insert(MetaFile::Config, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Config)).unwrap());
        map.insert(MetaFile::Deps, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Deps)).unwrap());
        map.insert(MetaFile::TDeps, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::TDeps)).unwrap());
        map.insert(MetaFile::Exposes, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Exposes)).unwrap());
        map.insert(MetaFile::Ident, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Ident)).unwrap());
        map.insert(MetaFile::LdRunPath, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::LdRunPath)).unwrap());
        map.insert(MetaFile::LdFlags, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::LdFlags)).unwrap());
        map.insert(MetaFile::Manifest, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Manifest)).unwrap());
        map.insert(MetaFile::Path, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Path)).unwrap());
        map
    };
}

type Metadata = HashMap<MetaFile, String>;

#[derive(Debug)]
pub struct PackageArchive {
    pub path: PathBuf,
    metadata: Option<Metadata>,
}

impl PackageArchive {
    pub fn new<P: Into<PathBuf>>(path: P) -> Self {
        PackageArchive {
            path: path.into(),
            metadata: None,
        }
    }

    /// Calculate and return the checksum of the package archive in base64 format.
    ///
    /// # Failures
    ///
    /// * If the archive cannot be read
    pub fn checksum(&self) -> Result<String> {
        hash::hash_file(&self.path)
    }

    pub fn cflags(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::CFlags) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn config(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::Config) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    /// Returns a list of package identifiers representing the runtime package dependencies for
    /// this archive.
    ///
    /// # Failures
    ///
    /// * If a `DEPS` metafile is not found in the archive
    /// * If the archive cannot be read
    /// * If the archive cannot be verified
    pub fn deps(&mut self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::Deps)
    }

    /// Returns a list of package identifiers representing the transitive runtime package
    /// dependencies for this archive.
    ///
    /// # Failures
    ///
    /// * If a `TDEPS` metafile is not found in the archive
    /// * If the archive cannot be read
    /// * If the archive cannot be verified
    pub fn tdeps(&mut self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::TDeps)
    }

    pub fn exposes(&mut self) -> Result<Vec<u16>> {
        match self.read_metadata(MetaFile::Exposes) {
            Ok(Some(data)) => {
                let ports: Vec<u16> = data.split(" ")
                    .filter_map(|port| port.parse::<u16>().ok())
                    .collect();
                Ok(ports)
            }
            Ok(None) => Ok(vec![]),
            Err(e) => Err(e),
        }
    }

    pub fn ident(&mut self) -> Result<PackageIdent> {
        match self.read_metadata(MetaFile::Ident) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Ident)),
            Ok(Some(data)) => PackageIdent::from_str(&data),
            Err(e) => Err(e),
        }
    }

    pub fn ld_run_path(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::LdRunPath) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn ldflags(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::LdFlags) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn manifest(&mut self) -> Result<String> {
        match self.read_metadata(MetaFile::Manifest) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Manifest)),
            Ok(Some(data)) => Ok(data.clone()),
            Err(e) => Err(e),
        }
    }

    pub fn path(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::Path) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    /// A plain string representation of the archive's file name.
    pub fn file_name(&self) -> String {
        self.path.file_name().unwrap().to_string_lossy().into_owned()
    }

    /// Given a package name and a path to a file as an `&str`, verify
    /// the files signature.
    ///
    /// # Failures
    ///
    /// * Fails if it cannot verify the signature for any reason
    pub fn verify<P: AsRef<Path>>(&self, cache_key_path: &P) -> Result<(String, String)> {
        artifact::verify(&self.path, cache_key_path)
    }

    /// Given a package name and a path to a file as an `&str`, unpack
    /// the package.
    ///
    /// # Failures
    ///
    /// * If the package cannot be unpacked
    pub fn unpack(&self, fs_root_path: Option<&Path>) -> Result<()> {
        let root = fs_root_path.unwrap_or(Path::new("/"));
        let tar_reader = try!(artifact::get_archive_reader(&self.path));
        let mut builder = reader::Builder::new();
        try!(builder.support_format(ReadFormat::Gnutar));
        try!(builder.support_filter(ReadFilter::Xz));
        let mut reader = try!(builder.open_stream(tar_reader));
        let writer = writer::Disk::new();
        let mut extract_options = ExtractOptions::new();
        extract_options.add(ExtractOption::Time);
        extract_options.add(ExtractOption::Owner);
        extract_options.add(ExtractOption::Permissions);
        try!(writer.set_options(&extract_options));
        try!(writer.set_standard_lookup());
        try!(writer.write(&mut reader, Some(root.to_string_lossy().as_ref())));
        try!(writer.close());
        Ok(())
    }

    fn read_deps(&mut self, file: MetaFile) -> Result<Vec<PackageIdent>> {
        let mut deps: Vec<PackageIdent> = vec![];
        match self.read_metadata(file) {
            Ok(Some(body)) => {
                debug!("body = [{}]", &body);
                let ids: Vec<String> = body.split("\n").map(|d| d.to_string()).collect();
                for id in &ids {
                    debug!("id = [{}]", &id);
                    let package = try!(PackageIdent::from_str(id));
                    if !package.fully_qualified() {
                        // JW TODO: use a more appropriate erorr to describe the invalid
                        // user input here. (user because a package was generated by a user
                        // and read into program)
                        return Err(Error::InvalidPackageIdent(package.to_string()));
                    }
                    deps.push(package);
                }
                Ok(deps)
            }
            Ok(None) => Ok(vec![]),
            Err(Error::MetaFileNotFound(_)) => Ok(deps),
            Err(e) => Err(e),
        }
    }

    fn read_metadata(&mut self, file: MetaFile) -> Result<Option<&String>> {
        if let Some(ref files) = self.metadata {
            return Ok(files.get(&file));
        }
        let mut metadata = Metadata::new();
        let mut matched_count = 0u8;
        let tar_reader = try!(artifact::get_archive_reader(&self.path));
        let mut builder = reader::Builder::new();
        try!(builder.support_format(ReadFormat::Gnutar));
        try!(builder.support_filter(ReadFilter::Xz));
        let mut reader = try!(builder.open_stream(tar_reader));
        loop {
            let mut matched_type: Option<MetaFile> = None;
            if let Some(entry) = reader.next_header() {
                for (matched, regx) in METAFILE_REGXS.iter() {
                    if regx.is_match(entry.pathname()) {
                        matched_type = Some((*matched).clone());
                        matched_count += 1;
                        break;
                    }
                }
            } else {
                break;
            }

            if matched_type.is_none() {
                continue;
            }

            let mut buf = String::new();
            loop {
                match reader.read_block() {
                    Ok(Some(bytes)) => {
                        match str::from_utf8(bytes) {
                            Ok(content) => {
                                buf.push_str(content.trim());
                            }
                            Err(_) => return Err(Error::MetaFileMalformed(matched_type.unwrap())),
                        }
                    }
                    Ok(None) => {
                        debug!("content = {}", &buf);
                        metadata.insert(matched_type.unwrap(), buf);
                        break;
                    }
                    Err(_) => return Err(Error::MetaFileMalformed(matched_type.unwrap())),
                }
            }//inner loop

            if matched_count == METAFILE_REGXS.len() as u8 {
                break;
            }
        }
        self.metadata = Some(metadata);
        Ok(self.metadata.as_ref().unwrap().get(&file))
    }
}

pub trait FromArchive: Sized {
    type Error: error::Error;

    fn from_archive(archive: &mut PackageArchive) -> result::Result<Self, Self::Error>;
}

#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use super::*;

    #[test]
    fn reading_artifact_metadata() {
        let mut hart = PackageArchive::new(fixtures()
            .join("happyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let ident = hart.ident().unwrap();
        assert_eq!(ident.origin, "happyhumans");
        assert_eq!(ident.name, "possums");
        assert_eq!(ident.version, Some("8.1.4".to_string()));
        assert_eq!(ident.release, Some("20160427165340".to_string()));
    }

    pub fn root() -> PathBuf {
        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests")
    }

    pub fn fixtures() -> PathBuf {
        root().join("fixtures")
    }

    #[test]
    fn reading_artifact_deps() {
        let mut hart = PackageArchive::new(fixtures()
            .join("happyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let _ = hart.deps().unwrap();
        let _ = hart.tdeps().unwrap();
    }

    #[test]
    fn reading_artifact_large_tdeps() {
        let mut hart = PackageArchive::new(fixtures()
            .join("unhappyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let tdeps = hart.tdeps().unwrap();
        assert_eq!(1024, tdeps.len());
    }

}
<|endoftext|>


<commit_before>// STL file handling.
//#![allow(unstable)]
#![allow(dead_code)]
#![deny(unused_imports)]

// This guy depends on multiple sibling sub-modules, so he can use that here.
use std::old_io::{IoResult,Reader};
use std::fmt;
use mesh::Mesh;
use mesh::Facet;
use vector::Vector3D;
use vector::VertexMap;

pub struct StlHeader {
    header: [u8; 80],
}

#[derive(PartialEq, Eq, Hash, Copy)]
pub struct StlFacet {
    pub n : Vector3D,
    pub v1: Vector3D,
    pub v2: Vector3D,
    pub v3: Vector3D,
    pub abc: u16,
}

impl fmt::Debug for StlFacet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{:?}]({:?}-{:?}-{:?})[{:X}]",
            &self.n, &self.v1, &self.v2, &self.v3, self.abc)
    }
}

impl StlFacet {
    pub fn read(r: &mut Reader) -> IoResult<StlFacet> {
        let n = try!(Vector3D::read(r));
        let v1 = try!(Vector3D::read(r));
        let v2 = try!(Vector3D::read(r));
        let v3 = try!(Vector3D::read(r));
        let abc = try!(r.read_le_u16());
        return Ok(StlFacet { n:n, v1:v1, v2:v2, v3:v3, abc:abc });
    }

    pub fn calculate_normal_vector(&self) -> Vector3D {
        // Dir = (B - A) x (C - A)
        // Norm = Dir / len(Dir)
        let direction = Vector3D::cross( self.v2.minus(self.v1), self.v3.minus(self.v1) );

        // Normalize is optional in our use case
        direction.normalize()
    }
}

pub struct StlFile {
    pub header: [u8; 80],
    pub facets: Vec<StlFacet>,
    pub vertices: VertexMap,
}

impl StlFile {

    pub fn read<R: Reader>(r: &mut R) -> IoResult<StlFile> {
        let mut file = StlFile {
            header: [0u8; 80],
            facets: Vec::new(),
            vertices: VertexMap::new()
        };
        try!(r.read_at_least(file.header.len(), &mut file.header));
        // TODO: select which form to read: binary or ascii
        try!(file.read_binary(r));
        Ok(file)
    }

    /*
    fn read_ascii(r: &mut Reader) -> IoResult<Mesh> {
        //solid vcg
        //  facet normal 7.733874e-001 -3.151335e-002 6.331499e-001
        //    outer loop
        //      vertex  2.137833e+001 5.385936e+001 1.350253e+001
        //      vertex  2.341920e+001 4.700068e+001 1.066826e+001
        //      vertex  2.859041e+001 5.985682e+001 4.991545e+000
        //    endloop
        //  endfacet
        //endsolid vcg
        for line in r.lines() {
            print!("{}", line.unwrap());
        }
        Mesh::new() // TODO
    }
    */

    fn read_binary(&mut self, r: &mut Reader) -> IoResult<&StlFile> {
        let facet_count = try!(r.read_le_u32());
        for _ in range(0, facet_count) {
            let f = try!(StlFacet::read(r));
            self.vertices.add(f.v1);
            self.vertices.add(f.v2);
            self.vertices.add(f.v3);
            self.facets.push(f);
        }
        Ok(self)
    }

    pub fn kind(&self) -> String {
        let hs = String::from_utf8_lossy(&self.header);
        if hs.starts_with("solid ") {
            "ASCII".to_string()
        } else {
            "binary".to_string()
        }
    }

    pub fn as_mesh(&self) -> Mesh {
        new_mesh(&self.facets, &self.vertices)
    }

    pub fn println_debug(&self) {
        println!("Is {} STL", self.kind());
        println!("Facets: {}", self.facets.len());
        for f in self.facets.iter() {
            let v1i = self.vertices.get(&f.v1);
            let v2i = self.vertices.get(&f.v2);
            let v3i = self.vertices.get(&f.v3);
            println!("  Facet: {:?} => {}-{}-{}", f, v1i, v2i, v3i);
        }
        println!("Vertices: {}", self.vertices.len());
    }
}

fn new_mesh(fv: &Vec<StlFacet>, vm: &VertexMap) -> Mesh {
    Mesh::new_from_parts(vm.vector(), indexed_vertices(fv, vm))
}

fn indexed_vertices(fv: &Vec<StlFacet>, vm: &VertexMap) -> Vec<Facet> {
    let mut v: Vec<Facet> = Vec::with_capacity(fv.len());
    for f in fv.iter() {
        let v1 = vm.get(&f.v1);
        let v2 = vm.get(&f.v2);
        let v3 = vm.get(&f.v3);
        // I wish there was a better place to put this
        let n = f.calculate_normal_vector();
        v.push(Facet{
            v1: v1,
            v2: v2,
            v3: v3,
            n: n,
        })
    }
    v
}
<commit_msg>Trimming VertexMap from StlFile state<commit_after>// STL file handling.
//#![allow(unstable)]
#![allow(dead_code)]
#![deny(unused_imports)]

// This guy depends on multiple sibling sub-modules, so he can use that here.
use std::old_io::{IoResult,Reader};
use std::fmt;
use mesh::Mesh;
use mesh::Facet;
use vector::Vector3D;
use vector::VertexMap;

pub struct StlHeader {
    header: [u8; 80],
}

#[derive(PartialEq, Eq, Hash, Copy)]
pub struct StlFacet {
    pub n : Vector3D,
    pub v1: Vector3D,
    pub v2: Vector3D,
    pub v3: Vector3D,
    pub abc: u16,
}

impl fmt::Debug for StlFacet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{:?}] ({:?}-{:?}-{:?}) [{:X}]",
            &self.n, &self.v1, &self.v2, &self.v3, self.abc)
    }
}

impl StlFacet {
    pub fn read(r: &mut Reader) -> IoResult<StlFacet> {
        let n = try!(Vector3D::read(r));
        let v1 = try!(Vector3D::read(r));
        let v2 = try!(Vector3D::read(r));
        let v3 = try!(Vector3D::read(r));
        let abc = try!(r.read_le_u16());
        return Ok(StlFacet { n:n, v1:v1, v2:v2, v3:v3, abc:abc });
    }

    pub fn calculate_normal_vector(&self) -> Vector3D {
        // Dir = (B - A) x (C - A)
        // Norm = Dir / len(Dir)
        let direction = Vector3D::cross( self.v2.minus(self.v1), self.v3.minus(self.v1) );

        // Normalize is optional in our use case
        direction.normalize()
    }
}

pub struct StlFile {
    pub header: [u8; 80],
    pub facets: Vec<StlFacet>,
}

impl StlFile {

    pub fn read<R: Reader>(r: &mut R) -> IoResult<StlFile> {
        let mut file = StlFile {
            header: [0u8; 80],
            facets: Vec::new(),
        };
        try!(r.read_at_least(file.header.len(), &mut file.header));
        // TODO: select which form to read: binary or ascii
        try!(file.read_binary(r));
        Ok(file)
    }

    /*
    fn read_ascii(r: &mut Reader) -> IoResult<Mesh> {
        //solid vcg
        //  facet normal 7.733874e-001 -3.151335e-002 6.331499e-001
        //    outer loop
        //      vertex  2.137833e+001 5.385936e+001 1.350253e+001
        //      vertex  2.341920e+001 4.700068e+001 1.066826e+001
        //      vertex  2.859041e+001 5.985682e+001 4.991545e+000
        //    endloop
        //  endfacet
        //endsolid vcg
        for line in r.lines() {
            print!("{}", line.unwrap());
        }
        Mesh::new() // TODO
    }
    */

    fn read_binary(&mut self, r: &mut Reader) -> IoResult<&StlFile> {
        let facet_count = try!(r.read_le_u32());
        for _ in range(0, facet_count) {
            let f = try!(StlFacet::read(r));
            self.facets.push(f);
        }
        Ok(self)
    }

    pub fn kind(&self) -> String {
        let hs = String::from_utf8_lossy(&self.header);
        if hs.starts_with("solid ") {
            "ASCII".to_string()
        } else {
            "binary".to_string()
        }
    }

    pub fn as_mesh(&self) -> Mesh {
        let mut vmap = VertexMap::new();
        for f in self.facets.iter() {
            vmap.add(f.v1);
            vmap.add(f.v2);
            vmap.add(f.v3);
        }
        Mesh::new_from_parts(vmap.vector(), indexed_vertices(&self.facets, &vmap))
    }

    pub fn println_debug(&self) {
        println!("Is {} STL", self.kind());
        println!("Facets: {}", self.facets.len());
        for f in self.facets.iter() {
            println!("  Facet: {:?}", f);
        }
    }
}

fn indexed_vertices(fv: &Vec<StlFacet>, vm: &VertexMap) -> Vec<Facet> {
    let mut v: Vec<Facet> = Vec::with_capacity(fv.len());
    for f in fv.iter() {
        let v1 = vm.get(&f.v1);
        let v2 = vm.get(&f.v2);
        let v3 = vm.get(&f.v3);
        // I wish there was a better place to put this
        let n = f.calculate_normal_vector();
        v.push(Facet{
            v1: v1,
            v2: v2,
            v3: v3,
            n: n,
        })
    }
    v
}
<|endoftext|>


<commit_before>use serde;
use serde_json;
use openssl::ssl;
use mio::channel;
use std::io;
use std::net::SocketAddr;
use std::default::Default;
use std::convert::From;
use std::sync::mpsc;

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct HttpFront {
    pub app_id: String,
    pub hostname: String,
    pub path_begin: String,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct TlsFront {
    pub app_id: String,
    pub hostname: String,
    pub path_begin: String,
    pub certificate: String,
    pub certificate_chain: Vec<String>,
    pub key:         String,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct TcpFront {
    pub app_id: String,
    pub ip_address: String,
    pub port: u16
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct Instance {
    pub app_id: String,
    pub ip_address: String,
    pub port: u16
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct HttpProxyConfiguration {
    pub front:           SocketAddr,
    pub front_timeout:   u64,
    pub back_timeout:    u64,
    pub max_connections: usize,
    pub buffer_size:     usize,
    pub public_address:  Option<String>,
    pub answer_404:      String,
    pub answer_503:      String,
}

impl Default for HttpProxyConfiguration {
  fn default() -> HttpProxyConfiguration {
    HttpProxyConfiguration {
      front:           "127.0.0.1:8080".parse().unwrap(),
      front_timeout:   5000,
      back_timeout:    5000,
      max_connections: 1000,
      buffer_size:     12000,
      public_address:  None,
      answer_404:      String::from("HTTP/1.1 404 Not Found\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n"),
      answer_503:      String::from("HTTP/1.1 503 your application is in deployment\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n"),
    }
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct TlsProxyConfiguration {
    pub front:           SocketAddr,
    pub front_timeout:   u64,
    pub back_timeout:    u64,
    pub max_connections: usize,
    pub buffer_size:     usize,
    pub public_address:  Option<String>,
    pub answer_404:      String,
    pub answer_503:      String,
    pub options:         i64,
    pub cipher_list:     String,
}

impl Default for TlsProxyConfiguration {
  fn default() -> TlsProxyConfiguration {
    TlsProxyConfiguration {
      front:           "127.0.0.1:8443".parse().unwrap(),
      front_timeout:   5000,
      back_timeout:    5000,
      max_connections: 1000,
      buffer_size:     12000,
      public_address:  None,
      answer_404:      String::from("HTTP/1.1 404 Not Found\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n"),
      answer_503:      String::from("HTTP/1.1 503 your application is in deployment\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n"),
      cipher_list:     String::from("ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305"),
      options:         (ssl::SSL_OP_CIPHER_SERVER_PREFERENCE | ssl::SSL_OP_NO_COMPRESSION |
                         ssl::SSL_OP_NO_TICKET | ssl::SSL_OP_NO_SSLV2 |
                         ssl::SSL_OP_NO_SSLV3 | ssl::SSL_OP_NO_TLSV1).bits(),
    }
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize)]
pub enum Command {
    AddHttpFront(HttpFront),
    RemoveHttpFront(HttpFront),

    AddTlsFront(TlsFront),
    RemoveTlsFront(TlsFront),

    AddTcpFront(TcpFront),
    RemoveTcpFront(TcpFront),

    AddInstance(Instance),
    RemoveInstance(Instance),

    HttpProxy(HttpProxyConfiguration),
    TlsProxy(TlsProxyConfiguration),
}

impl Command {
  pub fn get_topics(&self) -> Vec<Topic> {
    match *self {
      Command::AddHttpFront(_)    => vec![Topic::HttpProxyConfig                       ],
      Command::RemoveHttpFront(_) => vec![Topic::HttpProxyConfig                       ],
      Command::AddTlsFront(_)     => vec![Topic::TlsProxyConfig                        ],
      Command::RemoveTlsFront(_)  => vec![Topic::TlsProxyConfig                        ],
      Command::AddTcpFront(_)     => vec![Topic::TcpProxyConfig                        ],
      Command::RemoveTcpFront(_)  => vec![Topic::TcpProxyConfig                        ],
      Command::AddInstance(_)     => vec![Topic::HttpProxyConfig, Topic::TlsProxyConfig, Topic::TcpProxyConfig],
      Command::RemoveInstance(_)  => vec![Topic::HttpProxyConfig, Topic::TlsProxyConfig, Topic::TcpProxyConfig],
      Command::HttpProxy(_)       => vec![Topic::HttpProxyConfig],
      Command::TlsProxy(_)        => vec![Topic::TlsProxyConfig],
    }
  }
}

enum CommandField {
  Type,
  Data,
}

impl serde::Deserialize for CommandField {
  fn deserialize<D>(deserializer: &mut D) -> Result<CommandField, D::Error>
        where D: serde::de::Deserializer {
    struct CommandFieldVisitor;
    impl serde::de::Visitor for CommandFieldVisitor {
      type Value = CommandField;

      fn visit_str<E>(&mut self, value: &str) -> Result<CommandField, E>
        where E: serde::de::Error {
        match value {
          "type" => Ok(CommandField::Type),
          "data" => Ok(CommandField::Data),
          _ => Err(serde::de::Error::custom("expected type or data")),
        }
      }
    }

    deserializer.deserialize(CommandFieldVisitor)
  }
}

struct CommandVisitor;
impl serde::de::Visitor for CommandVisitor {
  type Value = Command;

  fn visit_map<V>(&mut self, mut visitor: V) -> Result<Command, V::Error>
        where V: serde::de::MapVisitor {
    let mut command_type:Option<String>    = None;
    let mut data:Option<serde_json::Value> = None;

    loop {
      match try!(visitor.visit_key()) {
        Some(CommandField::Type) => { command_type = Some(try!(visitor.visit_value())); }
        Some(CommandField::Data) => { data = Some(try!(visitor.visit_value())); }
        None => { break; }
      }
    }

    //println!("decoded type = {:?}, value= {:?}", command_type, data);
    let command_type = match command_type {
      Some(command) => command,
      None => try!(visitor.missing_field("type")),
    };
    let data = match data {
      Some(data) => data,
      None => try!(visitor.missing_field("data")),
    };

    try!(visitor.end());

    if &command_type == "ADD_HTTP_FRONT" {
      let res = serde_json::from_value(data).or(Err(serde::de::Error::custom("add_http_front")));
      //println!("ADD_HTTP_FRONT => {:?}", res);
      let acl = try!(res);
      Ok(Command::AddHttpFront(acl))
    } else if &command_type == "REMOVE_HTTP_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("remove_http_front"))));
      Ok(Command::RemoveHttpFront(acl))
    } else if &command_type == "ADD_TLS_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("add_tls_front"))));
      Ok(Command::AddTlsFront(acl))
    } else if &command_type == "REMOVE_TLS_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("remove_tls_front"))));
      Ok(Command::RemoveTlsFront(acl))
    } else if &command_type == "ADD_TCP_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("add_tcp_front"))));
      Ok(Command::AddTcpFront(acl))
    } else if &command_type == "REMOVE_TCP_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("remove_tcp_front"))));
      Ok(Command::RemoveTcpFront(acl))
    } else if &command_type == "ADD_INSTANCE" {
      let instance = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("add_instance"))));
      Ok(Command::AddInstance(instance))
    } else if &command_type == "REMOVE_INSTANCE" {
      let instance = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("remove_instance"))));
      Ok(Command::RemoveInstance(instance))
    } else if &command_type == "CONFIGURE_HTTP_PROXY" {
      let conf = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("configure_http_proxy"))));
      Ok(Command::HttpProxy(conf))
    } else {
      Err(serde::de::Error::custom("unrecognized command"))
    }
  }
}

impl serde::Deserialize for Command {
  fn deserialize<D>(deserializer: &mut D) -> Result<Command, D::Error>
        where D: serde::de::Deserializer {
    static FIELDS: &'static [&'static str] = &["type", "data"];
    deserializer.deserialize_struct("Command", FIELDS, CommandVisitor)
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash)]
pub enum Topic {
    HttpProxyConfig,
    TlsProxyConfig,
    TcpProxyConfig
}

pub trait Sender<T> {
  fn send_message(&self, t:T) -> Result<(), io::Error>;
}

pub trait Receiver<T> {
  fn recv_message(&self) -> Result<T, io::Error>;
}

impl<T> Sender<T> for mpsc::Sender<T> {
  fn send_message(&self, t:T) -> Result<(), io::Error> {
    match self.send(t) {
      Ok(()) => Ok(()),
      Err(mpsc::SendError(_)) => Err(io::Error::new(io::ErrorKind::BrokenPipe, "receiver disconnected"))
    }
  }
}

impl<T> Sender<T> for channel::Sender<T> {
  fn send_message(&self, t:T) -> Result<(), io::Error> {
    match self.send(t) {
      Ok(()) => Ok(()),
      Err(channel::SendError::Io(e)) => Err(e),
      Err(channel::SendError::Disconnected(_)) => Err(io::Error::new(io::ErrorKind::BrokenPipe, "receiver disconnected"))
    }
  }
}

impl<T> Receiver<T> for channel::Receiver<T> {
  fn recv_message(&self) -> Result<T, io::Error> {
    match self.try_recv() {
      Ok(t) => Ok(t),
      Err(mpsc::TryRecvError::Empty) => Err(io::Error::new(io::ErrorKind::WouldBlock, "no data")),
      Err(mpsc::TryRecvError::Disconnected) => Err(io::Error::new(io::ErrorKind::BrokenPipe, "receiver disconnected"))
    }
  }
}

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

  #[test]
  fn add_acl_test() {
    let raw_json = r#"{"type": "ADD_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "port": 4242}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::AddHttpFront(HttpFront{
      app_id: String::from("xxx"),
      hostname: String::from("yyy"),
      path_begin: String::from("xxx"),
    }));
  }

  #[test]
  fn remove_acl_test() {
    let raw_json = r#"{"type": "REMOVE_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "port": 4242}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::RemoveHttpFront(HttpFront{
      app_id: String::from("xxx"),
      hostname: String::from("yyy"),
      path_begin: String::from("xxx"),
    }));
  }

  #[test]
  fn add_instance_test() {
    let raw_json = r#"{"type": "ADD_INSTANCE", "data": {"app_id": "xxx", "ip_address": "yyy", "port": 8080}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::AddInstance(Instance{
      app_id: String::from("xxx"),
      ip_address: String::from("yyy"),
      port: 8080
    }));
  }

  #[test]
  fn remove_instance_test() {
    let raw_json = r#"{"type": "REMOVE_INSTANCE", "data": {"app_id": "xxx", "ip_address": "yyy", "port": 8080}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::RemoveInstance(Instance{
      app_id: String::from("xxx"),
      ip_address: String::from("yyy"),
      port: 8080
    }));
  }

  #[test]
  fn http_front_crash_test() {
    let raw_json = r#"{"type": "ADD_HTTP_FRONT", "data": {"app_id": "aa", "hostname": "cltdl.fr", "path_begin": ""}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::AddHttpFront(HttpFront{
      app_id: String::from("aa"),
      hostname: String::from("cltdl.fr"),
      path_begin: String::from(""),
    }));
  }

  #[test]
  fn http_front_crash_test2() {
    let raw_json = r#"{"app_id": "aa", "hostname": "cltdl.fr", "path_begin": ""}"#;
    let front: HttpFront = serde_json::from_str(raw_json).unwrap();
    println!("{:?}",front);
    assert!(front == HttpFront{
      app_id: String::from("aa"),
      hostname: String::from("cltdl.fr"),
      path_begin: String::from(""),
    });
  }
}

<commit_msg>cosmetics<commit_after>use serde;
use serde_json;
use openssl::ssl;
use mio::channel;
use std::io;
use std::net::SocketAddr;
use std::default::Default;
use std::convert::From;
use std::sync::mpsc;

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct HttpFront {
    pub app_id:     String,
    pub hostname:   String,
    pub path_begin: String,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct TlsFront {
    pub app_id:            String,
    pub hostname:          String,
    pub path_begin:        String,
    pub certificate:       String,
    pub certificate_chain: Vec<String>,
    pub key:               String,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct TcpFront {
    pub app_id:     String,
    pub ip_address: String,
    pub port:       u16
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct Instance {
    pub app_id:     String,
    pub ip_address: String,
    pub port:       u16
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct HttpProxyConfiguration {
    pub front:           SocketAddr,
    pub front_timeout:   u64,
    pub back_timeout:    u64,
    pub max_connections: usize,
    pub buffer_size:     usize,
    pub public_address:  Option<String>,
    pub answer_404:      String,
    pub answer_503:      String,
}

impl Default for HttpProxyConfiguration {
  fn default() -> HttpProxyConfiguration {
    HttpProxyConfiguration {
      front:           "127.0.0.1:8080".parse().unwrap(),
      front_timeout:   5000,
      back_timeout:    5000,
      max_connections: 1000,
      buffer_size:     12000,
      public_address:  None,
      answer_404:      String::from("HTTP/1.1 404 Not Found\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n"),
      answer_503:      String::from("HTTP/1.1 503 your application is in deployment\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n"),
    }
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize, Deserialize)]
pub struct TlsProxyConfiguration {
    pub front:           SocketAddr,
    pub front_timeout:   u64,
    pub back_timeout:    u64,
    pub max_connections: usize,
    pub buffer_size:     usize,
    pub public_address:  Option<String>,
    pub answer_404:      String,
    pub answer_503:      String,
    pub options:         i64,
    pub cipher_list:     String,
}

impl Default for TlsProxyConfiguration {
  fn default() -> TlsProxyConfiguration {
    TlsProxyConfiguration {
      front:           "127.0.0.1:8443".parse().unwrap(),
      front_timeout:   5000,
      back_timeout:    5000,
      max_connections: 1000,
      buffer_size:     12000,
      public_address:  None,
      answer_404:      String::from("HTTP/1.1 404 Not Found\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n"),
      answer_503:      String::from("HTTP/1.1 503 your application is in deployment\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n"),
      cipher_list:     String::from("ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305"),
      options:         (ssl::SSL_OP_CIPHER_SERVER_PREFERENCE | ssl::SSL_OP_NO_COMPRESSION |
                         ssl::SSL_OP_NO_TICKET | ssl::SSL_OP_NO_SSLV2 |
                         ssl::SSL_OP_NO_SSLV3 | ssl::SSL_OP_NO_TLSV1).bits(),
    }
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize)]
pub enum Command {
    AddHttpFront(HttpFront),
    RemoveHttpFront(HttpFront),

    AddTlsFront(TlsFront),
    RemoveTlsFront(TlsFront),

    AddTcpFront(TcpFront),
    RemoveTcpFront(TcpFront),

    AddInstance(Instance),
    RemoveInstance(Instance),

    HttpProxy(HttpProxyConfiguration),
    TlsProxy(TlsProxyConfiguration),
}

impl Command {
  pub fn get_topics(&self) -> Vec<Topic> {
    match *self {
      Command::AddHttpFront(_)    => vec![Topic::HttpProxyConfig                       ],
      Command::RemoveHttpFront(_) => vec![Topic::HttpProxyConfig                       ],
      Command::AddTlsFront(_)     => vec![Topic::TlsProxyConfig                        ],
      Command::RemoveTlsFront(_)  => vec![Topic::TlsProxyConfig                        ],
      Command::AddTcpFront(_)     => vec![Topic::TcpProxyConfig                        ],
      Command::RemoveTcpFront(_)  => vec![Topic::TcpProxyConfig                        ],
      Command::AddInstance(_)     => vec![Topic::HttpProxyConfig, Topic::TlsProxyConfig, Topic::TcpProxyConfig],
      Command::RemoveInstance(_)  => vec![Topic::HttpProxyConfig, Topic::TlsProxyConfig, Topic::TcpProxyConfig],
      Command::HttpProxy(_)       => vec![Topic::HttpProxyConfig],
      Command::TlsProxy(_)        => vec![Topic::TlsProxyConfig],
    }
  }
}

enum CommandField {
  Type,
  Data,
}

impl serde::Deserialize for CommandField {
  fn deserialize<D>(deserializer: &mut D) -> Result<CommandField, D::Error>
        where D: serde::de::Deserializer {
    struct CommandFieldVisitor;
    impl serde::de::Visitor for CommandFieldVisitor {
      type Value = CommandField;

      fn visit_str<E>(&mut self, value: &str) -> Result<CommandField, E>
        where E: serde::de::Error {
        match value {
          "type" => Ok(CommandField::Type),
          "data" => Ok(CommandField::Data),
          _ => Err(serde::de::Error::custom("expected type or data")),
        }
      }
    }

    deserializer.deserialize(CommandFieldVisitor)
  }
}

struct CommandVisitor;
impl serde::de::Visitor for CommandVisitor {
  type Value = Command;

  fn visit_map<V>(&mut self, mut visitor: V) -> Result<Command, V::Error>
        where V: serde::de::MapVisitor {
    let mut command_type:Option<String>    = None;
    let mut data:Option<serde_json::Value> = None;

    loop {
      match try!(visitor.visit_key()) {
        Some(CommandField::Type) => { command_type = Some(try!(visitor.visit_value())); }
        Some(CommandField::Data) => { data = Some(try!(visitor.visit_value())); }
        None => { break; }
      }
    }

    //println!("decoded type = {:?}, value= {:?}", command_type, data);
    let command_type = match command_type {
      Some(command) => command,
      None => try!(visitor.missing_field("type")),
    };
    let data = match data {
      Some(data) => data,
      None => try!(visitor.missing_field("data")),
    };

    try!(visitor.end());

    if &command_type == "ADD_HTTP_FRONT" {
      let res = serde_json::from_value(data).or(Err(serde::de::Error::custom("add_http_front")));
      //println!("ADD_HTTP_FRONT => {:?}", res);
      let acl = try!(res);
      Ok(Command::AddHttpFront(acl))
    } else if &command_type == "REMOVE_HTTP_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("remove_http_front"))));
      Ok(Command::RemoveHttpFront(acl))
    } else if &command_type == "ADD_TLS_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("add_tls_front"))));
      Ok(Command::AddTlsFront(acl))
    } else if &command_type == "REMOVE_TLS_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("remove_tls_front"))));
      Ok(Command::RemoveTlsFront(acl))
    } else if &command_type == "ADD_TCP_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("add_tcp_front"))));
      Ok(Command::AddTcpFront(acl))
    } else if &command_type == "REMOVE_TCP_FRONT" {
      let acl = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("remove_tcp_front"))));
      Ok(Command::RemoveTcpFront(acl))
    } else if &command_type == "ADD_INSTANCE" {
      let instance = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("add_instance"))));
      Ok(Command::AddInstance(instance))
    } else if &command_type == "REMOVE_INSTANCE" {
      let instance = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("remove_instance"))));
      Ok(Command::RemoveInstance(instance))
    } else if &command_type == "CONFIGURE_HTTP_PROXY" {
      let conf = try!(serde_json::from_value(data).or(Err(serde::de::Error::custom("configure_http_proxy"))));
      Ok(Command::HttpProxy(conf))
    } else {
      Err(serde::de::Error::custom("unrecognized command"))
    }
  }
}

impl serde::Deserialize for Command {
  fn deserialize<D>(deserializer: &mut D) -> Result<Command, D::Error>
        where D: serde::de::Deserializer {
    static FIELDS: &'static [&'static str] = &["type", "data"];
    deserializer.deserialize_struct("Command", FIELDS, CommandVisitor)
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash)]
pub enum Topic {
    HttpProxyConfig,
    TlsProxyConfig,
    TcpProxyConfig
}

pub trait Sender<T> {
  fn send_message(&self, t:T) -> Result<(), io::Error>;
}

pub trait Receiver<T> {
  fn recv_message(&self) -> Result<T, io::Error>;
}

impl<T> Sender<T> for mpsc::Sender<T> {
  fn send_message(&self, t:T) -> Result<(), io::Error> {
    match self.send(t) {
      Ok(()) => Ok(()),
      Err(mpsc::SendError(_)) => Err(io::Error::new(io::ErrorKind::BrokenPipe, "receiver disconnected"))
    }
  }
}

impl<T> Sender<T> for channel::Sender<T> {
  fn send_message(&self, t:T) -> Result<(), io::Error> {
    match self.send(t) {
      Ok(()) => Ok(()),
      Err(channel::SendError::Io(e)) => Err(e),
      Err(channel::SendError::Disconnected(_)) => Err(io::Error::new(io::ErrorKind::BrokenPipe, "receiver disconnected"))
    }
  }
}

impl<T> Receiver<T> for channel::Receiver<T> {
  fn recv_message(&self) -> Result<T, io::Error> {
    match self.try_recv() {
      Ok(t) => Ok(t),
      Err(mpsc::TryRecvError::Empty) => Err(io::Error::new(io::ErrorKind::WouldBlock, "no data")),
      Err(mpsc::TryRecvError::Disconnected) => Err(io::Error::new(io::ErrorKind::BrokenPipe, "receiver disconnected"))
    }
  }
}

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

  #[test]
  fn add_acl_test() {
    let raw_json = r#"{"type": "ADD_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "port": 4242}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::AddHttpFront(HttpFront{
      app_id: String::from("xxx"),
      hostname: String::from("yyy"),
      path_begin: String::from("xxx"),
    }));
  }

  #[test]
  fn remove_acl_test() {
    let raw_json = r#"{"type": "REMOVE_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "port": 4242}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::RemoveHttpFront(HttpFront{
      app_id: String::from("xxx"),
      hostname: String::from("yyy"),
      path_begin: String::from("xxx"),
    }));
  }

  #[test]
  fn add_instance_test() {
    let raw_json = r#"{"type": "ADD_INSTANCE", "data": {"app_id": "xxx", "ip_address": "yyy", "port": 8080}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::AddInstance(Instance{
      app_id: String::from("xxx"),
      ip_address: String::from("yyy"),
      port: 8080
    }));
  }

  #[test]
  fn remove_instance_test() {
    let raw_json = r#"{"type": "REMOVE_INSTANCE", "data": {"app_id": "xxx", "ip_address": "yyy", "port": 8080}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::RemoveInstance(Instance{
      app_id: String::from("xxx"),
      ip_address: String::from("yyy"),
      port: 8080
    }));
  }

  #[test]
  fn http_front_crash_test() {
    let raw_json = r#"{"type": "ADD_HTTP_FRONT", "data": {"app_id": "aa", "hostname": "cltdl.fr", "path_begin": ""}}"#;
    let command: Command = serde_json::from_str(raw_json).unwrap();
    println!("{:?}", command);
    assert!(command == Command::AddHttpFront(HttpFront{
      app_id: String::from("aa"),
      hostname: String::from("cltdl.fr"),
      path_begin: String::from(""),
    }));
  }

  #[test]
  fn http_front_crash_test2() {
    let raw_json = r#"{"app_id": "aa", "hostname": "cltdl.fr", "path_begin": ""}"#;
    let front: HttpFront = serde_json::from_str(raw_json).unwrap();
    println!("{:?}",front);
    assert!(front == HttpFront{
      app_id: String::from("aa"),
      hostname: String::from("cltdl.fr"),
      path_begin: String::from(""),
    });
  }
}

<|endoftext|>


<commit_before>//! A collection of newtypes defining type-strong IDs.

use std::fmt::{Display, Formatter, Result as FmtResult};

use chrono::{DateTime, TimeZone, Utc};
use serde::de::{Deserialize, Deserializer};

use super::utils::U64Visitor;
use crate::internal::prelude::*;

macro_rules! id_u64 {
    ($($name:ident;)*) => {
        $(
            impl $name {
                /// Retrieves the time that the Id was created at.
                pub fn created_at(&self) -> DateTime<Utc> {
                    const DISCORD_EPOCH: u64 = 1_420_070_400_000;
                    Utc.timestamp_millis(((self.0 >> 22) + DISCORD_EPOCH) as i64)
                }

                /// Immutably borrow inner Id.
                #[inline]
                pub fn as_u64(&self) -> &u64 {
                    &self.0
                }

                /// Mutably borrow inner Id.
                #[inline]
                pub fn as_mut_u64(&mut self) -> &mut u64 {
                    &mut self.0
                }
            }

            // This is a hack so functions can accept iterators that either:
            // 1. return the id itself (e.g: `MessageId`)
            // 2. return a reference to it (`&MessageId`).
            impl AsRef<$name> for $name {
                fn as_ref(&self) -> &Self {
                    self
                }
            }

            impl<'a> From<&'a $name> for $name {
                fn from(id: &'a $name) -> $name {
                    id.clone()
                }
            }

            impl From<u64> for $name {
                fn from(id_as_u64: u64) -> $name {
                    $name(id_as_u64)
                }
            }

            impl PartialEq<u64> for $name {
                fn eq(&self, u: &u64) -> bool {
                    self.0 == *u
                }
            }

            impl Display for $name {
                fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
                    Display::fmt(&self.0, f)
                }
            }

            impl<'de> Deserialize<'de> for $name {
                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
                    deserializer.deserialize_any(U64Visitor).map($name)
                }
            }

            impl From<$name> for u64 {
                fn from(id: $name) -> u64 {
                    id.0 as u64
                }
            }

            impl From<$name> for i64 {
                fn from(id: $name) -> i64 {
                    id.0 as i64
                }
            }
        )*
    }
}

/// An identifier for an Application.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct ApplicationId(pub u64);

/// An identifier for a Channel
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct ChannelId(pub u64);

/// An identifier for an Emoji
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct EmojiId(pub u64);

/// An identifier for a Guild
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct GuildId(pub u64);

/// An identifier for an Integration
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct IntegrationId(pub u64);

/// An identifier for a Message
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct MessageId(pub u64);

/// An identifier for a Role
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct RoleId(pub u64);

/// An identifier for a User
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct UserId(pub u64);

/// An identifier for a [`Webhook`][super::webhook::Webhook]
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct WebhookId(pub u64);

/// An identifier for an audit log entry.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct AuditLogEntryId(pub u64);

/// An identifier for an attachment.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct AttachmentId(u64);

/// An identifier for a sticker.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct StickerId(pub u64);

/// An identifier for a sticker pack.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct StickerPackId(pub u64);

/// An identifier for an interaction.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct InteractionId(pub u64);

/// An identifier for a slash command.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct CommandId(pub u64);

/// An identifier for a slash command permission Id. Can contain
/// a [`RoleId`] or [`UserId`].
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct CommandPermissionId(pub u64);

/// An identifier for a slash command version Id.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct CommandVersionId(pub u64);

/// An identifier for a slash command target Id. Can contain
/// a [`UserId`] or [`MessageId`].
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct TargetId(pub u64);

/// An identifier for a stage channel instance.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct StageInstanceId(pub u64);

id_u64! {
    AttachmentId;
    ApplicationId;
    ChannelId;
    EmojiId;
    GuildId;
    IntegrationId;
    MessageId;
    RoleId;
    StickerId;
    StickerPackId;
    UserId;
    WebhookId;
    AuditLogEntryId;
    InteractionId;
    CommandId;
    CommandPermissionId;
    CommandVersionId;
    TargetId;
    StageInstanceId;
}

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

    #[test]
    fn test_created_at() {
        // The id is from discord's snowflake docs
        assert_eq!(
            GuildId(175928847299117063).created_at().to_rfc3339(),
            "2016-04-30T11:18:25.796+00:00"
        );
    }
}
<commit_msg>Make the `u64` value of `AttachmentId`s public (#1591)<commit_after>//! A collection of newtypes defining type-strong IDs.

use std::fmt::{Display, Formatter, Result as FmtResult};

use chrono::{DateTime, TimeZone, Utc};
use serde::de::{Deserialize, Deserializer};

use super::utils::U64Visitor;
use crate::internal::prelude::*;

macro_rules! id_u64 {
    ($($name:ident;)*) => {
        $(
            impl $name {
                /// Retrieves the time that the Id was created at.
                pub fn created_at(&self) -> DateTime<Utc> {
                    const DISCORD_EPOCH: u64 = 1_420_070_400_000;
                    Utc.timestamp_millis(((self.0 >> 22) + DISCORD_EPOCH) as i64)
                }

                /// Immutably borrow inner Id.
                #[inline]
                pub fn as_u64(&self) -> &u64 {
                    &self.0
                }

                /// Mutably borrow inner Id.
                #[inline]
                pub fn as_mut_u64(&mut self) -> &mut u64 {
                    &mut self.0
                }
            }

            // This is a hack so functions can accept iterators that either:
            // 1. return the id itself (e.g: `MessageId`)
            // 2. return a reference to it (`&MessageId`).
            impl AsRef<$name> for $name {
                fn as_ref(&self) -> &Self {
                    self
                }
            }

            impl<'a> From<&'a $name> for $name {
                fn from(id: &'a $name) -> $name {
                    id.clone()
                }
            }

            impl From<u64> for $name {
                fn from(id_as_u64: u64) -> $name {
                    $name(id_as_u64)
                }
            }

            impl PartialEq<u64> for $name {
                fn eq(&self, u: &u64) -> bool {
                    self.0 == *u
                }
            }

            impl Display for $name {
                fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
                    Display::fmt(&self.0, f)
                }
            }

            impl<'de> Deserialize<'de> for $name {
                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
                    deserializer.deserialize_any(U64Visitor).map($name)
                }
            }

            impl From<$name> for u64 {
                fn from(id: $name) -> u64 {
                    id.0 as u64
                }
            }

            impl From<$name> for i64 {
                fn from(id: $name) -> i64 {
                    id.0 as i64
                }
            }
        )*
    }
}

/// An identifier for an Application.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct ApplicationId(pub u64);

/// An identifier for a Channel
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct ChannelId(pub u64);

/// An identifier for an Emoji
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct EmojiId(pub u64);

/// An identifier for a Guild
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct GuildId(pub u64);

/// An identifier for an Integration
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct IntegrationId(pub u64);

/// An identifier for a Message
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct MessageId(pub u64);

/// An identifier for a Role
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct RoleId(pub u64);

/// An identifier for a User
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct UserId(pub u64);

/// An identifier for a [`Webhook`][super::webhook::Webhook]
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct WebhookId(pub u64);

/// An identifier for an audit log entry.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct AuditLogEntryId(pub u64);

/// An identifier for an attachment.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct AttachmentId(pub u64);

/// An identifier for a sticker.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct StickerId(pub u64);

/// An identifier for a sticker pack.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct StickerPackId(pub u64);

/// An identifier for an interaction.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct InteractionId(pub u64);

/// An identifier for a slash command.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct CommandId(pub u64);

/// An identifier for a slash command permission Id. Can contain
/// a [`RoleId`] or [`UserId`].
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct CommandPermissionId(pub u64);

/// An identifier for a slash command version Id.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct CommandVersionId(pub u64);

/// An identifier for a slash command target Id. Can contain
/// a [`UserId`] or [`MessageId`].
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct TargetId(pub u64);

/// An identifier for a stage channel instance.
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct StageInstanceId(pub u64);

id_u64! {
    AttachmentId;
    ApplicationId;
    ChannelId;
    EmojiId;
    GuildId;
    IntegrationId;
    MessageId;
    RoleId;
    StickerId;
    StickerPackId;
    UserId;
    WebhookId;
    AuditLogEntryId;
    InteractionId;
    CommandId;
    CommandPermissionId;
    CommandVersionId;
    TargetId;
    StageInstanceId;
}

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

    #[test]
    fn test_created_at() {
        // The id is from discord's snowflake docs
        assert_eq!(
            GuildId(175928847299117063).created_at().to_rfc3339(),
            "2016-04-30T11:18:25.796+00:00"
        );
    }
}
<|endoftext|>


<commit_before>use iron::Response;
use iron::modifier::Modifier;
use serde::Serialize;
use serde_json::to_string;

#[derive(Clone, Debug)]
pub struct SerializableResponse<T: Serialize>(pub T);

impl<T> Modifier<Response> for SerializableResponse<T> where T: Serialize {
    fn modify(self, response: &mut Response) {
        response.body = Some(Box::new(to_string(&self.0).expect("could not serialize response data")));
    }
}
<commit_msg>Set the Content-Type header in responses.<commit_after>use iron::Response;
use iron::headers::ContentType;
use iron::modifier::Modifier;
use serde::Serialize;
use serde_json::to_string;

#[derive(Clone, Debug)]
pub struct SerializableResponse<T: Serialize>(pub T);

impl<T> Modifier<Response> for SerializableResponse<T> where T: Serialize {
    fn modify(self, response: &mut Response) {
        response.headers.set(ContentType::json());
        response.body = Some(Box::new(to_string(&self.0).expect("could not serialize response data")));
    }
}
<|endoftext|>