<commit_before>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        println!("tick: {:?}", keypad);
        self.vram_changed = false;
        let opcode = self.get_opcode();
        self.run_opcode(opcode);
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&mut self, opcode: u16) {

        let nibbles = (
            (opcode & 0x000F) as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0xF000) >> 12 as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x00, _, _, _) => self.op_0nnn(nnn),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS
    fn op_00e0(&mut self) {
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                self.vram[y][x] = 0;
            }
        }
        self.vram_changed = true;
    }

    // RET
    fn op_00ee(&mut self) {}
    // SYS addr
    fn op_0nnn(&mut self, nnn: u16) {}
    // JP addr
    fn op_1nnn(&mut self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&mut self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&mut self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&mut self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&mut self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&mut self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&mut self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&mut self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&mut self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&mut self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&mut self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&mut self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&mut self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&mut self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&mut self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&mut self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&mut self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&mut self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&mut self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&mut self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&mut self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&mut self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&mut self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&mut self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&mut self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&mut self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&mut self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&mut self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&mut self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&mut self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&mut self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&mut self, x: usize) {}
}

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

    #[test]
    fn test_initial_state() {
        let processor = Processor::new();
        assert_eq!(processor.sp, 0);
        assert_eq!(processor.stack, [0; 16]);
    }

    // CLS
    fn test_op_00e0() {
        let mut processor = Processor::new();
        processor.vram = [[128; CHIP8_WIDTH]; CHIP8_HEIGHT];
        processor.run_opcode(0x00e0);
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                assert_eq!(processor.vram[y][x], 0);
            }
        }
    }

}
<commit_msg>fix nibbles order and add RET<commit_after>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        self.vram_changed = false;
        let opcode = self.get_opcode();
        self.run_opcode(opcode);
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&mut self, opcode: u16) {

        let nibbles = (
            (opcode & 0xF000) >> 12 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x000F) as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS: Clear the display.
    fn op_00e0(&mut self) {
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                self.vram[y][x] = 0;
            }
        }
        self.vram_changed = true;
    }

    // RET:  Return from a subroutine.
    fn op_00ee(&mut self) {
        self.pc = self.stack[self.sp];
        self.sp -= 1;
    }

    // JP addr
    fn op_1nnn(&mut self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&mut self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&mut self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&mut self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&mut self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&mut self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&mut self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&mut self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&mut self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&mut self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&mut self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&mut self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&mut self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&mut self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&mut self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&mut self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&mut self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&mut self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&mut self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&mut self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&mut self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&mut self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&mut self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&mut self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&mut self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&mut self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&mut self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&mut self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&mut self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&mut self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&mut self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&mut self, x: usize) {}
}

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

    #[test]
    fn test_initial_state() {
        let processor = Processor::new();
        assert_eq!(processor.sp, 0);
        assert_eq!(processor.stack, [0; 16]);
    }

    // CLS
    #[test]
    fn test_op_00e0() {
        let mut processor = Processor::new();
        processor.vram = [[128; CHIP8_WIDTH]; CHIP8_HEIGHT];
        processor.run_opcode(0x00e0);
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                assert_eq!(processor.vram[y][x], 0);
            }
        }
    }

    // RET
    #[test]
    fn test_op_00ee() {
        let mut processor = Processor::new();
        processor.sp = 5;
        processor.stack[5] = 0x6666;
        processor.run_opcode(0x00ee);
        assert_eq!(processor.sp, 4);
        assert_eq!(processor.pc, 0x6666);
    }

}
<|endoftext|>


<commit_before>/*#[cfg(feature = "window")]
pub use api::x11::{Window, WindowProxy, MonitorID, get_available_monitors, get_primary_monitor};
#[cfg(feature = "window")]
pub use api::x11::{WaitEventsIterator, PollEventsIterator};*/

use std::collections::VecDeque;

use BuilderAttribs;
use CreationError;
use CursorState;
use Event;
use GlContext;
use MouseCursor;
use PixelFormat;
use libc;

use api::wayland;
use api::x11;

pub enum Window {
    #[doc(hidden)]
    X(x11::Window),
    #[doc(hidden)]
    Wayland(wayland::Window)
}

#[derive(Clone)]
pub enum WindowProxy {
    #[doc(hidden)]
    X(x11::WindowProxy),
    #[doc(hidden)]
    Wayland(wayland::WindowProxy)
}

impl WindowProxy {
    pub fn wakeup_event_loop(&self) {
        match self {
            &WindowProxy::X(ref wp) => wp.wakeup_event_loop(),
            &WindowProxy::Wayland(ref wp) => wp.wakeup_event_loop()
        }
    }
}

pub enum MonitorID {
    #[doc(hidden)]
    X(x11::MonitorID),
    #[doc(hidden)]
    Wayland(wayland::MonitorID)
}

pub fn get_available_monitors() -> VecDeque<MonitorID> {
    if false && wayland::is_available() {
        // We are doing wayland
        wayland::get_available_monitors()
            .into_iter()
            .map(|m| MonitorID::Wayland(m))
            .collect()
    } else {
        // Fallback on X
        x11::get_available_monitors()
            .into_iter()
            .map(|m| MonitorID::X(m))
            .collect()
    }
}
pub fn get_primary_monitor() -> MonitorID {
    if false && wayland::is_available() {
        MonitorID::Wayland(wayland::get_primary_monitor())
    } else {
        MonitorID::X(x11::get_primary_monitor())
    }
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorID::X(ref m) => m.get_name(),
            &MonitorID::Wayland(ref m) => m.get_name()
        }
    }

    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorID::X(ref m) => m.get_native_identifier(),
            &MonitorID::Wayland(ref m) => m.get_native_identifier()
        }
    }

    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorID::X(ref m) => m.get_dimensions(),
            &MonitorID::Wayland(ref m) => m.get_dimensions()
        }
    }
}

pub enum PollEventsIterator<'a> {
    #[doc(hidden)]
    X(x11::PollEventsIterator<'a>),
    #[doc(hidden)]
    Wayland(wayland::PollEventsIterator<'a>)
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        match self {
            &mut PollEventsIterator::X(ref mut it) => it.next(),
            &mut PollEventsIterator::Wayland(ref mut it) => it.next()
        }
    }
}

pub enum WaitEventsIterator<'a> {
    #[doc(hidden)]
    X(x11::WaitEventsIterator<'a>),
    #[doc(hidden)]
    Wayland(wayland::WaitEventsIterator<'a>)
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        match self {
            &mut WaitEventsIterator::X(ref mut it) => it.next(),
            &mut WaitEventsIterator::Wayland(ref mut it) => it.next()
        }
    }
}

impl Window {
    pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
        if false && wayland::is_available() {
            // we have a wayland connection, go for it
            let window = try!(wayland::Window::new(builder));
            Ok(Window::Wayland(window))
        } else {
            // fallback on X
            let window = try!(x11::Window::new(builder));
            Ok(Window::X(window))
        }
    }

    pub fn is_closed(&self) -> bool {
        match self {
            &Window::X(ref w) => w.is_closed(),
            &Window::Wayland(ref w) => w.is_closed()
        }
    }

    pub fn set_title(&self, title: &str) {
        match self {
            &Window::X(ref w) => w.set_title(title),
            &Window::Wayland(ref w) => w.set_title(title)
        }
    }

    pub fn show(&self) {
        match self {
            &Window::X(ref w) => w.show(),
            &Window::Wayland(ref w) => w.show()
        }
    }

    pub fn hide(&self) {
        match self {
            &Window::X(ref w) => w.hide(),
            &Window::Wayland(ref w) => w.hide()
        }
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window::X(ref w) => w.get_position(),
            &Window::Wayland(ref w) => w.get_position()
        }
    }

    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window::X(ref w) => w.set_position(x, y),
            &Window::Wayland(ref w) => w.set_position(x, y)
        }
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window::X(ref w) => w.get_inner_size(),
            &Window::Wayland(ref w) => w.get_inner_size()
        }
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window::X(ref w) => w.get_outer_size(),
            &Window::Wayland(ref w) => w.get_outer_size()
        }
    }

    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window::X(ref w) => w.set_inner_size(x, y),
            &Window::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    pub fn create_window_proxy(&self) -> WindowProxy {
        match self {
            &Window::X(ref w) => WindowProxy::X(w.create_window_proxy()),
            &Window::Wayland(ref w) => WindowProxy::Wayland(w.create_window_proxy())
        }
    }

    pub fn poll_events(&self) -> PollEventsIterator {
        match self {
            &Window::X(ref w) => PollEventsIterator::X(w.poll_events()),
            &Window::Wayland(ref w) => PollEventsIterator::Wayland(w.poll_events())
        }
    }

    pub fn wait_events(&self) -> WaitEventsIterator {
        match self {
            &Window::X(ref w) => WaitEventsIterator::X(w.wait_events()),
            &Window::Wayland(ref w) => WaitEventsIterator::Wayland(w.wait_events())
        }
    }

    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        match self {
            &mut Window::X(ref mut w) => w.set_window_resize_callback(callback),
            &mut Window::Wayland(ref mut w) => w.set_window_resize_callback(callback)
        }
    }

    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window::X(ref w) => w.set_cursor(cursor),
            &Window::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window::X(ref w) => w.set_cursor_state(state),
            &Window::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window::X(ref w) => w.hidpi_factor(),
            &Window::Wayland(ref w) => w.hidpi_factor()
        }
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window::X(ref w) => w.set_cursor_position(x, y),
            &Window::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        match self {
            &Window::X(ref w) => w.platform_display(),
            &Window::Wayland(ref w) => w.platform_display()
        }
    }

    pub fn platform_window(&self) -> *mut libc::c_void {
        match self {
            &Window::X(ref w) => w.platform_window(),
            &Window::Wayland(ref w) => w.platform_window()
        }
    }
}

impl GlContext for Window {

    unsafe fn make_current(&self) {
        match self {
            &Window::X(ref w) => w.make_current(),
            &Window::Wayland(ref w) => w.make_current()
        }
    }

    fn is_current(&self) -> bool {
        match self {
            &Window::X(ref w) => w.is_current(),
            &Window::Wayland(ref w) => w.is_current()
        }
    }

    fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
        match self {
            &Window::X(ref w) => w.get_proc_address(addr),
            &Window::Wayland(ref w) => w.get_proc_address(addr)
        }
    }

    fn swap_buffers(&self) {
        match self {
            &Window::X(ref w) => w.swap_buffers(),
            &Window::Wayland(ref w) => w.swap_buffers()
        }
    }

    fn get_api(&self) -> ::Api {
        match self {
            &Window::X(ref w) => w.get_api(),
            &Window::Wayland(ref w) => w.get_api()
        }
    }

    fn get_pixel_format(&self) -> PixelFormat {
        match self {
            &Window::X(ref w) => w.get_pixel_format(),
            &Window::Wayland(ref w) => w.get_pixel_format()
        }
    }
}<commit_msg>Do the linux backend choice only once at startup.<commit_after>/*#[cfg(feature = "window")]
pub use api::x11::{Window, WindowProxy, MonitorID, get_available_monitors, get_primary_monitor};
#[cfg(feature = "window")]
pub use api::x11::{WaitEventsIterator, PollEventsIterator};*/

use std::collections::VecDeque;

use BuilderAttribs;
use CreationError;
use CursorState;
use Event;
use GlContext;
use MouseCursor;
use PixelFormat;
use libc;

use api::wayland;
use api::x11;

enum Backend {
    X,
    Wayland
}

lazy_static!(
    static ref BACKEND: Backend = {
        // Wayland backend is not production-ready yet so we disable it
        if false && wayland::is_available() {
            Backend::Wayland
        } else {
            Backend::X
        }
    };
);

pub enum Window {
    #[doc(hidden)]
    X(x11::Window),
    #[doc(hidden)]
    Wayland(wayland::Window)
}

#[derive(Clone)]
pub enum WindowProxy {
    #[doc(hidden)]
    X(x11::WindowProxy),
    #[doc(hidden)]
    Wayland(wayland::WindowProxy)
}

impl WindowProxy {
    pub fn wakeup_event_loop(&self) {
        match self {
            &WindowProxy::X(ref wp) => wp.wakeup_event_loop(),
            &WindowProxy::Wayland(ref wp) => wp.wakeup_event_loop()
        }
    }
}

pub enum MonitorID {
    #[doc(hidden)]
    X(x11::MonitorID),
    #[doc(hidden)]
    Wayland(wayland::MonitorID)
}

pub fn get_available_monitors() -> VecDeque<MonitorID> {
    match *BACKEND {
        Backend::Wayland => wayland::get_available_monitors()
                                .into_iter()
                                .map(MonitorID::Wayland)
                                .collect(),
        Backend::X => x11::get_available_monitors()
                        .into_iter()
                        .map(MonitorID::X)
                        .collect(),
    }
}
pub fn get_primary_monitor() -> MonitorID {
    match *BACKEND {
        Backend::Wayland => MonitorID::Wayland(wayland::get_primary_monitor()),
        Backend::X => MonitorID::X(x11::get_primary_monitor()),
    }
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorID::X(ref m) => m.get_name(),
            &MonitorID::Wayland(ref m) => m.get_name()
        }
    }

    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorID::X(ref m) => m.get_native_identifier(),
            &MonitorID::Wayland(ref m) => m.get_native_identifier()
        }
    }

    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorID::X(ref m) => m.get_dimensions(),
            &MonitorID::Wayland(ref m) => m.get_dimensions()
        }
    }
}

pub enum PollEventsIterator<'a> {
    #[doc(hidden)]
    X(x11::PollEventsIterator<'a>),
    #[doc(hidden)]
    Wayland(wayland::PollEventsIterator<'a>)
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        match self {
            &mut PollEventsIterator::X(ref mut it) => it.next(),
            &mut PollEventsIterator::Wayland(ref mut it) => it.next()
        }
    }
}

pub enum WaitEventsIterator<'a> {
    #[doc(hidden)]
    X(x11::WaitEventsIterator<'a>),
    #[doc(hidden)]
    Wayland(wayland::WaitEventsIterator<'a>)
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        match self {
            &mut WaitEventsIterator::X(ref mut it) => it.next(),
            &mut WaitEventsIterator::Wayland(ref mut it) => it.next()
        }
    }
}

impl Window {
    pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
        match *BACKEND {
            Backend::Wayland => wayland::Window::new(builder).map(Window::Wayland),
            Backend::X => x11::Window::new(builder).map(Window::X),
        }
    }

    pub fn is_closed(&self) -> bool {
        match self {
            &Window::X(ref w) => w.is_closed(),
            &Window::Wayland(ref w) => w.is_closed()
        }
    }

    pub fn set_title(&self, title: &str) {
        match self {
            &Window::X(ref w) => w.set_title(title),
            &Window::Wayland(ref w) => w.set_title(title)
        }
    }

    pub fn show(&self) {
        match self {
            &Window::X(ref w) => w.show(),
            &Window::Wayland(ref w) => w.show()
        }
    }

    pub fn hide(&self) {
        match self {
            &Window::X(ref w) => w.hide(),
            &Window::Wayland(ref w) => w.hide()
        }
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window::X(ref w) => w.get_position(),
            &Window::Wayland(ref w) => w.get_position()
        }
    }

    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window::X(ref w) => w.set_position(x, y),
            &Window::Wayland(ref w) => w.set_position(x, y)
        }
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window::X(ref w) => w.get_inner_size(),
            &Window::Wayland(ref w) => w.get_inner_size()
        }
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window::X(ref w) => w.get_outer_size(),
            &Window::Wayland(ref w) => w.get_outer_size()
        }
    }

    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window::X(ref w) => w.set_inner_size(x, y),
            &Window::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    pub fn create_window_proxy(&self) -> WindowProxy {
        match self {
            &Window::X(ref w) => WindowProxy::X(w.create_window_proxy()),
            &Window::Wayland(ref w) => WindowProxy::Wayland(w.create_window_proxy())
        }
    }

    pub fn poll_events(&self) -> PollEventsIterator {
        match self {
            &Window::X(ref w) => PollEventsIterator::X(w.poll_events()),
            &Window::Wayland(ref w) => PollEventsIterator::Wayland(w.poll_events())
        }
    }

    pub fn wait_events(&self) -> WaitEventsIterator {
        match self {
            &Window::X(ref w) => WaitEventsIterator::X(w.wait_events()),
            &Window::Wayland(ref w) => WaitEventsIterator::Wayland(w.wait_events())
        }
    }

    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        match self {
            &mut Window::X(ref mut w) => w.set_window_resize_callback(callback),
            &mut Window::Wayland(ref mut w) => w.set_window_resize_callback(callback)
        }
    }

    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window::X(ref w) => w.set_cursor(cursor),
            &Window::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window::X(ref w) => w.set_cursor_state(state),
            &Window::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window::X(ref w) => w.hidpi_factor(),
            &Window::Wayland(ref w) => w.hidpi_factor()
        }
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window::X(ref w) => w.set_cursor_position(x, y),
            &Window::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        match self {
            &Window::X(ref w) => w.platform_display(),
            &Window::Wayland(ref w) => w.platform_display()
        }
    }

    pub fn platform_window(&self) -> *mut libc::c_void {
        match self {
            &Window::X(ref w) => w.platform_window(),
            &Window::Wayland(ref w) => w.platform_window()
        }
    }
}

impl GlContext for Window {

    unsafe fn make_current(&self) {
        match self {
            &Window::X(ref w) => w.make_current(),
            &Window::Wayland(ref w) => w.make_current()
        }
    }

    fn is_current(&self) -> bool {
        match self {
            &Window::X(ref w) => w.is_current(),
            &Window::Wayland(ref w) => w.is_current()
        }
    }

    fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
        match self {
            &Window::X(ref w) => w.get_proc_address(addr),
            &Window::Wayland(ref w) => w.get_proc_address(addr)
        }
    }

    fn swap_buffers(&self) {
        match self {
            &Window::X(ref w) => w.swap_buffers(),
            &Window::Wayland(ref w) => w.swap_buffers()
        }
    }

    fn get_api(&self) -> ::Api {
        match self {
            &Window::X(ref w) => w.get_api(),
            &Window::Wayland(ref w) => w.get_api()
        }
    }

    fn get_pixel_format(&self) -> PixelFormat {
        match self {
            &Window::X(ref w) => w.get_pixel_format(),
            &Window::Wayland(ref w) => w.get_pixel_format()
        }
    }
}<|endoftext|>


<commit_before>import vbuf = rustrt.vbuf;

type operator2[T,U,V] = fn(&T, &U) -> V;

native "rust" mod rustrt {
    type vbuf;

    fn vec_buf[T](vec[T] v, uint offset) -> vbuf;

    fn vec_len[T](vec[T] v) -> uint;
    /**
     * Sometimes we modify the vec internal data via vec_buf and need to
     * update the vec's fill length accordingly.
     */
    fn vec_len_set[T](vec[T] v, uint n);

    /**
     * The T in vec_alloc[T, U] is the type of the vec to allocate.  The
     * U is the type of an element in the vec.  So to allocate a vec[U] we
     * want to invoke this as vec_alloc[vec[U], U].
     */
    fn vec_alloc[T, U](uint n_elts) -> vec[U];
    fn vec_alloc_mut[T, U](uint n_elts) -> vec[mutable U];

    fn refcount[T](vec[T] v) -> uint;

    fn vec_print_debug_info[T](vec[T] v);
}

fn alloc[T](uint n_elts) -> vec[T] {
    ret rustrt.vec_alloc[vec[T], T](n_elts);
}

fn alloc_mut[T](uint n_elts) -> vec[mutable T] {
    ret rustrt.vec_alloc_mut[vec[mutable T], T](n_elts);
}

fn refcount[T](vec[mutable? T] v) -> uint {
    auto r = rustrt.refcount[T](v);
    if (r == dbg.const_refcount) {
        ret r;
    } else {
        // -1 because calling this function incremented the refcount.
        ret  r - 1u;
    }
}

type init_op[T] = fn(uint i) -> T;

fn init_fn[T](&init_op[T] op, uint n_elts) -> vec[T] {
    let vec[T] v = alloc[T](n_elts);
    let uint i = 0u;
    while (i < n_elts) {
        v += vec(op(i));
        i += 1u;
    }
    ret v;
}

fn init_fn_mut[T](&init_op[T] op, uint n_elts) -> vec[mutable T] {
    let vec[mutable T] v = alloc_mut[T](n_elts);
    let uint i = 0u;
    while (i < n_elts) {
        v += vec(mutable op(i));
        i += 1u;
    }
    ret v;
}

fn init_elt[T](&T t, uint n_elts) -> vec[T] {
    /**
     * FIXME (issue #81): should be:
     *
     * fn elt_op[T](&T x, uint i) -> T { ret x; }
     * let init_op[T] inner = bind elt_op[T](t, _);
     * ret init_fn[T](inner, n_elts);
     */
    let vec[T] v = alloc[T](n_elts);
    let uint i = n_elts;
    while (i > 0u) {
        i -= 1u;
        v += vec(t);
    }
    ret v;
}

fn init_elt_mut[T](&T t, uint n_elts) -> vec[mutable T] {
    let vec[mutable T] v = alloc_mut[T](n_elts);
    let uint i = n_elts;
    while (i > 0u) {
        i -= 1u;
        v += vec(mutable t);
    }
    ret v;
}

fn buf[T](vec[mutable? T] v) -> vbuf {
    ret rustrt.vec_buf[T](v, 0u);
}

fn len[T](vec[mutable? T] v) -> uint {
    ret rustrt.vec_len[T](v);
}

fn len_set[T](vec[mutable? T] v, uint n) {
    rustrt.vec_len_set[T](v, n);
}

fn buf_off[T](vec[mutable? T] v, uint offset) -> vbuf {
    check (offset < len[T](v));
    ret rustrt.vec_buf[T](v, offset);
}

fn print_debug_info[T](vec[mutable? T] v) {
    rustrt.vec_print_debug_info[T](v);
}

// Returns elements from [start..end) from v.
fn slice[T](vec[mutable? T] v, uint start, uint end) -> vec[T] {
    check (start <= end);
    check (end <= len[T](v));
    auto result = alloc[T](end - start);
    let uint i = start;
    while (i < end) {
        result += vec(v.(i));
        i += 1u;
    }
    ret result;
}

fn shift[T](&mutable vec[mutable? T] v) -> T {
    auto ln = len[T](v);
    check(ln > 0u);
    auto e = v.(0);
    v = slice[T](v, 1u, ln);
    ret e;
}

fn pop[T](&mutable vec[mutable? T] v) -> T {
    auto ln = len[T](v);
    check(ln > 0u);
    ln -= 1u;
    auto e = v.(ln);
    v = slice[T](v, 0u, ln);
    ret e;
}

fn push[T](&mutable vec[mutable? T] v, &T t) {
    v += vec(t);
}

fn unshift[T](&mutable vec[mutable? T] v, &T t) {
    auto res = alloc[T](len[T](v) + 1u);
    res += vec(t);
    res += v;
    v = res;
}

fn grow[T](&mutable vec[mutable? T] v, int n, &T initval) {
    let int i = n;
    while (i > 0) {
        i -= 1;
        v += vec(initval);
    }
}

fn map[T, U](&option.operator[T,U] f, &vec[mutable? T] v) -> vec[U] {
    let vec[U] u = alloc[U](len[T](v));
    for (T ve in v) {
        u += vec(f(ve));
    }
    ret u;
}

fn map2[T,U,V](&operator2[T,U,V] f, &vec[mutable? T] v0, &vec[mutable? U] v1)
        -> vec[V] {
    auto v0_len = len[T](v0);
    if (v0_len != len[U](v1)) {
        fail;
    }

    let vec[V] u = alloc[V](v0_len);
    auto i = 0u;
    while (i < v0_len) {
        u += vec(f(v0.(i), v1.(i)));
        i += 1u;
    }

    ret u;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Add a "last" function to return the last element of a vector to the standard library<commit_after>import option.none;
import option.some;

import vbuf = rustrt.vbuf;

type operator2[T,U,V] = fn(&T, &U) -> V;

native "rust" mod rustrt {
    type vbuf;

    fn vec_buf[T](vec[T] v, uint offset) -> vbuf;

    fn vec_len[T](vec[T] v) -> uint;
    /**
     * Sometimes we modify the vec internal data via vec_buf and need to
     * update the vec's fill length accordingly.
     */
    fn vec_len_set[T](vec[T] v, uint n);

    /**
     * The T in vec_alloc[T, U] is the type of the vec to allocate.  The
     * U is the type of an element in the vec.  So to allocate a vec[U] we
     * want to invoke this as vec_alloc[vec[U], U].
     */
    fn vec_alloc[T, U](uint n_elts) -> vec[U];
    fn vec_alloc_mut[T, U](uint n_elts) -> vec[mutable U];

    fn refcount[T](vec[T] v) -> uint;

    fn vec_print_debug_info[T](vec[T] v);
}

fn alloc[T](uint n_elts) -> vec[T] {
    ret rustrt.vec_alloc[vec[T], T](n_elts);
}

fn alloc_mut[T](uint n_elts) -> vec[mutable T] {
    ret rustrt.vec_alloc_mut[vec[mutable T], T](n_elts);
}

fn refcount[T](vec[mutable? T] v) -> uint {
    auto r = rustrt.refcount[T](v);
    if (r == dbg.const_refcount) {
        ret r;
    } else {
        // -1 because calling this function incremented the refcount.
        ret  r - 1u;
    }
}

type init_op[T] = fn(uint i) -> T;

fn init_fn[T](&init_op[T] op, uint n_elts) -> vec[T] {
    let vec[T] v = alloc[T](n_elts);
    let uint i = 0u;
    while (i < n_elts) {
        v += vec(op(i));
        i += 1u;
    }
    ret v;
}

fn init_fn_mut[T](&init_op[T] op, uint n_elts) -> vec[mutable T] {
    let vec[mutable T] v = alloc_mut[T](n_elts);
    let uint i = 0u;
    while (i < n_elts) {
        v += vec(mutable op(i));
        i += 1u;
    }
    ret v;
}

fn init_elt[T](&T t, uint n_elts) -> vec[T] {
    /**
     * FIXME (issue #81): should be:
     *
     * fn elt_op[T](&T x, uint i) -> T { ret x; }
     * let init_op[T] inner = bind elt_op[T](t, _);
     * ret init_fn[T](inner, n_elts);
     */
    let vec[T] v = alloc[T](n_elts);
    let uint i = n_elts;
    while (i > 0u) {
        i -= 1u;
        v += vec(t);
    }
    ret v;
}

fn init_elt_mut[T](&T t, uint n_elts) -> vec[mutable T] {
    let vec[mutable T] v = alloc_mut[T](n_elts);
    let uint i = n_elts;
    while (i > 0u) {
        i -= 1u;
        v += vec(mutable t);
    }
    ret v;
}

fn buf[T](vec[mutable? T] v) -> vbuf {
    ret rustrt.vec_buf[T](v, 0u);
}

fn len[T](vec[mutable? T] v) -> uint {
    ret rustrt.vec_len[T](v);
}

fn len_set[T](vec[mutable? T] v, uint n) {
    rustrt.vec_len_set[T](v, n);
}

fn buf_off[T](vec[mutable? T] v, uint offset) -> vbuf {
    check (offset < len[T](v));
    ret rustrt.vec_buf[T](v, offset);
}

fn print_debug_info[T](vec[mutable? T] v) {
    rustrt.vec_print_debug_info[T](v);
}

// Returns the last element of v.
fn last[T](vec[mutable? T] v) -> option.t[T] {
    auto l = len[T](v);
    if (l == 0u) {
        ret none[T];
    }
    ret some[T](v.(l - 1u));
}

// Returns elements from [start..end) from v.
fn slice[T](vec[mutable? T] v, uint start, uint end) -> vec[T] {
    check (start <= end);
    check (end <= len[T](v));
    auto result = alloc[T](end - start);
    let uint i = start;
    while (i < end) {
        result += vec(v.(i));
        i += 1u;
    }
    ret result;
}

fn shift[T](&mutable vec[mutable? T] v) -> T {
    auto ln = len[T](v);
    check(ln > 0u);
    auto e = v.(0);
    v = slice[T](v, 1u, ln);
    ret e;
}

fn pop[T](&mutable vec[mutable? T] v) -> T {
    auto ln = len[T](v);
    check(ln > 0u);
    ln -= 1u;
    auto e = v.(ln);
    v = slice[T](v, 0u, ln);
    ret e;
}

fn push[T](&mutable vec[mutable? T] v, &T t) {
    v += vec(t);
}

fn unshift[T](&mutable vec[mutable? T] v, &T t) {
    auto res = alloc[T](len[T](v) + 1u);
    res += vec(t);
    res += v;
    v = res;
}

fn grow[T](&mutable vec[mutable? T] v, int n, &T initval) {
    let int i = n;
    while (i > 0) {
        i -= 1;
        v += vec(initval);
    }
}

fn map[T, U](&option.operator[T,U] f, &vec[mutable? T] v) -> vec[U] {
    let vec[U] u = alloc[U](len[T](v));
    for (T ve in v) {
        u += vec(f(ve));
    }
    ret u;
}

fn map2[T,U,V](&operator2[T,U,V] f, &vec[mutable? T] v0, &vec[mutable? U] v1)
        -> vec[V] {
    auto v0_len = len[T](v0);
    if (v0_len != len[U](v1)) {
        fail;
    }

    let vec[V] u = alloc[V](v0_len);
    auto i = 0u;
    while (i < v0_len) {
        u += vec(f(v0.(i), v1.(i)));
        i += 1u;
    }

    ret u;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use error::{Error,Result};
use cleaner::{Cleaner, French};
use parser::Parser;
use token::Token;
use epub::EpubRenderer;
use html::HtmlRenderer;
use latex::LatexRenderer;
use templates::{epub,html};

use std::fs::File;
use std::io::{Write,Read};
use std::env;
use std::path::Path;
use std::borrow::Cow;

use mustache;
use mustache::MapBuilder;

// Numbering for a given chapter
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Number {
    Unnumbered, // chapter is not numbered
    Default, // chapter follows books numbering, number is given automatically
    Specified(i32), //chapter number set to specified number
}

// Configuration of the book
#[derive(Debug)]
pub struct Book {
    // Metadata
    pub lang: String,
    pub author: String,
    pub title: String,
    pub description: Option<String>,
    pub subject: Option<String>,
    pub cover: Option<String>,

    // Output files
    pub output_epub: Option<String>,
    pub output_html: Option<String>,
    pub output_pdf: Option<String>,
    pub output_tex: Option<String>,
    pub temp_dir: String,

    // internal structure
    pub chapters: Vec<(Number, Vec<Token>)>,

    // options
    pub numbering: bool, // turns on/off chapter numbering (individual chapters may still avoid it)
    pub autoclean: bool,
    pub nb_char: char,
    pub numbering_template: String, // template for chapter numbering
    pub verbose: bool,

    // for latex
    pub tex_command: String,

    // for epub
    pub epub_css: Option<String>,
    pub epub_template: Option<String>,

    // for HTML
    pub html_template: Option<String>,
    pub html_css: Option<String>,
}

impl Book {
    // Creates a new Book with default options
    pub fn new() -> Book {
        Book {
            verbose: false,
            numbering: true,
            autoclean: true,
            chapters: vec!(),
            lang: String::from("en"),
            author: String::from("Anonymous"),
            title: String::from("Untitled"),
            description: None,
            subject: None,
            cover: None,
            nb_char: ' ',
            numbering_template: String::from("{{number}}. {{title}}"),
            temp_dir: String::from("."),
            output_epub: None,
            output_html: None,
            output_pdf: None,
            output_tex: None,
            tex_command: String::from("pdflatex"),
            epub_css: None,
            epub_template: None,
            html_template: None,
            html_css: None,
        }
    }

    /// Creates a new book from a file
    ///
    /// This method also changes the current directory to the one of this file
    pub fn new_from_file(filename: &str) -> Result<Book> {
        let path = Path::new(filename);
        let mut f = try!(File::open(&path).map_err(|_| Error::FileNotFound(String::from(filename))));

        // change current directory
        if let Some(parent) = path.parent() {
            if !env::set_current_dir(&parent).is_ok() {
                return Err(Error::ConfigParser("could not change current directory to the one of the config file",
                                               format!("{}", parent.display())));
            }
        }

        let mut s = String::new();

        try!(f.read_to_string(&mut s).map_err(|_| Error::ConfigParser("file contains invalid UTF-8, could not parse it",
                                                                      String::from(filename))));
        let mut book = Book::new();
        try!(book.set_from_config(&s));
        Ok(book)
    }

    /// Returns a MapBuilder, to be used (and completed) for templating
    pub fn get_mapbuilder(&self) -> MapBuilder {
        MapBuilder::new()
            .insert_str("author", self.author.clone())
            .insert_str("title", self.title.clone())
            .insert_str("lang", self.lang.clone())
    }

    /// Return a Box<Cleaner> corresponding to the appropriate cleaning method, or None
    pub fn get_cleaner(&self) -> Option<Box<Cleaner>> {
        if self.autoclean {
            let lang = self.lang.to_lowercase();
            if lang.starts_with("fr") {
                Some(Box::new(French::new(self.nb_char)))
            } else {
                Some(Box::new(()))
            }
        } else {
            None
        }
    }

    /// Returns the string corresponding to a number, title, and the numbering template
    pub fn get_header(&self, n: i32, title: &str) -> Result<String> {
        let template = mustache::compile_str(&self.numbering_template);
        let data = MapBuilder::new()
            .insert_str("title", String::from(title))
            .insert_str("number", format!("{}", n))
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("header generated by mustache was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Sets options according to configuration file
    ///
    /// A line with "option: value" sets the option to value
    /// + chapter_name.md adds the (default numbered) chapter
    /// - chapter_name.md adds the (unnumbered) chapter
    /// 3. chapter_name.md adds the (custom numbered) chapter
    pub fn set_from_config(&mut self, s: &str) -> Result<()> {
        fn get_char(s: &str) -> Result<char> {
            let words: Vec<_> = s.trim().split('\'').collect();
            if words.len() != 3 {
                return Err(Error::ConfigParser("could not parse char", String::from(s)));
            }
            let chars: Vec<_> = words[1].chars().collect();
            if chars.len() != 1 {
                return Err(Error::ConfigParser("could not parse char", String::from(s)));
            }
            Ok(chars[0])
        }

        fn get_filename(s: &str) -> Result<&str> {
            let words:Vec<&str> = (&s[1..]).split_whitespace().collect();
            if words.len() > 1 {
                return Err(Error::ConfigParser("chapter filenames must not contain whitespace", String::from(s)));
            } else if words.len() < 1 {
                return Err(Error::ConfigParser("no chapter name specified", String::from(s)));
            }
            Ok(words[0])
        }

        for line in s.lines() {
            let line = line.trim();
            let bool_error = |_| Error::ConfigParser("could not parse bool", String::from(line));
            if line.is_empty() || line.starts_with('#') {
                continue;
            }
            if line.starts_with('-') {
                //unnumbered chapter
                let file = try!(get_filename(line));
                try!(self.add_chapter(Number::Unnumbered, file));
            } else if line.starts_with('+') {
                //nunmbered chapter
                let file = try!(get_filename(line));
                try!(self.add_chapter(Number::Default, file));
            } else if line.starts_with(|c: char| c.is_digit(10)) {
                // chapter with specific number
                let parts:Vec<_> = line.splitn(2, |c: char| c == '.' || c == ':' || c == '+').collect();
                if parts.len() != 2 {
                    return Err(Error::ConfigParser("ill-formatted line specifying chapter number", String::from(line)));
                } else {
                    let file = try!(get_filename(parts[1]));
                    let number = try!(parts[0].parse::<i32>().map_err(|_| Error::ConfigParser("Error parsing integer", String::from(line))));
                    try!(self.add_chapter(Number::Specified(number), file));
                }
            } else {
                // standard case: "option: value"
                let parts:Vec<_> = line.splitn(2, ':').collect();
                if parts.len() != 2 {
                    return Err(Error::ConfigParser("option setting must be of the form option: value", String::from(line)));
                }
                let option = parts[0].trim();
                let value = parts[1].trim();
                match option {
                    "nb-char" | "nb_char" => self.nb_char = try!(get_char(value)),
                    "numbering-template" | "numbering_template" => self.numbering_template = String::from(value),
                    "verbose" => self.verbose = try!(value.parse::<bool>().map_err(bool_error)),
                    "numbering" => self.numbering = try!(value.parse::<bool>().map_err(bool_error)),
                    "autoclean" => self.autoclean = try!(value.parse::<bool>().map_err(bool_error)),
                    "temp_dir" | "temp-dir" => self.temp_dir = String::from(value),
                    "output_epub" | "output-epub" => self.output_epub = Some(String::from(value)),
                    "output_html" | "output-html" => self.output_html = Some(String::from(value)),
                    "output_tex" | "output-tex" => self.output_tex = Some(String::from(value)),
                    "output_pdf" | "output-pdf" => self.output_pdf = Some(String::from(value)),
                    "tex_command" | "tex-command" => self.tex_command = String::from(value),
                    "author" => self.author = String::from(value),
                    "title" => self.title = String::from(value),
                    "cover" => self.cover = Some(String::from(value)),
                    "lang" => self.lang = String::from(value),
                    "description" => self.description = Some(String::from(value)),
                    "subject" => self.subject = Some(String::from(value)),
                    "epub_css" | "epub-css" => self.epub_css = Some(String::from(value)),
                    "epub_template" | "epub-template" => self.epub_template = Some(String::from(value)),
                    "html_template" | "html-template" => self.html_template = Some(String::from(value)),
                    "html_css" | "html-css" => self.html_css = Some(String::from(value)),
                    _ => return Err(Error::ConfigParser("unrecognized option", String::from(line))),
                }
            }
        }

        Ok(())
    }

    /// Generates output files acccording to book options
    pub fn render_all(&self) -> Result<()> {
        let mut did_some_stuff = false;
        if let Some(ref file) = self.output_epub {
            did_some_stuff = true;
            if self.verbose {
                println!("Attempting to generate epub...");
            }
            let mut epub = EpubRenderer::new(&self);
            let result = try!(epub.render_book());
            if self.verbose {
                println!("{}", result);
            }
            println!("Successfully generated epub file: {}", file);
        }
        if let Some(ref file) = self.output_html {
            did_some_stuff = true;
            if self.verbose {
                println!("Attempting to generate HTML...");
            }
            let mut html = HtmlRenderer::new(&self);
            let result = try!(html.render_book());
            let mut f = try!(File::create(file).map_err(|_| Error::Render("could not create HTML file")));
            try!(f.write_all(&result.as_bytes()).map_err(|_| Error::Render("problem when writing to HTML file")));
            println!("Successfully generated HTML file: {}", file);
        }
        if let Some(ref file) = self.output_tex {
            did_some_stuff = true;
            if self.verbose {
                println!("Attempting to generate LaTeX...");
            }
            let mut latex = LatexRenderer::new(&self);
            let result = try!(latex.render_book());
            let mut f = try!(File::create(file).map_err(|_| Error::Render("could not create LaTeX file")));
            try!(f.write_all(&result.as_bytes()).map_err(|_| Error::Render("problem when writing to LaTeX file")));
            println!("Successfully generated LaTeX file: {}", file);
        }
        if let Some(ref file) = self.output_pdf {
            did_some_stuff = true;
            if self.verbose {
                println!("Attempting to generate pdf...");
            }
            let mut latex = LatexRenderer::new(&self);
            let result = try!(latex.render_pdf());
            if self.verbose {
                println!("{}", result);
            }
            println!("Successfully generated pdf file: {}", file);
        }
        if !did_some_stuff {
            println!("Warning: generated no file because no output file speficied. Add output_{{format}} to your config file.");
        }
        Ok(())
    }

    /// File: location of the file for this chapter
    pub fn add_chapter(&mut self, number: Number, file: &str) -> Result<()> {
        let mut parser = Parser::new();
        if let Some(cleaner) = self.get_cleaner() {
            parser = parser.with_cleaner(cleaner)
        }
        let v = try!(parser.parse_file(file));
        self.chapters.push((number, v));
        Ok(())
    }

    /// Returns the template (default or modified version)
    pub fn get_template(&self, template: &str) -> Result<Cow<'static, str>> {
        let (option, fallback) = match template {
            "epub_css" => (&self.epub_css, epub::CSS),
            "epub_template" => (&self.epub_template, epub::TEMPLATE),
            "html_css" => (&self.html_css, html::CSS),
            "html_template" => (&self.html_template, html::TEMPLATE),
            _ => return Err(Error::ConfigParser("invalid template", template.to_owned())),
        };
        if let Some (ref s) = *option {
            let mut f = try!(File::open(s).map_err(|_| Error::FileNotFound(s.to_owned())));
            let mut res = String::new();
            try!(f.read_to_string(&mut res)
                 .map_err(|_| Error::ConfigParser("file could not be read", s.to_owned())));
            Ok(Cow::Owned(res))
        } else {
            Ok(Cow::Borrowed(fallback))
        }
    }
}
<commit_msg>fixed a bug which caused error when crowbook runned on book in same directory<commit_after>use error::{Error,Result};
use cleaner::{Cleaner, French};
use parser::Parser;
use token::Token;
use epub::EpubRenderer;
use html::HtmlRenderer;
use latex::LatexRenderer;
use templates::{epub,html};

use std::fs::File;
use std::io::{Write,Read};
use std::env;
use std::path::Path;
use std::borrow::Cow;

use mustache;
use mustache::MapBuilder;

// Numbering for a given chapter
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Number {
    Unnumbered, // chapter is not numbered
    Default, // chapter follows books numbering, number is given automatically
    Specified(i32), //chapter number set to specified number
}

// Configuration of the book
#[derive(Debug)]
pub struct Book {
    // Metadata
    pub lang: String,
    pub author: String,
    pub title: String,
    pub description: Option<String>,
    pub subject: Option<String>,
    pub cover: Option<String>,

    // Output files
    pub output_epub: Option<String>,
    pub output_html: Option<String>,
    pub output_pdf: Option<String>,
    pub output_tex: Option<String>,
    pub temp_dir: String,

    // internal structure
    pub chapters: Vec<(Number, Vec<Token>)>,

    // options
    pub numbering: bool, // turns on/off chapter numbering (individual chapters may still avoid it)
    pub autoclean: bool,
    pub nb_char: char,
    pub numbering_template: String, // template for chapter numbering
    pub verbose: bool,

    // for latex
    pub tex_command: String,

    // for epub
    pub epub_css: Option<String>,
    pub epub_template: Option<String>,

    // for HTML
    pub html_template: Option<String>,
    pub html_css: Option<String>,
}

impl Book {
    // Creates a new Book with default options
    pub fn new() -> Book {
        Book {
            verbose: false,
            numbering: true,
            autoclean: true,
            chapters: vec!(),
            lang: String::from("en"),
            author: String::from("Anonymous"),
            title: String::from("Untitled"),
            description: None,
            subject: None,
            cover: None,
            nb_char: ' ',
            numbering_template: String::from("{{number}}. {{title}}"),
            temp_dir: String::from("."),
            output_epub: None,
            output_html: None,
            output_pdf: None,
            output_tex: None,
            tex_command: String::from("pdflatex"),
            epub_css: None,
            epub_template: None,
            html_template: None,
            html_css: None,
        }
    }

    /// Creates a new book from a file
    ///
    /// This method also changes the current directory to the one of this file
    pub fn new_from_file(filename: &str) -> Result<Book> {
        let path = Path::new(filename);
        let mut f = try!(File::open(&path).map_err(|_| Error::FileNotFound(String::from(filename))));

        // change current directory
        if let Some(parent) = path.parent() {
            if !parent.to_string_lossy().is_empty() {
                if !env::set_current_dir(&parent).is_ok() {
                    return Err(Error::ConfigParser("could not change current directory to the one of the config file",
                                                   format!("{}", parent.display())));
                }
            }
        }

        let mut s = String::new();

        try!(f.read_to_string(&mut s).map_err(|_| Error::ConfigParser("file contains invalid UTF-8, could not parse it",
                                                                      String::from(filename))));
        let mut book = Book::new();
        try!(book.set_from_config(&s));
        Ok(book)
    }

    /// Returns a MapBuilder, to be used (and completed) for templating
    pub fn get_mapbuilder(&self) -> MapBuilder {
        MapBuilder::new()
            .insert_str("author", self.author.clone())
            .insert_str("title", self.title.clone())
            .insert_str("lang", self.lang.clone())
    }

    /// Return a Box<Cleaner> corresponding to the appropriate cleaning method, or None
    pub fn get_cleaner(&self) -> Option<Box<Cleaner>> {
        if self.autoclean {
            let lang = self.lang.to_lowercase();
            if lang.starts_with("fr") {
                Some(Box::new(French::new(self.nb_char)))
            } else {
                Some(Box::new(()))
            }
        } else {
            None
        }
    }

    /// Returns the string corresponding to a number, title, and the numbering template
    pub fn get_header(&self, n: i32, title: &str) -> Result<String> {
        let template = mustache::compile_str(&self.numbering_template);
        let data = MapBuilder::new()
            .insert_str("title", String::from(title))
            .insert_str("number", format!("{}", n))
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("header generated by mustache was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Sets options according to configuration file
    ///
    /// A line with "option: value" sets the option to value
    /// + chapter_name.md adds the (default numbered) chapter
    /// - chapter_name.md adds the (unnumbered) chapter
    /// 3. chapter_name.md adds the (custom numbered) chapter
    pub fn set_from_config(&mut self, s: &str) -> Result<()> {
        fn get_char(s: &str) -> Result<char> {
            let words: Vec<_> = s.trim().split('\'').collect();
            if words.len() != 3 {
                return Err(Error::ConfigParser("could not parse char", String::from(s)));
            }
            let chars: Vec<_> = words[1].chars().collect();
            if chars.len() != 1 {
                return Err(Error::ConfigParser("could not parse char", String::from(s)));
            }
            Ok(chars[0])
        }

        fn get_filename(s: &str) -> Result<&str> {
            let words:Vec<&str> = (&s[1..]).split_whitespace().collect();
            if words.len() > 1 {
                return Err(Error::ConfigParser("chapter filenames must not contain whitespace", String::from(s)));
            } else if words.len() < 1 {
                return Err(Error::ConfigParser("no chapter name specified", String::from(s)));
            }
            Ok(words[0])
        }

        for line in s.lines() {
            let line = line.trim();
            let bool_error = |_| Error::ConfigParser("could not parse bool", String::from(line));
            if line.is_empty() || line.starts_with('#') {
                continue;
            }
            if line.starts_with('-') {
                //unnumbered chapter
                let file = try!(get_filename(line));
                try!(self.add_chapter(Number::Unnumbered, file));
            } else if line.starts_with('+') {
                //nunmbered chapter
                let file = try!(get_filename(line));
                try!(self.add_chapter(Number::Default, file));
            } else if line.starts_with(|c: char| c.is_digit(10)) {
                // chapter with specific number
                let parts:Vec<_> = line.splitn(2, |c: char| c == '.' || c == ':' || c == '+').collect();
                if parts.len() != 2 {
                    return Err(Error::ConfigParser("ill-formatted line specifying chapter number", String::from(line)));
                } else {
                    let file = try!(get_filename(parts[1]));
                    let number = try!(parts[0].parse::<i32>().map_err(|_| Error::ConfigParser("Error parsing integer", String::from(line))));
                    try!(self.add_chapter(Number::Specified(number), file));
                }
            } else {
                // standard case: "option: value"
                let parts:Vec<_> = line.splitn(2, ':').collect();
                if parts.len() != 2 {
                    return Err(Error::ConfigParser("option setting must be of the form option: value", String::from(line)));
                }
                let option = parts[0].trim();
                let value = parts[1].trim();
                match option {
                    "nb-char" | "nb_char" => self.nb_char = try!(get_char(value)),
                    "numbering-template" | "numbering_template" => self.numbering_template = String::from(value),
                    "verbose" => self.verbose = try!(value.parse::<bool>().map_err(bool_error)),
                    "numbering" => self.numbering = try!(value.parse::<bool>().map_err(bool_error)),
                    "autoclean" => self.autoclean = try!(value.parse::<bool>().map_err(bool_error)),
                    "temp_dir" | "temp-dir" => self.temp_dir = String::from(value),
                    "output_epub" | "output-epub" => self.output_epub = Some(String::from(value)),
                    "output_html" | "output-html" => self.output_html = Some(String::from(value)),
                    "output_tex" | "output-tex" => self.output_tex = Some(String::from(value)),
                    "output_pdf" | "output-pdf" => self.output_pdf = Some(String::from(value)),
                    "tex_command" | "tex-command" => self.tex_command = String::from(value),
                    "author" => self.author = String::from(value),
                    "title" => self.title = String::from(value),
                    "cover" => self.cover = Some(String::from(value)),
                    "lang" => self.lang = String::from(value),
                    "description" => self.description = Some(String::from(value)),
                    "subject" => self.subject = Some(String::from(value)),
                    "epub_css" | "epub-css" => self.epub_css = Some(String::from(value)),
                    "epub_template" | "epub-template" => self.epub_template = Some(String::from(value)),
                    "html_template" | "html-template" => self.html_template = Some(String::from(value)),
                    "html_css" | "html-css" => self.html_css = Some(String::from(value)),
                    _ => return Err(Error::ConfigParser("unrecognized option", String::from(line))),
                }
            }
        }

        Ok(())
    }

    /// Generates output files acccording to book options
    pub fn render_all(&self) -> Result<()> {
        let mut did_some_stuff = false;
        if let Some(ref file) = self.output_epub {
            did_some_stuff = true;
            if self.verbose {
                println!("Attempting to generate epub...");
            }
            let mut epub = EpubRenderer::new(&self);
            let result = try!(epub.render_book());
            if self.verbose {
                println!("{}", result);
            }
            println!("Successfully generated epub file: {}", file);
        }
        if let Some(ref file) = self.output_html {
            did_some_stuff = true;
            if self.verbose {
                println!("Attempting to generate HTML...");
            }
            let mut html = HtmlRenderer::new(&self);
            let result = try!(html.render_book());
            let mut f = try!(File::create(file).map_err(|_| Error::Render("could not create HTML file")));
            try!(f.write_all(&result.as_bytes()).map_err(|_| Error::Render("problem when writing to HTML file")));
            println!("Successfully generated HTML file: {}", file);
        }
        if let Some(ref file) = self.output_tex {
            did_some_stuff = true;
            if self.verbose {
                println!("Attempting to generate LaTeX...");
            }
            let mut latex = LatexRenderer::new(&self);
            let result = try!(latex.render_book());
            let mut f = try!(File::create(file).map_err(|_| Error::Render("could not create LaTeX file")));
            try!(f.write_all(&result.as_bytes()).map_err(|_| Error::Render("problem when writing to LaTeX file")));
            println!("Successfully generated LaTeX file: {}", file);
        }
        if let Some(ref file) = self.output_pdf {
            did_some_stuff = true;
            if self.verbose {
                println!("Attempting to generate pdf...");
            }
            let mut latex = LatexRenderer::new(&self);
            let result = try!(latex.render_pdf());
            if self.verbose {
                println!("{}", result);
            }
            println!("Successfully generated pdf file: {}", file);
        }
        if !did_some_stuff {
            println!("Warning: generated no file because no output file speficied. Add output_{{format}} to your config file.");
        }
        Ok(())
    }

    /// File: location of the file for this chapter
    pub fn add_chapter(&mut self, number: Number, file: &str) -> Result<()> {
        let mut parser = Parser::new();
        if let Some(cleaner) = self.get_cleaner() {
            parser = parser.with_cleaner(cleaner)
        }
        let v = try!(parser.parse_file(file));
        self.chapters.push((number, v));
        Ok(())
    }

    /// Returns the template (default or modified version)
    pub fn get_template(&self, template: &str) -> Result<Cow<'static, str>> {
        let (option, fallback) = match template {
            "epub_css" => (&self.epub_css, epub::CSS),
            "epub_template" => (&self.epub_template, epub::TEMPLATE),
            "html_css" => (&self.html_css, html::CSS),
            "html_template" => (&self.html_template, html::TEMPLATE),
            _ => return Err(Error::ConfigParser("invalid template", template.to_owned())),
        };
        if let Some (ref s) = *option {
            let mut f = try!(File::open(s).map_err(|_| Error::FileNotFound(s.to_owned())));
            let mut res = String::new();
            try!(f.read_to_string(&mut res)
                 .map_err(|_| Error::ConfigParser("file could not be read", s.to_owned())));
            Ok(Cow::Owned(res))
        } else {
            Ok(Cow::Borrowed(fallback))
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "servo"]
#![comment = "The Servo Parallel Browser Project"]
#![license = "MPL"]

#![feature(globs, macro_rules, phase, thread_local)]

#[phase(plugin, link)]
extern crate log;

extern crate debug;

extern crate compositing;
extern crate rustuv;
extern crate servo_net = "net";
extern crate servo_msg = "msg";
#[phase(plugin, link)]
extern crate servo_util = "util";
extern crate script;
extern crate layout;
extern crate green;
extern crate gfx;
extern crate libc;
extern crate native;
extern crate rustrt;
extern crate url = "url_";

#[cfg(not(test))]
use compositing::{CompositorChan, CompositorTask, Constellation};
#[cfg(not(test))]
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg};
#[cfg(not(test))]
use script::dom::bindings::codegen::RegisterBindings;

#[cfg(not(test))]
use servo_net::image_cache_task::ImageCacheTask;
#[cfg(not(test))]
use servo_net::resource_task::new_resource_task;
#[cfg(not(test))]
use gfx::font_cache_task::FontCacheTask;
#[cfg(not(test))]
use servo_util::time::TimeProfiler;
#[cfg(not(test))]
use servo_util::memory::MemoryProfiler;

#[cfg(not(test))]
use servo_util::opts;

#[cfg(not(test))]
use url::{Url, UrlParser};

#[cfg(not(test))]
use std::os;
#[cfg(not(test), target_os="android")]
use std::str;
#[cfg(not(test))]
use rustrt::task::TaskOpts;

#[cfg(not(test), target_os="linux")]
#[cfg(not(test), target_os="macos")]
#[start]
#[allow(dead_code)]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, proc() {
        opts::from_cmdline_args(os::args().as_slice()).map(run);
    })
}

#[cfg(not(test), target_os="android")]
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn android_start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, proc() {
        let mut args: Vec<String> = vec!();
        for i in range(0u, argc as uint) {
            unsafe {
                args.push(str::raw::from_c_str(*argv.offset(i as int) as *const i8));
            }
        }

        let opts = opts::from_cmdline_args(args.as_slice());
        match opts {
            Some(mut o) => {
                // Always use CPU rendering on android.
                o.cpu_painting = true;
                run(o);
            },
            None => {}
        }
    })
}

#[cfg(not(test))]
pub fn run(opts: opts::Opts) {
    ::servo_util::opts::set_experimental_enabled(opts.enable_experimental);
    RegisterBindings::RegisterProxyHandlers();

    let mut pool_config = green::PoolConfig::new();
    pool_config.event_loop_factory = rustuv::event_loop;
    let mut pool = green::SchedPool::new(pool_config);

    let (compositor_port, compositor_chan) = CompositorChan::new();
    let time_profiler_chan = TimeProfiler::create(opts.time_profiler_period);
    let memory_profiler_chan = MemoryProfiler::create(opts.memory_profiler_period);

    let opts_clone = opts.clone();
    let time_profiler_chan_clone = time_profiler_chan.clone();

    let (result_chan, result_port) = channel();
    pool.spawn(TaskOpts::new(), proc() {
        let opts = &opts_clone;
        // Create a Servo instance.
        let resource_task = new_resource_task();
        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task = if opts.output_file.is_some() {
                ImageCacheTask::new_sync(resource_task.clone())
            } else {
                ImageCacheTask::new(resource_task.clone())
            };
        let font_cache_task = FontCacheTask::new();
        let constellation_chan = Constellation::<layout::layout_task::LayoutTask>::start(
                                                      compositor_chan,
                                                      opts,
                                                      resource_task,
                                                      image_cache_task,
                                                      font_cache_task,
                                                      time_profiler_chan_clone);

        let base_url = Url::from_directory_path(&os::getcwd()).unwrap();
        let mut url_parser = UrlParser::new();
        let url_parser = url_parser.base_url(&base_url);
        // Send the URL command to the constellation.
        for url in opts.urls.iter() {
            let url = url_parser.parse(url.as_slice()).ok().expect("URL parsing failed");

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(InitLoadUrlMsg(url));
        }

        // Send the constallation Chan as the result
        result_chan.send(constellation_chan);
    });

    let constellation_chan = result_port.recv();

    debug!("preparing to enter main loop");
    CompositorTask::create(opts,
                           compositor_port,
                           constellation_chan,
                           time_profiler_chan,
                           memory_profiler_chan);

    pool.shutdown();
}

<commit_msg>Use TaskBuilder for the main Servo task.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "servo"]
#![comment = "The Servo Parallel Browser Project"]
#![license = "MPL"]

#![feature(globs, macro_rules, phase, thread_local)]

#[phase(plugin, link)]
extern crate log;

extern crate debug;

extern crate compositing;
extern crate rustuv;
extern crate servo_net = "net";
extern crate servo_msg = "msg";
#[phase(plugin, link)]
extern crate servo_util = "util";
extern crate script;
extern crate layout;
extern crate green;
extern crate gfx;
extern crate libc;
extern crate native;
extern crate rustrt;
extern crate url = "url_";

#[cfg(not(test))]
use compositing::{CompositorChan, CompositorTask, Constellation};
#[cfg(not(test))]
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg};
#[cfg(not(test))]
use script::dom::bindings::codegen::RegisterBindings;

#[cfg(not(test))]
use servo_net::image_cache_task::ImageCacheTask;
#[cfg(not(test))]
use servo_net::resource_task::new_resource_task;
#[cfg(not(test))]
use gfx::font_cache_task::FontCacheTask;
#[cfg(not(test))]
use servo_util::time::TimeProfiler;
#[cfg(not(test))]
use servo_util::memory::MemoryProfiler;
#[cfg(not(test))]
use servo_util::opts;

#[cfg(not(test))]
use green::GreenTaskBuilder;
#[cfg(not(test))]
use std::os;
#[cfg(not(test))]
use std::task::TaskBuilder;
#[cfg(not(test), target_os="android")]
use std::str;
#[cfg(not(test))]
use url::{Url, UrlParser};

#[cfg(not(test), target_os="linux")]
#[cfg(not(test), target_os="macos")]
#[start]
#[allow(dead_code)]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, proc() {
        opts::from_cmdline_args(os::args().as_slice()).map(run);
    })
}

#[cfg(not(test), target_os="android")]
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn android_start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, proc() {
        let mut args: Vec<String> = vec!();
        for i in range(0u, argc as uint) {
            unsafe {
                args.push(str::raw::from_c_str(*argv.offset(i as int) as *const i8));
            }
        }

        let opts = opts::from_cmdline_args(args.as_slice());
        match opts {
            Some(mut o) => {
                // Always use CPU rendering on android.
                o.cpu_painting = true;
                run(o);
            },
            None => {}
        }
    })
}

#[cfg(not(test))]
pub fn run(opts: opts::Opts) {
    ::servo_util::opts::set_experimental_enabled(opts.enable_experimental);
    RegisterBindings::RegisterProxyHandlers();

    let mut pool_config = green::PoolConfig::new();
    pool_config.event_loop_factory = rustuv::event_loop;
    let mut pool = green::SchedPool::new(pool_config);

    let (compositor_port, compositor_chan) = CompositorChan::new();
    let time_profiler_chan = TimeProfiler::create(opts.time_profiler_period);
    let memory_profiler_chan = MemoryProfiler::create(opts.memory_profiler_period);

    let opts_clone = opts.clone();
    let time_profiler_chan_clone = time_profiler_chan.clone();

    let (result_chan, result_port) = channel();
    TaskBuilder::new()
        .green(&mut pool)
        .spawn(proc() {
        let opts = &opts_clone;
        // Create a Servo instance.
        let resource_task = new_resource_task();
        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task = if opts.output_file.is_some() {
                ImageCacheTask::new_sync(resource_task.clone())
            } else {
                ImageCacheTask::new(resource_task.clone())
            };
        let font_cache_task = FontCacheTask::new();
        let constellation_chan = Constellation::<layout::layout_task::LayoutTask>::start(
                                                      compositor_chan,
                                                      opts,
                                                      resource_task,
                                                      image_cache_task,
                                                      font_cache_task,
                                                      time_profiler_chan_clone);

        let base_url = Url::from_directory_path(&os::getcwd()).unwrap();
        let mut url_parser = UrlParser::new();
        let url_parser = url_parser.base_url(&base_url);
        // Send the URL command to the constellation.
        for url in opts.urls.iter() {
            let url = url_parser.parse(url.as_slice()).ok().expect("URL parsing failed");

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(InitLoadUrlMsg(url));
        }

        // Send the constallation Chan as the result
        result_chan.send(constellation_chan);
    });

    let constellation_chan = result_port.recv();

    debug!("preparing to enter main loop");
    CompositorTask::create(opts,
                           compositor_port,
                           constellation_chan,
                           time_profiler_chan,
                           memory_profiler_chan);

    pool.shutdown();
}

<|endoftext|>


<commit_before>//! The Mach-o, mostly zero-copy, binary format parser and raw struct definitions
use core::fmt;

use scroll::{self, Pread};

use error;
use container;

pub mod header;
pub mod constants;
pub mod fat;
pub mod load_command;
pub mod symbols;
pub mod exports;
pub mod imports;
pub mod bind_opcodes;

pub use self::constants::cputype as cputype;

/// Returns a big endian magical number
pub fn peek<B: AsRef<[u8]>>(bytes: B, offset: usize) -> error::Result<u32> {
    Ok(bytes.pread_with::<u32>(offset, scroll::BE)?)
}

#[derive(Debug)]
/// A cross-platform, zero-copy, endian-aware, 32/64 bit Mach-o binary parser
pub struct MachO<'a> {
    pub header: header::Header,
    pub load_commands: Vec<load_command::LoadCommand>,
    pub segments: load_command::Segments<'a>,
    pub symbols: Option<symbols::Symbols<'a>>,
    pub libs: Vec<&'a str>,
    pub entry: u64,
    pub name: Option<&'a str>,
    pub little_endian: bool,
    pub is_64: bool,
    ctx: container::Ctx,
    export_trie: Option<exports::ExportTrie<'a>>,
    bind_interpreter: Option<imports::BindInterpreter<'a>>,
}

impl<'a> MachO<'a> {
    /// Return the exported symbols in this binary (if any)
    pub fn exports(&self) -> error::Result<Vec<exports::Export>> {
        if let Some(ref trie) = self.export_trie {
            trie.exports(self.libs.as_slice())
        } else {
            Ok(vec![])
        }
    }
    /// Return the imported symbols in this binary that dyld knows about (if any)
    pub fn imports(&self) -> error::Result<Vec<imports::Import>> {
        if let Some(ref interpreter) = self.bind_interpreter {
            interpreter.imports(self.libs.as_slice(), self.segments.as_slice(), &self.ctx)
        } else {
            Ok(vec![])
        }
    }
    /// Parses the Mach-o binary from `bytes` at `offset`
    pub fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<MachO<'a>> {
        let offset = &mut offset;
        let header: header::Header = bytes.pread(*offset)?;
        let ctx = header.ctx()?;
        let little_endian = ctx.le.is_little();
        let is_64 = ctx.container.is_big();
        *offset = *offset + header.size();
        let ncmds = header.ncmds;
        let mut cmds: Vec<load_command::LoadCommand> = Vec::with_capacity(ncmds);
        let mut symbols = None;
        let mut libs = vec!["self"];
        let mut export_trie = None;
        let mut bind_interpreter = None;
        let mut entry = 0x0;
        let mut name = None;
        let mut segments = load_command::Segments::new(ctx);
        for _ in 0..ncmds {
            let cmd = load_command::LoadCommand::parse(bytes, offset, ctx.le)?;
            match cmd.command {
                load_command::CommandVariant::Segment32(command) => {
                    segments.push(load_command::Segment::from_32(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Segment64(command) => {
                    segments.push(load_command::Segment::from_64(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Symtab(command) => {
                    symbols = Some(symbols::Symbols::parse(bytes, &command, ctx)?);
                },
                  load_command::CommandVariant::LoadDylib      (command)
                | load_command::CommandVariant::LoadUpwardDylib(command)
                | load_command::CommandVariant::ReexportDylib  (command)
                | load_command::CommandVariant::LazyLoadDylib  (command) => {
                    let lib = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs.push(lib);
                },
                  load_command::CommandVariant::DyldInfo    (command)
                | load_command::CommandVariant::DyldInfoOnly(command) => {
                    export_trie = Some(exports::ExportTrie::new(bytes, &command));
                    bind_interpreter = Some(imports::BindInterpreter::new(bytes, &command));
                },
                load_command::CommandVariant::Unixthread(command) => {
                    entry = command.thread_state.eip as u64;
                },
                load_command::CommandVariant::Main(command) => {
                    entry = command.entryoff;
                },
                load_command::CommandVariant::IdDylib(command) => {
                    let id = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs[0] = id;
                    name = Some(id);
                },
                _ => ()
            }
            cmds.push(cmd)
        }
        Ok(MachO {
            header: header,
            load_commands: cmds,
            segments: segments,
            symbols: symbols,
            libs: libs,
            export_trie: export_trie,
            bind_interpreter: bind_interpreter,
            entry: entry,
            name: name,
            ctx: ctx,
            is_64: is_64,
            little_endian: little_endian,
        })
    }
}

#[cfg(feature = "std")]
/// A Mach-o multi architecture (Fat) binary container
pub struct MultiArch<'a> {
    data: &'a [u8],
    start: usize,
    pub narches: usize,
}

/// Iterator over the fat architecture headers in a `MultiArch` container
pub struct FatArchIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for FatArchIterator<'a> {
    type Item = scroll::Result<fat::FatArch>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let offset = (self.index * fat::SIZEOF_FAT_ARCH) + self.start;
            let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE);
            self.index += 1;
            Some(arch)
        }
    }
}

impl<'a, 'b> IntoIterator for &'b MultiArch<'a> {
    type Item = scroll::Result<fat::FatArch>;
    type IntoIter = FatArchIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        FatArchIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
}

#[cfg(feature = "std")]
impl<'a> MultiArch<'a> {
    /// Lazily construct `Self`
    pub fn new(bytes: &'a [u8]) -> error::Result<Self> {
        let header = fat::FatHeader::parse(bytes)?;
        Ok(MultiArch {
            data: bytes,
            start: fat::SIZEOF_FAT_HEADER,
            narches: header.nfat_arch as usize
        })
    }
    /// Return all the architectures in this binary
    pub fn arches(&self) -> error::Result<Vec<fat::FatArch>> {
        let mut arches = Vec::with_capacity(self.narches);
        for arch in self.into_iter() {
            arches.push(arch?);
        }
        Ok(arches)
    }
    /// Try to get the Mach-o binary at `index`
    pub fn get(&self, index: usize) -> error::Result<MachO> {
        if index >= self.narches {
            return Err(error::Error::Malformed(format!("Requested the {}-th binary, but there are only {} architectures in this container", index, self.narches).into()))
        }
        let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
        let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE)?;
        let bytes = arch.slice(self.data);
        Ok(MachO::parse(bytes, 0)?)
    }

    /// Try and find the `cputype` in `Self`, if there is one
    pub fn find_cputype(&self, cputype: u32) -> error::Result<Option<fat::FatArch>> {
        for arch in self.into_iter() {
            let arch = arch?;
            if arch.cputype == cputype { return Ok(Some(arch)) }
        }
        Ok(None)
    }
}

#[cfg(feature = "std")]
impl<'a> fmt::Debug for MultiArch<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("MultiArch")
            .field("arches",  &self.arches().unwrap())
            .field("data",    &self.data.len())
            .finish()
    }
}

#[derive(Debug)]
/// Either a collection of multiple architectures, or a single mach-o binary
pub enum Mach<'a> {
    Fat(MultiArch<'a>),
    Binary(MachO<'a>)
}

impl<'a> Mach<'a> {
    pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
        let size = bytes.len();
        if size < 4 {
            let error = error::Error::Malformed(
                                       format!("size is smaller than a magical number"));
            return Err(error);
        }
        let magic = peek(&bytes, 0)?;
        match magic {
            fat::FAT_MAGIC => {
                let multi = MultiArch::new(bytes)?;
                Ok(Mach::Fat(multi))
            },
            // we're a regular binary
            _ => {
                let binary = MachO::parse(bytes, 0)?;
                Ok(Mach::Binary(binary))
            }
        }
    }
}
<commit_msg>mach: add some docs<commit_after>//! The Mach-o, mostly zero-copy, binary format parser and raw struct definitions
use core::fmt;

use scroll::{self, Pread};

use error;
use container;

pub mod header;
pub mod constants;
pub mod fat;
pub mod load_command;
pub mod symbols;
pub mod exports;
pub mod imports;
pub mod bind_opcodes;

pub use self::constants::cputype as cputype;

/// Returns a big endian magical number
pub fn peek<B: AsRef<[u8]>>(bytes: B, offset: usize) -> error::Result<u32> {
    Ok(bytes.pread_with::<u32>(offset, scroll::BE)?)
}

#[derive(Debug)]
/// A cross-platform, zero-copy, endian-aware, 32/64 bit Mach-o binary parser
pub struct MachO<'a> {
    /// The mach-o header
    pub header: header::Header,
    /// The load commands tell the kernel and dynamic linker how to use/interpret this binary
    pub load_commands: Vec<load_command::LoadCommand>,
    /// The load command "segments" - typically the pieces of the binary that are loaded into memory
    pub segments: load_command::Segments<'a>,
    /// The Nlist style symbols in this binary - strippable
    pub symbols: Option<symbols::Symbols<'a>>,
    /// The dylibs this library depends on
    pub libs: Vec<&'a str>,
    /// The entry point, 0 if none
    pub entry: u64,
    /// The name of the dylib, if any
    pub name: Option<&'a str>,
    /// Are we a little-endian binary?
    pub little_endian: bool,
    /// Are we a 64-bit binary
    pub is_64: bool,
    ctx: container::Ctx,
    export_trie: Option<exports::ExportTrie<'a>>,
    bind_interpreter: Option<imports::BindInterpreter<'a>>,
}

impl<'a> MachO<'a> {
    /// Return the exported symbols in this binary (if any)
    pub fn exports(&self) -> error::Result<Vec<exports::Export>> {
        if let Some(ref trie) = self.export_trie {
            trie.exports(self.libs.as_slice())
        } else {
            Ok(vec![])
        }
    }
    /// Return the imported symbols in this binary that dyld knows about (if any)
    pub fn imports(&self) -> error::Result<Vec<imports::Import>> {
        if let Some(ref interpreter) = self.bind_interpreter {
            interpreter.imports(self.libs.as_slice(), self.segments.as_slice(), &self.ctx)
        } else {
            Ok(vec![])
        }
    }
    /// Parses the Mach-o binary from `bytes` at `offset`
    pub fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<MachO<'a>> {
        let offset = &mut offset;
        let header: header::Header = bytes.pread(*offset)?;
        let ctx = header.ctx()?;
        let little_endian = ctx.le.is_little();
        let is_64 = ctx.container.is_big();
        *offset = *offset + header.size();
        let ncmds = header.ncmds;
        let mut cmds: Vec<load_command::LoadCommand> = Vec::with_capacity(ncmds);
        let mut symbols = None;
        let mut libs = vec!["self"];
        let mut export_trie = None;
        let mut bind_interpreter = None;
        let mut entry = 0x0;
        let mut name = None;
        let mut segments = load_command::Segments::new(ctx);
        for _ in 0..ncmds {
            let cmd = load_command::LoadCommand::parse(bytes, offset, ctx.le)?;
            match cmd.command {
                load_command::CommandVariant::Segment32(command) => {
                    segments.push(load_command::Segment::from_32(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Segment64(command) => {
                    segments.push(load_command::Segment::from_64(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Symtab(command) => {
                    symbols = Some(symbols::Symbols::parse(bytes, &command, ctx)?);
                },
                  load_command::CommandVariant::LoadDylib      (command)
                | load_command::CommandVariant::LoadUpwardDylib(command)
                | load_command::CommandVariant::ReexportDylib  (command)
                | load_command::CommandVariant::LazyLoadDylib  (command) => {
                    let lib = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs.push(lib);
                },
                  load_command::CommandVariant::DyldInfo    (command)
                | load_command::CommandVariant::DyldInfoOnly(command) => {
                    export_trie = Some(exports::ExportTrie::new(bytes, &command));
                    bind_interpreter = Some(imports::BindInterpreter::new(bytes, &command));
                },
                load_command::CommandVariant::Unixthread(command) => {
                    entry = command.thread_state.eip as u64;
                },
                load_command::CommandVariant::Main(command) => {
                    entry = command.entryoff;
                },
                load_command::CommandVariant::IdDylib(command) => {
                    let id = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs[0] = id;
                    name = Some(id);
                },
                _ => ()
            }
            cmds.push(cmd)
        }
        Ok(MachO {
            header: header,
            load_commands: cmds,
            segments: segments,
            symbols: symbols,
            libs: libs,
            export_trie: export_trie,
            bind_interpreter: bind_interpreter,
            entry: entry,
            name: name,
            ctx: ctx,
            is_64: is_64,
            little_endian: little_endian,
        })
    }
}

#[cfg(feature = "std")]
/// A Mach-o multi architecture (Fat) binary container
pub struct MultiArch<'a> {
    data: &'a [u8],
    start: usize,
    pub narches: usize,
}

/// Iterator over the fat architecture headers in a `MultiArch` container
pub struct FatArchIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for FatArchIterator<'a> {
    type Item = scroll::Result<fat::FatArch>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let offset = (self.index * fat::SIZEOF_FAT_ARCH) + self.start;
            let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE);
            self.index += 1;
            Some(arch)
        }
    }
}

impl<'a, 'b> IntoIterator for &'b MultiArch<'a> {
    type Item = scroll::Result<fat::FatArch>;
    type IntoIter = FatArchIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        FatArchIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
}

#[cfg(feature = "std")]
impl<'a> MultiArch<'a> {
    /// Lazily construct `Self`
    pub fn new(bytes: &'a [u8]) -> error::Result<Self> {
        let header = fat::FatHeader::parse(bytes)?;
        Ok(MultiArch {
            data: bytes,
            start: fat::SIZEOF_FAT_HEADER,
            narches: header.nfat_arch as usize
        })
    }
    /// Return all the architectures in this binary
    pub fn arches(&self) -> error::Result<Vec<fat::FatArch>> {
        let mut arches = Vec::with_capacity(self.narches);
        for arch in self.into_iter() {
            arches.push(arch?);
        }
        Ok(arches)
    }
    /// Try to get the Mach-o binary at `index`
    pub fn get(&self, index: usize) -> error::Result<MachO> {
        if index >= self.narches {
            return Err(error::Error::Malformed(format!("Requested the {}-th binary, but there are only {} architectures in this container", index, self.narches).into()))
        }
        let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
        let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE)?;
        let bytes = arch.slice(self.data);
        Ok(MachO::parse(bytes, 0)?)
    }

    /// Try and find the `cputype` in `Self`, if there is one
    pub fn find_cputype(&self, cputype: u32) -> error::Result<Option<fat::FatArch>> {
        for arch in self.into_iter() {
            let arch = arch?;
            if arch.cputype == cputype { return Ok(Some(arch)) }
        }
        Ok(None)
    }
}

#[cfg(feature = "std")]
impl<'a> fmt::Debug for MultiArch<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("MultiArch")
            .field("arches",  &self.arches().unwrap())
            .field("data",    &self.data.len())
            .finish()
    }
}

#[derive(Debug)]
/// Either a collection of multiple architectures, or a single mach-o binary
pub enum Mach<'a> {
    Fat(MultiArch<'a>),
    Binary(MachO<'a>)
}

impl<'a> Mach<'a> {
    /// Parse from `bytes` either a multi-arch binary or a regular mach-o binary
    pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
        let size = bytes.len();
        if size < 4 {
            let error = error::Error::Malformed(
                                       format!("size is smaller than a magical number"));
            return Err(error);
        }
        let magic = peek(&bytes, 0)?;
        match magic {
            fat::FAT_MAGIC => {
                let multi = MultiArch::new(bytes)?;
                Ok(Mach::Fat(multi))
            },
            // we're a regular binary
            _ => {
                let binary = MachO::parse(bytes, 0)?;
                Ok(Mach::Binary(binary))
            }
        }
    }
}
<|endoftext|>