<commit_before>use super::{Read, Write, Port};
use ::util;

#[derive(Debug, Copy, Clone)]
#[repr(usize)]
pub enum Serial { Com1 = 0
                , Com2 = 1
                , Com3 = 2
                , Com4 = 3
                }

impl Serial {
    #[inline]
    fn get_port_addr(&self) -> Option<u16> {
        match BDA_SERIAL_INFO[*self as usize] {
            n if n > 0 => Some(n)
          , _ => None
        }
    }

    /// Returns `Some(SerialPort)` if this port exists, `None` if it does not
    pub fn new(&self) -> Option<SerialPort> {
        self.get_port_addr().map(|port| {
            Port::<u8>::new(port + 1).write(0x00);
            Port::<u8>::new(port + 3).write(0x80);
            Port::<u8>::new(port + 0).write(0x03);
            Port::<u8>::new(port + 1).write(0x00);
            Port::<u8>::new(port + 3).write(0x03);
            Port::<u8>::new(port + 2).write(0xC7);
            Port::<u8>::new(port + 4).write(0x0B);
            Port::<u8>::new(port + 1).write(0x01);

            SerialPort { data_port: Port::<u8>::new(port)
                       , status_port: Port::<u8>::new(port + 5)
                       }
        })
    }
}

/// Address of the BIOS Data Area (BDA)
/// where the serial port addresses are stored.
const BDA_ADDR: usize = 0x400;

lazy_static! {
    static ref BDA_SERIAL_INFO: [u16; 4]
        = unsafe { *(BDA_ADDR as *const [u16; 4]) };

}

pub struct SerialPort { data_port: Port<u8>
                      , status_port: Port<u8>
                      }

impl SerialPort {
    /// Returns true if the serial port has recieved data
    #[inline]
    pub fn has_byte(&self) -> bool {
        self.status_port.read() & 1 != 0
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.status_port.read() & 0x20 == 0x20
    }

    #[inline]
    pub fn read_byte(&self) -> u8 {
        while !self.has_byte() {};
        self.data_port.read()
    }

    #[inline]
    pub fn write_byte(&self, byte: u8) {
        while !self.is_empty() {};
        self.data_port.write(byte)
    }
}

impl Read for SerialPort {
    type Error = util::Void;

    /// Reads a single byte into the given buffer
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        Ok(match &mut *buf {
            // if the length of the buffer is 0, then obviously
            // no bytes were read
            &mut []                  => 0
            // otherwise, read one byte into the head of the buffer
          , &mut [ref mut head, _..] => { *head = self.read_byte(); 1 }
        })
    }

    /// Reads a new byte into each position in the buffer.
    fn read_all(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        let mut read_bytes = 0;
        for idx in buf.iter_mut() {
            // for each index in the buffer, read another byte from the port
            *idx = self.read_byte();
            // and increment the number of bytes read (this should be faster
            // than calling `buf.len()` later; as we only need 1 loop)
            read_bytes += 1;
        }
        Ok(read_bytes)
    }
}

impl Write for SerialPort {
    type Error = util::Void;

    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
        let mut written_bytes = 0;
        for byte in buf {
            // write each byte in the buffer to the port
            self.write_byte(*byte);
            // and increment the number of bytes written (this should be faster
            // than calling `buf.len()` later; as we only need 1 loop)
            written_bytes += 1;
        }
        Ok(written_bytes)
    }
}
<commit_msg>[kernel] documentation for serial port driver<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Serial port driver
//!
//! Create new serial ports by calling `PortNum::new()`. If the system supports
//! that port, `Some(SerialPort)` will be returned. Otherwise, if the system
//! does not have that port number (such as `COM3` and `COM4`) on many machines,
//! `PortNum::new()` returns `None`.
//!
//! See [the OS Dev wiki](http://wiki.osdev.org/Serial_Ports) for more
//! information.

use super::{Read, Write, Port};
use ::util;

/// Available serial ports.
///
/// These are used to create new serial ports, so that serial ports
/// cannot be created for an arbitrary memory location.
///
#[derive(Debug, Copy, Clone)]
#[repr(usize)]
pub enum PortNum { Com1 = 0
                , Com2 = 1
                , Com3 = 2
                , Com4 = 3
                }

impl PortNum {
    #[inline]
    fn get_port_addr(&self) -> Option<u16> {
        match BDA_SERIAL_INFO[*self as usize] {
            n if n > 0 => Some(n)
          , _ => None
        }
    }

    /// Returns `Some(SerialPort)` if this port exists, `None` if it does not
    pub fn new(&self) -> Option<SerialPort> {
        self.get_port_addr().map(|port| {
             // Disable all interrupts
            Port::<u8>::new(port + 1).write(0x00);
            // Enable DLAB (set baud rate divisor)
            Port::<u8>::new(port + 3).write(0x80);
            // Set divisor to 38400 baud
            Port::<u8>::new(port + 0).write(0x03); // divisor hi byte
            Port::<u8>::new(port + 1).write(0x00); // divisor lo byte
            // 8 bits, no parity, one stop bit
            Port::<u8>::new(port + 3).write(0x03);
            // Enable FIFO, clear them, with 14-byte threshold
            Port::<u8>::new(port + 2).write(0xC7);
            // IRQs enabled, RTS/DSR set
            Port::<u8>::new(port + 4).write(0x0B);
            Port::<u8>::new(port + 1).write(0x01);

            SerialPort { data_port: Port::<u8>::new(port)
                       , status_port: Port::<u8>::new(port + 5)
                       }
        })
    }
}

/// Address of the BIOS Data Area (BDA)
/// where the serial port addresses are stored.
const BDA_ADDR: usize = 0x400;

lazy_static! {
    static ref BDA_SERIAL_INFO: [u16; 4]
        = unsafe { *(BDA_ADDR as *const [u16; 4]) };

}

/// A serial port
pub struct SerialPort { data_port: Port<u8>
                      , status_port: Port<u8>
                      }

impl SerialPort {
    /// Returns true if the serial port has recieved data
    #[inline]
    pub fn has_byte(&self) -> bool {
        self.status_port.read() & 1 != 0
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.status_port.read() & 0x20 == 0x20
    }

    #[inline]
    pub fn read_byte(&self) -> u8 {
        while !self.has_byte() {};
        self.data_port.read()
    }

    #[inline]
    pub fn write_byte(&self, byte: u8) {
        while !self.is_empty() {};
        self.data_port.write(byte)
    }
}

impl Read for SerialPort {
    type Error = util::Void;

    /// Reads a single byte into the given buffer
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        Ok(match &mut *buf {
            // if the length of the buffer is 0, then obviously
            // no bytes were read
            &mut []                  => 0
            // otherwise, read one byte into the head of the buffer
          , &mut [ref mut head, _..] => { *head = self.read_byte(); 1 }
        })
    }

    /// Reads a new byte into each position in the buffer.
    fn read_all(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        let mut read_bytes = 0;
        for idx in buf.iter_mut() {
            // for each index in the buffer, read another byte from the port
            *idx = self.read_byte();
            // and increment the number of bytes read (this should be faster
            // than calling `buf.len()` later; as we only need 1 loop)
            read_bytes += 1;
        }
        Ok(read_bytes)
    }
}

impl Write for SerialPort {
    type Error = util::Void;

    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
        let mut written_bytes = 0;
        for byte in buf {
            // write each byte in the buffer to the port
            self.write_byte(*byte);
            // and increment the number of bytes written (this should be faster
            // than calling `buf.len()` later; as we only need 1 loop)
            written_bytes += 1;
        }
        Ok(written_bytes)
    }
}
<|endoftext|>


<commit_before>use camera::Camera;
use ctrl::{Analog2d, Gesture};
use ctrl::GameController;
use level::Level;
use math::{Vec3, Vec3f, Vec2f, Numvec};
use sdl2::scancode::ScanCode;
use std::default::Default;
use num::Float;

pub struct PlayerBindings {
    pub movement: Analog2d,
    pub look: Analog2d,
    pub jump: Gesture,
}

impl PlayerBindings {
    pub fn look_vector(&self, controller: &GameController) -> Vec2f {
        controller.poll_analog2d(&self.look)
    }

    pub fn movement_vector(&self, controller: &GameController) -> Vec2f {
        controller.poll_analog2d(&self.movement)
    }

    pub fn jump(&self, controller: &GameController) -> bool {
        controller.poll_gesture(&self.jump)
    }
}

impl Default for PlayerBindings {
    fn default() -> PlayerBindings {
        PlayerBindings {
            movement: Analog2d::Gestures(
                Gesture::AnyOf(vec![Gesture::KeyHold(ScanCode::D),
                                    Gesture::KeyHold(ScanCode::Right)]),
                Gesture::AnyOf(vec![Gesture::KeyHold(ScanCode::A),
                                    Gesture::KeyHold(ScanCode::Left)]),
                Gesture::AnyOf(vec![Gesture::KeyHold(ScanCode::W),
                                    Gesture::KeyHold(ScanCode::Up)]),
                Gesture::AnyOf(vec![Gesture::KeyHold(ScanCode::S),
                                    Gesture::KeyHold(ScanCode::Down)]),
                1.0),
            look: Analog2d::Mouse(0.002),
            jump: Gesture::KeyTrigger(ScanCode::Space),
        }
    }
}

pub struct Player {
    bindings: PlayerBindings,
    camera: Camera,
    move_accel: f32,
    floor_height: f32,
    ceil_height: f32,
    vertical_speed: f32,
    horizontal_speed: Vec2f,
}

impl Player {
    pub fn new(fov: f32, aspect_ratio: f32,
               bindings: PlayerBindings) -> Player {
        let mut camera = Camera::new(fov, aspect_ratio, 0.01, 100.0);
        camera.set_yaw(3.1415926538);

        Player {
            bindings: bindings,
            camera: camera,
            move_accel: 10.0,
            floor_height: 0.0,
            ceil_height: 100.0,
            vertical_speed: 0.0,
            horizontal_speed: Vec2f::zero(),
        }
    }

    pub fn set_position(&mut self, new_pos: &Vec3f) -> &mut Player {
        self.camera.set_position(*new_pos);
        self
    }

    pub fn update(&mut self, delta_time: f32, controller: &GameController, level: &Level) {
        let mut pos = *self.camera.position();
        let old_pos = pos;

        pos.x += self.horizontal_speed.x * delta_time;
        pos.z += self.horizontal_speed.y * delta_time;
        pos.y += self.vertical_speed * delta_time;
        level.heights_at(&Vec2f::new(pos.x, pos.z)).map(|(floor, ceil)| {
            self.floor_height = floor + 50.0 / 100.0;
            self.ceil_height = ceil - 1.0 / 100.0;
        });

        let floor_dist = (pos.y - self.floor_height).abs();
        let in_control = self.vertical_speed.abs() < 0.5 && floor_dist < 1e-1;
        let floored = floor_dist < 1e-2;

        if floored {
            self.horizontal_speed = self.horizontal_speed * 0.7;
        } else {
            self.horizontal_speed = self.horizontal_speed * 0.97;
        }

        if old_pos.y < self.floor_height && pos.y > self.floor_height
                || old_pos.y > self.floor_height && pos.y < self.floor_height
                || floor_dist <= 1e-3 {
            self.vertical_speed = 0.0;
            pos.y = self.floor_height;
        } else if pos.y > self.ceil_height {
            self.vertical_speed = 0.0;
            pos.y = self.ceil_height;
        } else {
            if pos.y < self.floor_height {
                if self.floor_height - pos.y > 1.0 {
                    pos.y = self.floor_height;
                } else {
                    self.vertical_speed += 1.0 * delta_time;
                    pos.y = (pos.y + self.floor_height + 0.1)/2.0;
                }
            } else {
                self.vertical_speed -= 17.0 * delta_time;
            }
        }

        let movement = self.bindings.movement_vector(controller);
        let look = self.bindings.look_vector(controller);
        if movement.norm() != 0.0 || look.norm() != 0.0 {
            let yaw = self.camera.yaw() + look.x;
            let pitch = clamp(self.camera.pitch() - look.y, (-3.14 / 2.0, 3.14 / 2.0));
            self.camera.set_yaw(yaw);
            self.camera.set_pitch(pitch);

            let movement = Vec2f::new(
                yaw.cos() * movement.x + yaw.sin() * movement.y,
                -yaw.cos() * movement.y + yaw.sin() * movement.x) * self.move_accel;
            let mut displacement = self.move_accel * delta_time;
            if !floored {
                displacement *= 0.05;
            }
            self.horizontal_speed = self.horizontal_speed + movement * displacement;
        }

        let jump = self.bindings.jump(controller);
        if jump && in_control {
            self.vertical_speed = 5.0;
        }
        self.camera.set_position(pos);
    }

    pub fn get_camera(&self) -> &Camera {
        &self.camera
    }

    pub fn get_camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }
}

fn clamp<T: PartialOrd>(value: T, (limit_min, limit_max): (T, T)) -> T {
    if value < limit_min { limit_min }
    else if value > limit_max { limit_max }
    else { value }
}

<commit_msg>Removed unused import.<commit_after>use camera::Camera;
use ctrl::{Analog2d, Gesture};
use ctrl::GameController;
use level::Level;
use math::{Vec3f, Vec2f, Numvec};
use sdl2::scancode::ScanCode;
use std::default::Default;
use num::Float;

pub struct PlayerBindings {
    pub movement: Analog2d,
    pub look: Analog2d,
    pub jump: Gesture,
}

impl PlayerBindings {
    pub fn look_vector(&self, controller: &GameController) -> Vec2f {
        controller.poll_analog2d(&self.look)
    }

    pub fn movement_vector(&self, controller: &GameController) -> Vec2f {
        controller.poll_analog2d(&self.movement)
    }

    pub fn jump(&self, controller: &GameController) -> bool {
        controller.poll_gesture(&self.jump)
    }
}

impl Default for PlayerBindings {
    fn default() -> PlayerBindings {
        PlayerBindings {
            movement: Analog2d::Gestures(
                Gesture::AnyOf(vec![Gesture::KeyHold(ScanCode::D),
                                    Gesture::KeyHold(ScanCode::Right)]),
                Gesture::AnyOf(vec![Gesture::KeyHold(ScanCode::A),
                                    Gesture::KeyHold(ScanCode::Left)]),
                Gesture::AnyOf(vec![Gesture::KeyHold(ScanCode::W),
                                    Gesture::KeyHold(ScanCode::Up)]),
                Gesture::AnyOf(vec![Gesture::KeyHold(ScanCode::S),
                                    Gesture::KeyHold(ScanCode::Down)]),
                1.0),
            look: Analog2d::Mouse(0.002),
            jump: Gesture::KeyTrigger(ScanCode::Space),
        }
    }
}

pub struct Player {
    bindings: PlayerBindings,
    camera: Camera,
    move_accel: f32,
    floor_height: f32,
    ceil_height: f32,
    vertical_speed: f32,
    horizontal_speed: Vec2f,
}

impl Player {
    pub fn new(fov: f32, aspect_ratio: f32,
               bindings: PlayerBindings) -> Player {
        let mut camera = Camera::new(fov, aspect_ratio, 0.01, 100.0);
        camera.set_yaw(3.1415926538);

        Player {
            bindings: bindings,
            camera: camera,
            move_accel: 10.0,
            floor_height: 0.0,
            ceil_height: 100.0,
            vertical_speed: 0.0,
            horizontal_speed: Vec2f::zero(),
        }
    }

    pub fn set_position(&mut self, new_pos: &Vec3f) -> &mut Player {
        self.camera.set_position(*new_pos);
        self
    }

    pub fn update(&mut self, delta_time: f32, controller: &GameController, level: &Level) {
        let mut pos = *self.camera.position();
        let old_pos = pos;

        pos.x += self.horizontal_speed.x * delta_time;
        pos.z += self.horizontal_speed.y * delta_time;
        pos.y += self.vertical_speed * delta_time;
        level.heights_at(&Vec2f::new(pos.x, pos.z)).map(|(floor, ceil)| {
            self.floor_height = floor + 50.0 / 100.0;
            self.ceil_height = ceil - 1.0 / 100.0;
        });

        let floor_dist = (pos.y - self.floor_height).abs();
        let in_control = self.vertical_speed.abs() < 0.5 && floor_dist < 1e-1;
        let floored = floor_dist < 1e-2;

        if floored {
            self.horizontal_speed = self.horizontal_speed * 0.7;
        } else {
            self.horizontal_speed = self.horizontal_speed * 0.97;
        }

        if old_pos.y < self.floor_height && pos.y > self.floor_height
                || old_pos.y > self.floor_height && pos.y < self.floor_height
                || floor_dist <= 1e-3 {
            self.vertical_speed = 0.0;
            pos.y = self.floor_height;
        } else if pos.y > self.ceil_height {
            self.vertical_speed = 0.0;
            pos.y = self.ceil_height;
        } else {
            if pos.y < self.floor_height {
                if self.floor_height - pos.y > 1.0 {
                    pos.y = self.floor_height;
                } else {
                    self.vertical_speed += 1.0 * delta_time;
                    pos.y = (pos.y + self.floor_height + 0.1)/2.0;
                }
            } else {
                self.vertical_speed -= 17.0 * delta_time;
            }
        }

        let movement = self.bindings.movement_vector(controller);
        let look = self.bindings.look_vector(controller);
        if movement.norm() != 0.0 || look.norm() != 0.0 {
            let yaw = self.camera.yaw() + look.x;
            let pitch = clamp(self.camera.pitch() - look.y, (-3.14 / 2.0, 3.14 / 2.0));
            self.camera.set_yaw(yaw);
            self.camera.set_pitch(pitch);

            let movement = Vec2f::new(
                yaw.cos() * movement.x + yaw.sin() * movement.y,
                -yaw.cos() * movement.y + yaw.sin() * movement.x) * self.move_accel;
            let mut displacement = self.move_accel * delta_time;
            if !floored {
                displacement *= 0.05;
            }
            self.horizontal_speed = self.horizontal_speed + movement * displacement;
        }

        let jump = self.bindings.jump(controller);
        if jump && in_control {
            self.vertical_speed = 5.0;
        }
        self.camera.set_position(pos);
    }

    pub fn get_camera(&self) -> &Camera {
        &self.camera
    }

    pub fn get_camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }
}

fn clamp<T: PartialOrd>(value: T, (limit_min, limit_max): (T, T)) -> T {
    if value < limit_min { limit_min }
    else if value > limit_max { limit_max }
    else { value }
}

<|endoftext|>


<commit_before>use std::io;

use num::rational::Ratio;
use imageops::overlay;

use color;
use animation::Frame;
use image::{ImageError, ImageResult, DecodingResult, ImageDecoder};
use buffer::{ImageBuffer, GreyImage, RgbaImage};

use super::lzw::LZWReader;

#[deriving(PartialEq)]
enum State {
    Start,
    HaveHeader,
    HaveLSD,
}

#[deriving(FromPrimitive)]
enum Block {
    Image = 0x2C,
    Extension = 0x21,
    Trailer = 0x3B
}

#[deriving(FromPrimitive)]
enum Extension {
    Text = 0x01,
    Control = 0xF9,
    Comment = 0xFE,
    Application = 0xFF
}

pub struct GIFDecoder<R: Reader> {
    r: R,
    state: State,

    width: u16,
    height: u16,
    global_table: Vec<(u8, u8, u8)>,
    global_background_index: Option<u8>,
    delay: u16,
    local_transparent_index: Option<u8>,
}

impl<R: Reader> GIFDecoder<R> {
    pub fn new(r: R) -> GIFDecoder<R> {
        GIFDecoder {
            r: r,
            state: State::Start,

            width: 0,
            height: 0,
            global_table: Vec::new(),
            global_background_index: None,
            delay: 0,
            local_transparent_index: None,
        }
    }

    fn read_header(&mut self) -> ImageResult<()> {
        if self.state == State::Start {
            let mut signature = [0, ..3];
            let mut version = [0, ..3];
            try!(self.r.read_at_least(3, signature.as_mut_slice()));
            try!(self.r.read_at_least(3, version.as_mut_slice()));

            if signature.as_slice() != b"GIF" {
                Err(ImageError::FormatError("GIF signature not found.".to_string()))
            } else if version.as_slice() != b"87a" && version.as_slice() != b"89a" {
                Err(ImageError::UnsupportedError(
                    format!("GIF version {} is not supported.", version)
                ))
            } else {
                self.state = State::HaveHeader;
                Ok(())
            }
        } else { Ok(()) }
    }

    fn read_logical_screen_descriptor(&mut self) -> ImageResult<()> {
        try!(self.read_header());
        if self.state == State::HaveHeader {
            self.width  = try!(self.r.read_le_u16());
            self.height = try!(self.r.read_le_u16());

            let fields = try!(self.r.read_u8());

            let global_table = fields & 0x80 != 0;

            let entries = if global_table {
                1 << ((fields & 0b111) + 1) as uint
            } else {
                0u
            };

            let b = try!(self.r.read_u8());
            if global_table {
                self.global_table.reserve_exact(entries);
                self.global_background_index = Some(b);
            }

            let _aspect_ratio = try!(self.r.read_u8());

            let buf = try!(self.r.read_exact(3 * entries));

            for rgb in buf.as_slice().chunks(3) {
                self.global_table.push((rgb[0], rgb[1], rgb[2]));
            }
            self.state = State::HaveLSD;
            Ok(())
        } else { Ok(()) }
    }

    fn read_extension(&mut self) -> ImageResult<()> {
        use self::Extension::{Text, Control, Comment, Application};

        match FromPrimitive::from_u8(try!(self.r.read_u8())) {
            Some(Text) => try!(self.skip_extension()),
            Some(Control) => try!(self.read_control_extension()),
            Some(Comment) => try!(self.skip_extension()),
            Some(Application) => try!(self.skip_extension()),
            None => try!(self.skip_extension())
        }
        Ok(())
    }

    fn read_control_extension(&mut self) -> ImageResult<()> {
        let size = try!(self.r.read_u8());
        if size != 4 {
            return Err(ImageError::FormatError(
                "Malformed graphics control extension.".to_string()
            ))
        }
        let fields = try!(self.r.read_u8());
        self.delay = try!(self.r.read_le_u16());
        let trans  = try!(self.r.read_u8());

        if fields & 1 != 0 {
            self.local_transparent_index = Some(trans);
        }
        let size = try!(self.r.read_u8());
        if size != 0 {
            return Err(ImageError::FormatError(
                "Malformed graphics control extension.".to_string()
            ))
        }
        Ok(())
    }

    /// Skips an unknown extension
    fn skip_extension(&mut self) -> ImageResult<()> {
        let mut size = try!(self.r.read_u8());
        while size != 0 {
            for _ in range(0, size) {
                let _ = try!(self.r.read_u8());
            }
            size = try!(self.r.read_u8());
        }
        Ok(())
    }

    /// Reads data blocks
    fn read_data(&mut self) -> ImageResult<Vec<u8>> {
        let mut size = try!(self.r.read_u8()) as uint;
        let mut data = Vec::with_capacity(size);
        while size != 0 {
            data.push_all(try!(self.r.read_exact(size)).as_slice());
            size = try!(self.r.read_u8()) as uint;
        }
        Ok(data)
    }

    #[allow(unused_variables)]
    fn read_frame(&mut self) -> ImageResult<Frame> {
        let image_left   = try!(self.r.read_le_u16());
        let image_top    = try!(self.r.read_le_u16());
        let image_width  = try!(self.r.read_le_u16());
        let image_height = try!(self.r.read_le_u16());

        let fields = try!(self.r.read_u8());

        let local_table = (fields & 0b1000_0000) != 0;
        let interlace   = (fields & 0b0100_0000) != 0;
        let table_size  =  fields & 0b0000_0111;

        if interlace {
            return Err(ImageError::UnsupportedError(
                "Interlaced images are not supported.".to_string()
            ))
        }

        let local_table = if local_table {
            let entries = 1 << (table_size + 1) as uint;
            let mut table = Vec::with_capacity(entries * 3);
            let buf = try!(self.r.read_exact(3 * entries));

            for rgb in buf.as_slice().chunks(3) {
                table.push((rgb[0], rgb[1], rgb[2]));
            }
            Some(table)
        } else {
            None
        };

        let code_size = try!(self.r.read_u8());
        let data = try!(self.read_data());

        let mut lzw = LZWReader::new(
            io::MemReader::new(data),
            code_size
        );
        let mut indices = Vec::with_capacity(
            image_width as uint
            * image_height as uint
        );
        try!(lzw.decode(&mut indices));

        let table = if let Some(ref table) = local_table {
            table.as_slice()
        } else {
            self.global_table.as_slice()
        };

        let image: Option<GreyImage> = ImageBuffer::from_vec(
            image_width as u32,
            image_height as u32,
            indices
        );
        if let Some(image) = image {
            let image = expand_palette(image, table, self.local_transparent_index);
            Ok(Frame::from_parts(
                image,
                image_left as u32,
                image_top as u32,
                Ratio::new(self.delay, 100)
            ))
        } else {
            Err(ImageError::FormatError(
                "Image data has not the expected size.".to_string()
            ))
        }
    }

    fn next_frame(&mut self) -> ImageResult<Option<Frame>> {
        use self::Block::{Image, Extension, Trailer};

        try!(self.read_logical_screen_descriptor());
        loop {
            match FromPrimitive::from_u8(try!(self.r.read_u8())) {
                Some(Extension) => try!(self.read_extension()),
                Some(Image) => return self.read_frame().map(|v| Some(v)),
                Some(Trailer) => return Ok(None),
                None => return Err(ImageError::UnsupportedError(
                    "Unknown block encountered".to_string()
                ))
            }
        }
    }
}

fn expand_palette(image: GreyImage,
                  palette: &[(u8, u8, u8)],
                  transparent_idx: Option<u8>) -> RgbaImage {
    // TODO make this more efficient without copying
    let width = image.width();
    let height = image.height();
    let vec = image.into_vec();
    let mut image = ImageBuffer::new(width, height);
    for (pixel, &idx) in image.pixels_mut().zip(vec.iter()) {
        let (r, g, b) = palette[idx as uint];
        let alpha = if let Some(t_idx) = transparent_idx {
            if t_idx == idx {
                0
            } else {
                255
            }
        } else {
            255
        };
        *pixel = color::Rgba([r, g, b, alpha])
    }
    image
}

impl<R: Reader> ImageDecoder for GIFDecoder<R> {
    fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
        let _ = try!(self.read_logical_screen_descriptor());
        Ok((self.width as u32, self.height as u32))
    }

    fn colortype(&mut self) -> ImageResult<color::ColorType> {
        let _ = try!(self.read_logical_screen_descriptor());
        Ok(color::ColorType::RGBA(8))
    }

    fn row_len(&mut self) -> ImageResult<uint> {
        let _ = try!(self.read_logical_screen_descriptor());
        Ok(3 * self.width as uint)
    }

    fn read_scanline(&mut self, _: &mut [u8]) -> ImageResult<u32> {
        unimplemented!()
    }

    fn read_image(&mut self) -> ImageResult<DecodingResult> {
        let (width, height) = try!(self.dimensions());
        let background = if let Some(idx) = self.global_background_index {
            let (r, g, b) = self.global_table[idx as uint];
            color::Rgba([r, g, b, 255])
        } else {
            color::Rgba([0, 0, 0, 255])
        };
        let mut canvas: RgbaImage = ImageBuffer::from_pixel(width, height, background);
        let frame = try!(self.next_frame());
        match frame {
            Some(frame) => {
                let left = frame.left();
                let top = frame.top();
                let buffer = frame.into_buffer();
                overlay(&mut canvas, &buffer, left, top);
                while let Some(frame) = try!(self.next_frame()) {
                    if frame.delay() == Ratio::new(0, 100) {
                        let left = frame.left();
                        let top = frame.top();
                        let buffer = frame.into_buffer();
                        overlay(&mut canvas, &buffer, left, top);
                    }
                }
                Ok(DecodingResult::U8(canvas.into_vec()))
            },
            None => Err(ImageError::ImageEnd)
        }
    }
}
<commit_msg>add docs<commit_after>use std::io;

use num::rational::Ratio;
use imageops::overlay;

use color;
use animation::Frame;
use image::{ImageError, ImageResult, DecodingResult, ImageDecoder};
use buffer::{ImageBuffer, GreyImage, RgbaImage};

use super::lzw::LZWReader;

#[deriving(PartialEq)]
enum State {
    Start,
    HaveHeader,
    HaveLSD,
}

#[deriving(FromPrimitive)]
enum Block {
    Image = 0x2C,
    Extension = 0x21,
    Trailer = 0x3B
}

#[deriving(FromPrimitive)]
enum Extension {
    Text = 0x01,
    Control = 0xF9,
    Comment = 0xFE,
    Application = 0xFF
}

pub struct GIFDecoder<R: Reader> {
    r: R,
    state: State,

    width: u16,
    height: u16,
    global_table: Vec<(u8, u8, u8)>,
    global_background_index: Option<u8>,
    delay: u16,
    local_transparent_index: Option<u8>,
}

impl<R: Reader> GIFDecoder<R> {
    /// Creates a new GIF decoder
    pub fn new(r: R) -> GIFDecoder<R> {
        GIFDecoder {
            r: r,
            state: State::Start,

            width: 0,
            height: 0,
            global_table: Vec::new(),
            global_background_index: None,
            delay: 0,
            local_transparent_index: None,
        }
    }

    fn read_header(&mut self) -> ImageResult<()> {
        if self.state == State::Start {
            let mut signature = [0, ..3];
            let mut version = [0, ..3];
            try!(self.r.read_at_least(3, signature.as_mut_slice()));
            try!(self.r.read_at_least(3, version.as_mut_slice()));

            if signature.as_slice() != b"GIF" {
                Err(ImageError::FormatError("GIF signature not found.".to_string()))
            } else if version.as_slice() != b"87a" && version.as_slice() != b"89a" {
                Err(ImageError::UnsupportedError(
                    format!("GIF version {} is not supported.", version)
                ))
            } else {
                self.state = State::HaveHeader;
                Ok(())
            }
        } else { Ok(()) }
    }

    fn read_logical_screen_descriptor(&mut self) -> ImageResult<()> {
        try!(self.read_header());
        if self.state == State::HaveHeader {
            self.width  = try!(self.r.read_le_u16());
            self.height = try!(self.r.read_le_u16());

            let fields = try!(self.r.read_u8());

            let global_table = fields & 0x80 != 0;

            let entries = if global_table {
                1 << ((fields & 0b111) + 1) as uint
            } else {
                0u
            };

            let b = try!(self.r.read_u8());
            if global_table {
                self.global_table.reserve_exact(entries);
                self.global_background_index = Some(b);
            }

            let _aspect_ratio = try!(self.r.read_u8());

            let buf = try!(self.r.read_exact(3 * entries));

            for rgb in buf.as_slice().chunks(3) {
                self.global_table.push((rgb[0], rgb[1], rgb[2]));
            }
            self.state = State::HaveLSD;
            Ok(())
        } else { Ok(()) }
    }

    fn read_extension(&mut self) -> ImageResult<()> {
        use self::Extension::{Text, Control, Comment, Application};

        match FromPrimitive::from_u8(try!(self.r.read_u8())) {
            Some(Text) => try!(self.skip_extension()),
            Some(Control) => try!(self.read_control_extension()),
            Some(Comment) => try!(self.skip_extension()),
            Some(Application) => try!(self.skip_extension()),
            None => try!(self.skip_extension())
        }
        Ok(())
    }

    fn read_control_extension(&mut self) -> ImageResult<()> {
        let size = try!(self.r.read_u8());
        if size != 4 {
            return Err(ImageError::FormatError(
                "Malformed graphics control extension.".to_string()
            ))
        }
        let fields = try!(self.r.read_u8());
        self.delay = try!(self.r.read_le_u16());
        let trans  = try!(self.r.read_u8());

        if fields & 1 != 0 {
            self.local_transparent_index = Some(trans);
        }
        let size = try!(self.r.read_u8());
        if size != 0 {
            return Err(ImageError::FormatError(
                "Malformed graphics control extension.".to_string()
            ))
        }
        Ok(())
    }

    /// Skips an unknown extension
    fn skip_extension(&mut self) -> ImageResult<()> {
        let mut size = try!(self.r.read_u8());
        while size != 0 {
            for _ in range(0, size) {
                let _ = try!(self.r.read_u8());
            }
            size = try!(self.r.read_u8());
        }
        Ok(())
    }

    /// Reads data blocks
    fn read_data(&mut self) -> ImageResult<Vec<u8>> {
        let mut size = try!(self.r.read_u8()) as uint;
        let mut data = Vec::with_capacity(size);
        while size != 0 {
            data.push_all(try!(self.r.read_exact(size)).as_slice());
            size = try!(self.r.read_u8()) as uint;
        }
        Ok(data)
    }

    #[allow(unused_variables)]
    fn read_frame(&mut self) -> ImageResult<Frame> {
        let image_left   = try!(self.r.read_le_u16());
        let image_top    = try!(self.r.read_le_u16());
        let image_width  = try!(self.r.read_le_u16());
        let image_height = try!(self.r.read_le_u16());

        let fields = try!(self.r.read_u8());

        let local_table = (fields & 0b1000_0000) != 0;
        let interlace   = (fields & 0b0100_0000) != 0;
        let table_size  =  fields & 0b0000_0111;

        if interlace {
            return Err(ImageError::UnsupportedError(
                "Interlaced images are not supported.".to_string()
            ))
        }

        let local_table = if local_table {
            let entries = 1 << (table_size + 1) as uint;
            let mut table = Vec::with_capacity(entries * 3);
            let buf = try!(self.r.read_exact(3 * entries));

            for rgb in buf.as_slice().chunks(3) {
                table.push((rgb[0], rgb[1], rgb[2]));
            }
            Some(table)
        } else {
            None
        };

        let code_size = try!(self.r.read_u8());
        let data = try!(self.read_data());

        let mut lzw = LZWReader::new(
            io::MemReader::new(data),
            code_size
        );
        let mut indices = Vec::with_capacity(
            image_width as uint
            * image_height as uint
        );
        try!(lzw.decode(&mut indices));

        let table = if let Some(ref table) = local_table {
            table.as_slice()
        } else {
            self.global_table.as_slice()
        };

        let image: Option<GreyImage> = ImageBuffer::from_vec(
            image_width as u32,
            image_height as u32,
            indices
        );
        if let Some(image) = image {
            let image = expand_palette(image, table, self.local_transparent_index);
            Ok(Frame::from_parts(
                image,
                image_left as u32,
                image_top as u32,
                Ratio::new(self.delay, 100)
            ))
        } else {
            Err(ImageError::FormatError(
                "Image data has not the expected size.".to_string()
            ))
        }
    }

    fn next_frame(&mut self) -> ImageResult<Option<Frame>> {
        use self::Block::{Image, Extension, Trailer};

        try!(self.read_logical_screen_descriptor());
        loop {
            match FromPrimitive::from_u8(try!(self.r.read_u8())) {
                Some(Extension) => try!(self.read_extension()),
                Some(Image) => return self.read_frame().map(|v| Some(v)),
                Some(Trailer) => return Ok(None),
                None => return Err(ImageError::UnsupportedError(
                    "Unknown block encountered".to_string()
                ))
            }
        }
    }
}

fn expand_palette(image: GreyImage,
                  palette: &[(u8, u8, u8)],
                  transparent_idx: Option<u8>) -> RgbaImage {
    // TODO make this more efficient without copying
    let width = image.width();
    let height = image.height();
    let vec = image.into_vec();
    let mut image = ImageBuffer::new(width, height);
    for (pixel, &idx) in image.pixels_mut().zip(vec.iter()) {
        let (r, g, b) = palette[idx as uint];
        let alpha = if let Some(t_idx) = transparent_idx {
            if t_idx == idx {
                0
            } else {
                255
            }
        } else {
            255
        };
        *pixel = color::Rgba([r, g, b, alpha])
    }
    image
}

impl<R: Reader> ImageDecoder for GIFDecoder<R> {
    fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
        let _ = try!(self.read_logical_screen_descriptor());
        Ok((self.width as u32, self.height as u32))
    }

    fn colortype(&mut self) -> ImageResult<color::ColorType> {
        let _ = try!(self.read_logical_screen_descriptor());
        Ok(color::ColorType::RGBA(8))
    }

    fn row_len(&mut self) -> ImageResult<uint> {
        let _ = try!(self.read_logical_screen_descriptor());
        Ok(3 * self.width as uint)
    }

    fn read_scanline(&mut self, _: &mut [u8]) -> ImageResult<u32> {
        unimplemented!()
    }

    fn read_image(&mut self) -> ImageResult<DecodingResult> {
        let (width, height) = try!(self.dimensions());
        let background = if let Some(idx) = self.global_background_index {
            let (r, g, b) = self.global_table[idx as uint];
            color::Rgba([r, g, b, 255])
        } else {
            color::Rgba([0, 0, 0, 255])
        };
        let mut canvas: RgbaImage = ImageBuffer::from_pixel(width, height, background);
        let frame = try!(self.next_frame());
        match frame {
            Some(frame) => {
                let left = frame.left();
                let top = frame.top();
                let buffer = frame.into_buffer();
                overlay(&mut canvas, &buffer, left, top);
                while let Some(frame) = try!(self.next_frame()) {
                    if frame.delay() == Ratio::new(0, 100) {
                        let left = frame.left();
                        let top = frame.top();
                        let buffer = frame.into_buffer();
                        overlay(&mut canvas, &buffer, left, top);
                    }
                }
                Ok(DecodingResult::U8(canvas.into_vec()))
            },
            None => Err(ImageError::ImageEnd)
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::{Deref, DerefMut};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

use std::io;
use std::io::Write;
use byteorder::{WriteBytesExt, LittleEndian};

use buffer::{ImageBuffer, Pixel};
use color::{Rgb, Rgba};
use utils::lzw;
use utils::bitstream::LsbWriter;
use imageops::ColorMap;

use super::{Extension, Block, DisposalMethod};

use math::nq;

#[derive(Debug, Clone, Copy)]
#[allow(unused_qualifications)]
/// The color mode the encoder will use to encode the image.
pub enum ColorMode {
    /// Image will be encoded in multiple frames if more than 256 colors are present
    TrueColor,
    /// Number of colors will be reduced
    Indexed(u8),
}
use self::ColorMode::{TrueColor, Indexed};

/// A GIF encoder.
///
/// Encodes the image either in true color using indexed colors.
/// If the mode is set to TrueColor the image is split into multiple frames
/// when the number of colors including transparent color exceeds 256.
/// Pixels with an alpha value != 1.0 will be set to alpha = 0.
pub struct Encoder<Image> {
    image: Image,
    bg_color: Option<Rgb<u8>>,
    color_mode: ColorMode
}

const TRANSPARENT: Rgba<u8> = Rgba {data: [0, 0, 0, 0]};

impl<Container> Encoder<ImageBuffer<Rgba<u8>, Container>>
where Container: Deref<Target=[u8]> + DerefMut {
    /// Creates a new GIF encoder
    pub fn new(image: ImageBuffer<Rgba<u8>, Container>,
               bg_color: Option<Rgb<u8>>,
               color_mode: ColorMode,
              ) -> Encoder<ImageBuffer<Rgba<u8>, Container>> {
        Encoder {
            image: image,
            bg_color: bg_color,
            color_mode: color_mode
        }
    }

    /// Encodes the image
    pub fn encode<W: Write>(&mut self, w: &mut W) -> io::Result<()> {
        use std::u16;
        // Header
        try!(w.write_all(b"GIF89a"));
        // Logical screen descriptor
        let height = self.image.height();
        let width = self.image.width();
        if width > u16::MAX as u32 ||
           height > u16::MAX as u32 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Image dimensions are too large for the gif format.",
            ))
        }
        try!(w.write_u16::<LittleEndian>(width as u16));
        try!(w.write_u16::<LittleEndian>(height as u16));

        let (hist, transparent) = self.histogram();
        let num_colors = hist.len();

        try!(self.write_global_table(w, &hist));

        match self.color_mode {
            // Global color table has been written, just write the image data now
            TrueColor if num_colors <= 256 => {
                // NOTE: copy paste any changes to case: Indexed(n) if n as usize <= num_colors
                try!(self.write_control_ext(w, 0, transparent));
                try!(self.write_descriptor(w, None));
                try!(self.write_image_simple(w, &hist, transparent));
            },
            TrueColor => {
                try!(self.write_true_color(w, hist, transparent));
            },
            Indexed(n) if n as usize <= num_colors && num_colors <= 256 => {
                // NOTE: copy paste from case: TrueColor if num_colors <= 256
                try!(self.write_control_ext(w, 0, transparent));
                try!(self.write_descriptor(w, None));
                try!(self.write_image_simple(w, &hist, transparent));
            }
            Indexed(n) => {
                try!(self.write_indexed_colors(w, n))
            }

        }
        w.write_all(&[Block::Trailer as u8])
    }

    /// Returns a histogram of the colors in the image
    fn histogram(&self) -> (Vec<(Rgba<u8>, usize)>, Option<usize>){
        let mut hist: HashMap<_, usize> = HashMap::new();
        // Add bg_color to table
        if let Some(bg_color) = self.bg_color {
            let _ = hist.insert(bg_color.to_rgba(), 0);
        }
        for p in self.image.pixels() {
            let mut p = *p;
            // Replace transparent pixels with black, alpha = 0
            if let Some(bg_color) = self.bg_color {
                p.blend(&bg_color.to_rgba())
            // do not use 255 as a limit there could be rounding error etc.
            // thus take 250 to give it some security margin.
            } else if p[3] < 250 {
                p = TRANSPARENT;
            }
            match hist.entry(p) {
                Occupied(mut entry) => {
                    let val = entry.get_mut();
                    *val = *val + 1;
                },
                Vacant(entry) => {
                    entry.insert(1);
                }
            }
        }
        let mut colors: Vec<(Rgba<u8>, usize)> = hist.into_iter().collect();
        // Sort color map with decreasing color freqs
        colors.sort_by(|a, b| b.1.cmp(&a.1));
        // Add bg_color to table
        let transparent = colors.iter().position(|x| x.0 == TRANSPARENT);
        (colors, transparent)
    }

    /// Write the global color table and the corresponding flags
    fn write_global_table<W: Write>(&mut self,
                                     w: &mut W,
                                     hist: &[(Rgba<u8>, usize)]
                                    ) -> io::Result<()>
    {
        let num_colors = hist.len();
        let mut flags = 0;
        flags |= 1 << 4; // sort flag
        let n = flag_n(num_colors);
        flags |= n << 4; // 2^(n+1) colors
        let (global_table, bg_index) = if num_colors <= 256 {
            flags |= 1 << 7; // glocal table flag
            flags |= n;
            let mut bg_index = 0;
            let mut table = Vec::with_capacity(3*(2 << n));
            for (i, &(color, _)) in hist.iter().enumerate() {
                let channels = &color.channels()[..3];
                if let Some(bg_color) = self.bg_color {
                    if channels == bg_color.channels() {
                        bg_index = i;
                    }
                }
                table.extend(channels.iter().map(|&c| c))
            }
            // Waste some space as of gif spec
            for _ in 0..((2 << n) - num_colors) {
                table.extend([0, 0, 0].iter().map(|&c| c));
            }
            (Some(table), bg_index as u8)
        } else if let Some(bg_color) = self.bg_color {
            flags |= 1 << 7; // glocal table flag
            let mut table = Vec::with_capacity(6);
            table.extend(bg_color.channels().iter().take(3).map(|&c| c));
            table.extend([0, 0, 0].iter().map(|&c| c));
            (Some(table), 0)
        } else {
            (None, 0)
        };
        try!(w.write_all(&[flags]));
        try!(w.write_all(&[bg_index]));
        try!(w.write_all(&[0])); // aspect ration, disregard
        if let Some(global_table) = global_table {
            try!(w.write_all(&global_table));
        }
        Ok(())
    }

    /// Writes the graphics control extension
    fn write_control_ext<W: Write>(&mut self,
                                    w: &mut W,
                                    delay: u16,
                                    transparent: Option<usize>
                                   ) -> io::Result<()>
    {
        try!(w.write_all(&[Block::Extension as u8]));
        try!(w.write_all(&[Extension::Control as u8]));
        try!(w.write_all(&[4])); // size
        let mut field = 0;
        field |= (DisposalMethod::None as u8) << 2;
        let idx = if let Some(idx) = transparent {
            field |=  1;
            idx as u8
        } else {
            0
        };
        try!(w.write_all(&[field]));
        try!(w.write_u16::<LittleEndian>(delay));
        try!(w.write_all(&[idx]));
        w.write_all(&[0])
    }

    /// Writes the image descriptor
    fn write_descriptor<W: Write>(&mut self,
                                   w: &mut W,
                                   table_len: Option<usize>
                                  ) -> io::Result<()>
    {
        try!(w.write_all(&[Block::Image as u8]));
        try!(w.write_u16::<LittleEndian>(0)); // left
        try!(w.write_u16::<LittleEndian>(0)); // top
        let height = self.image.height();
        let width = self.image.width();
        try!(w.write_u16::<LittleEndian>(width as u16));
        try!(w.write_u16::<LittleEndian>(height as u16));
        if let Some(len) = table_len {
            w.write_all(&[flag_n(len) | 0x80])
        } else {
            w.write_all(&[0])
        }
    }

    /// Writes and compresses the indexed data
    fn write_indices<W: Write>(&mut self,
                                w: &mut W,
                                indices: &[u8],
                               ) -> io::Result<()>
    {
        let code_size = match flag_n(indices.len()) + 1 {
            1 => 2,
            n => n
        };
        let mut encoded_data = Vec::new();
        try!(lzw::encode(indices, LsbWriter::new(&mut encoded_data), code_size));
        try!(w.write_all(&[code_size]));
        for chunk in encoded_data.chunks(255) {
            try!(w.write_all(&[(chunk.len()) as u8]));
            try!(w.write_all(chunk));
        }
        w.write_all(&[0]) // block terminator

    }

    /// Writes the image to the file assuming that every pixel is in the color table
    /// If not, the index of the transparent pixel is written
    fn write_image_simple<W: Write>(&mut self,
                                     w: &mut W,
                                     hist: &[(Rgba<u8>, usize)],
                                     transparent: Option<usize>,
                                    ) -> io::Result<()>
    {
        let t_idx = match transparent { Some(i) => i as u8, None => 0 };
        let data: Vec<u8> = self.image.pixels().map(|p| {
            if let Some(idx) = hist.iter().position(|x| x.0 == *p) {
                idx as u8
            } else {
                t_idx
            }
        }).collect();
        self.write_indices(w, &data)

    }

    /// Writes the image as a true color image by splitting the colors
    /// over several frames
    fn write_true_color<W: Write>(&mut self,
                                   w: &mut W,
                                   hist: Vec<(Rgba<u8>, usize)>,
                                   transparent: Option<usize>
                                  ) -> io::Result<()>
    {
        let mut hist = hist;
        // Remove transparent idx
        if let Some(transparent) = transparent {
            let _ = hist.swap_remove(transparent);
        }
        let transparent = Some(0);
        // Calculating the indices is expensive so just do it once
        let indices: Vec<u32> = self.image.pixels().map(|p| {
            if let Some(idx) = hist.iter().position(|x| x.0 == *p) {
                idx as u32
            } else {
                0
            }
        }).collect();
        let mut chunk_indices = Vec::with_capacity(
            self.image.width() as usize * self.image.height() as usize
        );
        // starting from 1 since we inject the transparent color in every frame
        for (j, chunk) in hist.chunks(255).enumerate() {
            // Now we can reuse the indices for every subimage
            // if the substract j*255 from each an replace it with 0 if it gets negative
            chunk_indices.clear();
            for &idx in indices.iter() {
                let i: i64 = idx as i64 - j as i64*255;
                chunk_indices.push(if i < 0 || i > 255 { 0 } else { i as u8 + 1 })
            }
            // Write local color table
            let num_local_colors = chunk.len() + 1;
            let n = flag_n(num_local_colors);
            try!(self.write_control_ext(w, 0, transparent));
            try!(self.write_descriptor(w, Some(num_local_colors)));
            // Inject transparent color
            try!(w.write_all(&TRANSPARENT.channels()[..3]));
            for &(color, _) in chunk.iter() {
                try!(w.write_all(&color.channels()[..3]));
            }
            // waste some space as of gif spec
            for _ in 0..((2 << n) - num_local_colors) {
                try!(w.write_all(&[0, 0, 0]));
            }
            // write indices
            try!(self.write_indices(w, &chunk_indices));
        }
        Ok(())
    }
    /// Writes the image as a true color image by splitting the colors
    /// over several frames
    fn write_indexed_colors<W: Write>(&mut self, w: &mut W, n: u8) -> io::Result<()> {
        if n < 64 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                &format!("Unsupported number of colors: {} < 64", n)[..],
            ))
        }
        let nq = nq::NeuQuant::new(3, 256, &self.image);
        for pixel in self.image.pixels_mut() {
            nq.map_color(pixel);
        }

        let (hist, transparent) = self.histogram();
        let num_local_colors = hist.len();
        let n = flag_n(num_local_colors);
        try!(self.write_control_ext(w, 0, transparent));
        try!(self.write_descriptor(w, Some(num_local_colors)));
        for &(color, _) in hist.iter() {
            try!(w.write_all(&color.channels()[..3]));
        }
        // waste some space as of gif spec
        for _ in 0..((2 << n) - num_local_colors) {
            try!(w.write_all(&[0, 0, 0]));
        }
        self.write_image_simple(w, &hist, transparent)
    }

    /// Writes the netscape application block to set the number `n` of repetitions
    #[allow(dead_code)]
    fn write_nab<W: Write>(&mut self, w: &mut W, n: u16) -> io::Result<()> {
        try!(w.write_all(&[Block::Extension as u8]));
        try!(w.write_all(&[Extension::Application as u8]));
        try!(w.write_all(&[0x0B])); // size
        try!(w.write_all(b"NETSCAPE2.0"));
        try!(w.write_all(&[0x03])); // sub-block size
        try!(w.write_all(&[0x01])); // sub-block id
        try!(w.write_u16::<LittleEndian>(n));
        w.write_all(&[0]) // terminator
    }
}

// Color table len converted to flag bits
fn flag_n(size: usize) -> u8 {
    match size {
        0  ...2   => 0,
        3  ...4   => 1,
        5  ...8   => 2,
        7  ...16  => 3,
        17 ...32  => 4,
        33 ...64  => 5,
        65 ...128 => 6,
        129...256 => 7,
        _ => 7
    }
}
<commit_msg>Typo in docs<commit_after>use std::ops::{Deref, DerefMut};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

use std::io;
use std::io::Write;
use byteorder::{WriteBytesExt, LittleEndian};

use buffer::{ImageBuffer, Pixel};
use color::{Rgb, Rgba};
use utils::lzw;
use utils::bitstream::LsbWriter;
use imageops::ColorMap;

use super::{Extension, Block, DisposalMethod};

use math::nq;

#[derive(Debug, Clone, Copy)]
#[allow(unused_qualifications)]
/// The color mode the encoder will use to encode the image.
pub enum ColorMode {
    /// Image will be encoded in multiple frames if more than 256 colors are present
    TrueColor,
    /// Image will be reduced to `64 < = n <= 256` colors
    Indexed(u8),
}
use self::ColorMode::{TrueColor, Indexed};

/// A GIF encoder.
///
/// Encodes the image either in true color using indexed colors.
/// If the mode is set to TrueColor the image is split into multiple frames
/// when the number of colors including transparent color exceeds 256.
/// Pixels with an alpha value != 1.0 will be set to alpha = 0.
pub struct Encoder<Image> {
    image: Image,
    bg_color: Option<Rgb<u8>>,
    color_mode: ColorMode
}

const TRANSPARENT: Rgba<u8> = Rgba {data: [0, 0, 0, 0]};

impl<Container> Encoder<ImageBuffer<Rgba<u8>, Container>>
where Container: Deref<Target=[u8]> + DerefMut {
    /// Creates a new GIF encoder
    pub fn new(image: ImageBuffer<Rgba<u8>, Container>,
               bg_color: Option<Rgb<u8>>,
               color_mode: ColorMode,
              ) -> Encoder<ImageBuffer<Rgba<u8>, Container>> {
        Encoder {
            image: image,
            bg_color: bg_color,
            color_mode: color_mode
        }
    }

    /// Encodes the image
    pub fn encode<W: Write>(&mut self, w: &mut W) -> io::Result<()> {
        use std::u16;
        // Header
        try!(w.write_all(b"GIF89a"));
        // Logical screen descriptor
        let height = self.image.height();
        let width = self.image.width();
        if width > u16::MAX as u32 ||
           height > u16::MAX as u32 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Image dimensions are too large for the gif format.",
            ))
        }
        try!(w.write_u16::<LittleEndian>(width as u16));
        try!(w.write_u16::<LittleEndian>(height as u16));

        let (hist, transparent) = self.histogram();
        let num_colors = hist.len();

        try!(self.write_global_table(w, &hist));

        match self.color_mode {
            // Global color table has been written, just write the image data now
            TrueColor if num_colors <= 256 => {
                // NOTE: copy paste any changes to case: Indexed(n) if n as usize <= num_colors
                try!(self.write_control_ext(w, 0, transparent));
                try!(self.write_descriptor(w, None));
                try!(self.write_image_simple(w, &hist, transparent));
            },
            TrueColor => {
                try!(self.write_true_color(w, hist, transparent));
            },
            Indexed(n) if n as usize <= num_colors && num_colors <= 256 => {
                // NOTE: copy paste from case: TrueColor if num_colors <= 256
                try!(self.write_control_ext(w, 0, transparent));
                try!(self.write_descriptor(w, None));
                try!(self.write_image_simple(w, &hist, transparent));
            }
            Indexed(n) => {
                try!(self.write_indexed_colors(w, n))
            }

        }
        w.write_all(&[Block::Trailer as u8])
    }

    /// Returns a histogram of the colors in the image
    fn histogram(&self) -> (Vec<(Rgba<u8>, usize)>, Option<usize>){
        let mut hist: HashMap<_, usize> = HashMap::new();
        // Add bg_color to table
        if let Some(bg_color) = self.bg_color {
            let _ = hist.insert(bg_color.to_rgba(), 0);
        }
        for p in self.image.pixels() {
            let mut p = *p;
            // Replace transparent pixels with black, alpha = 0
            if let Some(bg_color) = self.bg_color {
                p.blend(&bg_color.to_rgba())
            // do not use 255 as a limit there could be rounding error etc.
            // thus take 250 to give it some security margin.
            } else if p[3] < 250 {
                p = TRANSPARENT;
            }
            match hist.entry(p) {
                Occupied(mut entry) => {
                    let val = entry.get_mut();
                    *val = *val + 1;
                },
                Vacant(entry) => {
                    entry.insert(1);
                }
            }
        }
        let mut colors: Vec<(Rgba<u8>, usize)> = hist.into_iter().collect();
        // Sort color map with decreasing color freqs
        colors.sort_by(|a, b| b.1.cmp(&a.1));
        // Add bg_color to table
        let transparent = colors.iter().position(|x| x.0 == TRANSPARENT);
        (colors, transparent)
    }

    /// Write the global color table and the corresponding flags
    fn write_global_table<W: Write>(&mut self,
                                     w: &mut W,
                                     hist: &[(Rgba<u8>, usize)]
                                    ) -> io::Result<()>
    {
        let num_colors = hist.len();
        let mut flags = 0;
        flags |= 1 << 4; // sort flag
        let n = flag_n(num_colors);
        flags |= n << 4; // 2^(n+1) colors
        let (global_table, bg_index) = if num_colors <= 256 {
            flags |= 1 << 7; // glocal table flag
            flags |= n;
            let mut bg_index = 0;
            let mut table = Vec::with_capacity(3*(2 << n));
            for (i, &(color, _)) in hist.iter().enumerate() {
                let channels = &color.channels()[..3];
                if let Some(bg_color) = self.bg_color {
                    if channels == bg_color.channels() {
                        bg_index = i;
                    }
                }
                table.extend(channels.iter().map(|&c| c))
            }
            // Waste some space as of gif spec
            for _ in 0..((2 << n) - num_colors) {
                table.extend([0, 0, 0].iter().map(|&c| c));
            }
            (Some(table), bg_index as u8)
        } else if let Some(bg_color) = self.bg_color {
            flags |= 1 << 7; // glocal table flag
            let mut table = Vec::with_capacity(6);
            table.extend(bg_color.channels().iter().take(3).map(|&c| c));
            table.extend([0, 0, 0].iter().map(|&c| c));
            (Some(table), 0)
        } else {
            (None, 0)
        };
        try!(w.write_all(&[flags]));
        try!(w.write_all(&[bg_index]));
        try!(w.write_all(&[0])); // aspect ration, disregard
        if let Some(global_table) = global_table {
            try!(w.write_all(&global_table));
        }
        Ok(())
    }

    /// Writes the graphics control extension
    fn write_control_ext<W: Write>(&mut self,
                                    w: &mut W,
                                    delay: u16,
                                    transparent: Option<usize>
                                   ) -> io::Result<()>
    {
        try!(w.write_all(&[Block::Extension as u8]));
        try!(w.write_all(&[Extension::Control as u8]));
        try!(w.write_all(&[4])); // size
        let mut field = 0;
        field |= (DisposalMethod::None as u8) << 2;
        let idx = if let Some(idx) = transparent {
            field |=  1;
            idx as u8
        } else {
            0
        };
        try!(w.write_all(&[field]));
        try!(w.write_u16::<LittleEndian>(delay));
        try!(w.write_all(&[idx]));
        w.write_all(&[0])
    }

    /// Writes the image descriptor
    fn write_descriptor<W: Write>(&mut self,
                                   w: &mut W,
                                   table_len: Option<usize>
                                  ) -> io::Result<()>
    {
        try!(w.write_all(&[Block::Image as u8]));
        try!(w.write_u16::<LittleEndian>(0)); // left
        try!(w.write_u16::<LittleEndian>(0)); // top
        let height = self.image.height();
        let width = self.image.width();
        try!(w.write_u16::<LittleEndian>(width as u16));
        try!(w.write_u16::<LittleEndian>(height as u16));
        if let Some(len) = table_len {
            w.write_all(&[flag_n(len) | 0x80])
        } else {
            w.write_all(&[0])
        }
    }

    /// Writes and compresses the indexed data
    fn write_indices<W: Write>(&mut self,
                                w: &mut W,
                                indices: &[u8],
                               ) -> io::Result<()>
    {
        let code_size = match flag_n(indices.len()) + 1 {
            1 => 2,
            n => n
        };
        let mut encoded_data = Vec::new();
        try!(lzw::encode(indices, LsbWriter::new(&mut encoded_data), code_size));
        try!(w.write_all(&[code_size]));
        for chunk in encoded_data.chunks(255) {
            try!(w.write_all(&[(chunk.len()) as u8]));
            try!(w.write_all(chunk));
        }
        w.write_all(&[0]) // block terminator

    }

    /// Writes the image to the file assuming that every pixel is in the color table
    /// If not, the index of the transparent pixel is written
    fn write_image_simple<W: Write>(&mut self,
                                     w: &mut W,
                                     hist: &[(Rgba<u8>, usize)],
                                     transparent: Option<usize>,
                                    ) -> io::Result<()>
    {
        let t_idx = match transparent { Some(i) => i as u8, None => 0 };
        let data: Vec<u8> = self.image.pixels().map(|p| {
            if let Some(idx) = hist.iter().position(|x| x.0 == *p) {
                idx as u8
            } else {
                t_idx
            }
        }).collect();
        self.write_indices(w, &data)

    }

    /// Writes the image as a true color image by splitting the colors
    /// over several frames
    fn write_true_color<W: Write>(&mut self,
                                   w: &mut W,
                                   hist: Vec<(Rgba<u8>, usize)>,
                                   transparent: Option<usize>
                                  ) -> io::Result<()>
    {
        let mut hist = hist;
        // Remove transparent idx
        if let Some(transparent) = transparent {
            let _ = hist.swap_remove(transparent);
        }
        let transparent = Some(0);
        // Calculating the indices is expensive so just do it once
        let indices: Vec<u32> = self.image.pixels().map(|p| {
            if let Some(idx) = hist.iter().position(|x| x.0 == *p) {
                idx as u32
            } else {
                0
            }
        }).collect();
        let mut chunk_indices = Vec::with_capacity(
            self.image.width() as usize * self.image.height() as usize
        );
        // starting from 1 since we inject the transparent color in every frame
        for (j, chunk) in hist.chunks(255).enumerate() {
            // Now we can reuse the indices for every subimage
            // if the substract j*255 from each an replace it with 0 if it gets negative
            chunk_indices.clear();
            for &idx in indices.iter() {
                let i: i64 = idx as i64 - j as i64*255;
                chunk_indices.push(if i < 0 || i > 255 { 0 } else { i as u8 + 1 })
            }
            // Write local color table
            let num_local_colors = chunk.len() + 1;
            let n = flag_n(num_local_colors);
            try!(self.write_control_ext(w, 0, transparent));
            try!(self.write_descriptor(w, Some(num_local_colors)));
            // Inject transparent color
            try!(w.write_all(&TRANSPARENT.channels()[..3]));
            for &(color, _) in chunk.iter() {
                try!(w.write_all(&color.channels()[..3]));
            }
            // waste some space as of gif spec
            for _ in 0..((2 << n) - num_local_colors) {
                try!(w.write_all(&[0, 0, 0]));
            }
            // write indices
            try!(self.write_indices(w, &chunk_indices));
        }
        Ok(())
    }
    /// Writes the image as a true color image by splitting the colors
    /// over several frames
    fn write_indexed_colors<W: Write>(&mut self, w: &mut W, n: u8) -> io::Result<()> {
        if n < 64 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                &format!("Unsupported number of colors: {} < 64", n)[..],
            ))
        }
        let nq = nq::NeuQuant::new(3, 256, &self.image);
        for pixel in self.image.pixels_mut() {
            nq.map_color(pixel);
        }

        let (hist, transparent) = self.histogram();
        let num_local_colors = hist.len();
        let n = flag_n(num_local_colors);
        try!(self.write_control_ext(w, 0, transparent));
        try!(self.write_descriptor(w, Some(num_local_colors)));
        for &(color, _) in hist.iter() {
            try!(w.write_all(&color.channels()[..3]));
        }
        // waste some space as of gif spec
        for _ in 0..((2 << n) - num_local_colors) {
            try!(w.write_all(&[0, 0, 0]));
        }
        self.write_image_simple(w, &hist, transparent)
    }

    /// Writes the netscape application block to set the number `n` of repetitions
    #[allow(dead_code)]
    fn write_nab<W: Write>(&mut self, w: &mut W, n: u16) -> io::Result<()> {
        try!(w.write_all(&[Block::Extension as u8]));
        try!(w.write_all(&[Extension::Application as u8]));
        try!(w.write_all(&[0x0B])); // size
        try!(w.write_all(b"NETSCAPE2.0"));
        try!(w.write_all(&[0x03])); // sub-block size
        try!(w.write_all(&[0x01])); // sub-block id
        try!(w.write_u16::<LittleEndian>(n));
        w.write_all(&[0]) // terminator
    }
}

// Color table len converted to flag bits
fn flag_n(size: usize) -> u8 {
    match size {
        0  ...2   => 0,
        3  ...4   => 1,
        5  ...8   => 2,
        7  ...16  => 3,
        17 ...32  => 4,
        33 ...64  => 5,
        65 ...128 => 6,
        129...256 => 7,
        _ => 7
    }
}
<|endoftext|>


<commit_before>use std;
use std::io::Read;
use gltf::v2::{ import, Root };
use gltf::v2::accessor::ComponentType;
use gltf::v2::buffer::Target;
use gltf::v2::mesh::Mode;

pub fn load_file(path: &str) {
    let root = import(path);
    match root {
        Ok(root) => {
            println!("glTF version 2.0");
            println!("{:#?}", root);
            load_box(&root);
        }
        Err(err) => {
            println!("Error: {:#?}", err);
        }
    }
}

pub fn load_box(root: &Root) {
    let buffer = &root.buffers()[0];

    // TODO!: determine base directory...
    let mut file = std::fs::File::open(format!("src/data/{}", buffer.uri)).unwrap();
    let mut buffer_contents = Vec::with_capacity(buffer.byte_length as usize);
    file.read_to_end(&mut buffer_contents).unwrap();
    assert_eq!(buffer_contents.len(), buffer.byte_length as usize);

    let mesh = &root.meshes()[0];
    let primitive = &mesh.primitives[0];
    assert_eq!(primitive.mode, Mode::Triangles);

    let posAccessorIndex = primitive.attributes["POSITION"].value() as usize;
    let posAccessor = &root.accessors()[posAccessorIndex];
    let posBufferView = &root.buffer_views()[posAccessor.buffer_view.value() as usize];

    let positionData = &buffer_contents[
        posBufferView.byte_offset as usize .. (posBufferView.byte_offset + posBufferView.byte_length) as usize];

}
<commit_msg>WIP parse normals, indices<commit_after>use std;
use std::io::Read;
use gltf::v2::{ import, Root };
use gltf::v2::accessor::{ Accessor, ComponentType };
use gltf::v2::buffer::{ Target, BufferView};
use gltf::v2::mesh::{ Mode, Primitive };

pub fn load_file(path: &str) {
    let root = import(path);
    match root {
        Ok(root) => {
            println!("glTF version 2.0");
            // println!("{:#?}", root);
            load_box(&root);
        }
        Err(err) => {
            println!("Error: {:#?}", err);
        }
    }
}

struct PrimitiveData<'a> {
    accessor: &'a Accessor,
    buffer_view: &'a BufferView,
    data: &'a [u8],
}

pub fn load_box(root: &Root) {
    let buffer = &root.buffers()[0];

    // TODO!: determine base directory...
    let mut file = std::fs::File::open(format!("src/data/{}", buffer.uri)).unwrap();
    let mut buffer_contents = Vec::with_capacity(buffer.byte_length as usize);
    file.read_to_end(&mut buffer_contents).unwrap();
    assert_eq!(buffer_contents.len(), buffer.byte_length as usize);

    let mesh = &root.meshes()[0];
    let primitive = &mesh.primitives[0];
    assert_eq!(primitive.mode, Mode::Triangles);

    let pos_accessor_index = primitive.attributes["POSITION"].value() as usize;
    let pos_accessor = &root.accessors()[pos_accessor_index];
    let pos_buffer_view = &root.buffer_views()[pos_accessor.buffer_view.value() as usize];

    let position_data = &buffer_contents[
        pos_buffer_view.byte_offset as usize .. (pos_buffer_view.byte_offset + pos_buffer_view.byte_length) as usize];

    // TODO!: deal with no index case
    let index_accessor_index = primitive.indices.as_ref().unwrap().clone();
    let index_accessor = &root.accessor(index_accessor_index);
    let index_buffer_view = &root.buffer_view(index_accessor.buffer_view.clone());
    let index_data = &buffer_contents[
        index_buffer_view.byte_offset as usize .. (index_buffer_view.byte_offset + index_buffer_view.byte_length) as usize];

    let normals_accessor_index = primitive.attributes["NORMAL"].clone();
    let normals_accessor = &root.accessor(normals_accessor_index);
    let normal_buffer_view = &root.buffer_view(index_accessor.buffer_view.clone());
    let normal_data = &buffer_contents[
        normal_buffer_view.byte_offset as usize .. (normal_buffer_view.byte_offset + normal_buffer_view.byte_length) as usize
    ];

    println!("pos len: {}", position_data.len());
    println!("idx len: {}", index_data.len());
}

// fn get_attribute_data(root: &Root, buffer_data: &[u8], primitive: &Primitive, attribute_name: &str) {
//     let accessor = &root.accessor(primitive)
// }<|endoftext|>


<commit_before>use std::rc::Rc;

use grid::Grid;
use cell::Cell;

const NEIGHBORS_COUNT: usize = 8;

type Neighbors<C> = [Option<Rc<C>>; NEIGHBORS_COUNT];

pub struct SquareGrid<C: Cell> {
    cells: Vec<Rc<C>>,
    neighbors: Vec<Neighbors<C>>,
    rows: usize,
    cols: usize
}

impl<C: Cell + Clone> SquareGrid<C> {

    pub fn new(rows: usize, cols: usize, initial: C) -> Self {

        let len = rows * cols;
        let cells = vec![Rc::new(initial); len];
        let neighbors = Vec::with_capacity(len);

        let mut grid = SquareGrid {
            cells: cells,
            neighbors: neighbors,
            rows: rows,
            cols: cols
        };
        grid.init_neighbors();

        grid
    }

    /// 0 | 1 | 2
    /// 3 | x | 4
    /// 5 | 6 | 7
    fn init_neighbors(&mut self) {

        let len = self.cells.len() as i32;
        let cols = self.cols as i32;

        for (offset, cell) in self.cells.iter().enumerate() {

            for serial in 0 .. NEIGHBORS_COUNT {

                let neighbor_index: i32;

                {
                    let offset = offset as i32;
                    let serial = serial as i32;

                    neighbor_index = match serial {
                        i @ 0 ... 2 => offset - cols - (i - 1),
                        3 => offset - 1,
                        4 => offset + 1,
                        i @ 5 ... 7 => offset + cols - (i - 1),
                        // such values will be ignored later
                        _ => len
                    };
                }

                if neighbor_index >= 0 && neighbor_index < len {
                    self.neighbors[offset][serial] = Some(cell.clone());
                }
                else {
                    self.neighbors[offset][serial] = None;
                }
            }
        }
    }
}

impl<C: Cell> Grid for SquareGrid<C> {
    fn step(&self) {}
}
<commit_msg>Name shows neighborhood type.<commit_after>use std::rc::Rc;

use grid::Grid;
use cell::Cell;

const NEIGHBORS_COUNT: usize = 8;

type Neighbors<C> = [Option<Rc<C>>; NEIGHBORS_COUNT];

pub struct MooreSquareGrid<C: Cell> {
    cells: Vec<Rc<C>>,
    neighbors: Vec<Neighbors<C>>,
    rows: usize,
    cols: usize
}

impl<C: Cell + Clone> MooreSquareGrid<C> {

    pub fn new(rows: usize, cols: usize, initial: C) -> Self {

        let len = rows * cols;
        let cells = vec![Rc::new(initial); len];
        let neighbors = Vec::with_capacity(len);

        let mut grid = MooreSquareGrid {
            cells: cells,
            neighbors: neighbors,
            rows: rows,
            cols: cols
        };
        grid.init_neighbors();

        grid
    }

    /// 0 | 1 | 2
    /// 3 | x | 4
    /// 5 | 6 | 7
    fn init_neighbors(&mut self) {

        let len = self.cells.len() as i32;
        let cols = self.cols as i32;

        for (offset, cell) in self.cells.iter().enumerate() {

            for serial in 0 .. NEIGHBORS_COUNT {

                let neighbor_index: i32;

                {
                    let offset = offset as i32;
                    let serial = serial as i32;

                    neighbor_index = match serial {
                        i @ 0 ... 2 => offset - cols - (i - 1),
                        3 => offset - 1,
                        4 => offset + 1,
                        i @ 5 ... 7 => offset + cols - (i - 1),
                        // such values will be ignored later
                        _ => len
                    };
                }

                if neighbor_index >= 0 && neighbor_index < len {
                    self.neighbors[offset][serial] = Some(cell.clone());
                }
                else {
                    self.neighbors[offset][serial] = None;
                }
            }
        }
    }
}

impl<C: Cell> Grid for MooreSquareGrid<C> {
    fn step(&self) {}
}
<|endoftext|>


<commit_before>// need to raise recursion limit because many combinators
#![recursion_limit = "128"]
#![deny(bare_trait_objects)]

use std::time::Duration;

use futures::{future, future::lazy, Future, Stream};
use log::{debug, error, info, warn};

use gerritbot_gerrit as gerrit;
use gerritbot_spark as spark;
use gerritbot as bot;
use gerritbot::args as args;

/// Create spark message stream. Returns a future representing a webhook server
/// and a stream of messages.
fn create_spark_message_stream(
    spark_config: args::SparkConfig,
    spark_client: spark::Client,
) -> (
    impl Future<Item = (), Error = ()>,
    Box<dyn Stream<Item = spark::Message, Error = ()> + Send>,
) {
    match spark_config.mode {
        args::ModeConfig::Direct {
            endpoint: listen_address,
        } => {
            let spark::WebhookServer { server, messages } =
                spark::start_webhook_server(&listen_address, spark_client);
            (
                future::Either::A(server.map_err(|e| error!("webhook server error: {}", e))),
                Box::new(messages),
            )
        }
        args::ModeConfig::Sqs { uri, region } => (
            future::Either::B(future::empty()),
            Box::new(spark::sqs_event_stream(uri, region, spark_client)),
        ),
    }
}

fn main() {
    let args = args::parse_args();
    stderrlog::new()
        .module(module_path!())
        .module("gerritbot_gerrit")
        .module("gerritbot_spark")
        .quiet(args.quiet)
        .timestamp(stderrlog::Timestamp::Second)
        .verbosity(if args.verbose { 5 } else { 2 })
        .init()
        .unwrap();
    let args::Config {
        gerrit: gerrit_config,
        bot: bot_config,
        spark: spark_config,
    } = args::parse_config(args.config);

    // load or create a new bot
    let bot_state = bot::State::load("state.json")
        .map(|state| {
            info!(
                "Loaded bot from 'state.json' with {} user(s).",
                state.num_users()
            );
            state
        })
        .unwrap_or_else(|err| {
            warn!("Could not load bot from 'state.json': {:?}", err);
            bot::State::new()
        });

    let bot_builder = bot::Builder::new(bot_state);
    let bot_builder = {
        if bot_config.msg_expiration != 0 && bot_config.msg_capacity != 0 {
            debug!(
                "Approval LRU cache: capacity - {}, expiration - {} sec",
                bot_config.msg_capacity, bot_config.msg_expiration
            );
            bot_builder.with_msg_cache(
                bot_config.msg_capacity,
                Duration::from_secs(bot_config.msg_expiration),
            )
        } else {
            bot_builder
        }
    };
    let connect_to_gerrit = || {
        info!(
            "Connecting to gerrit with username {} at {}",
            gerrit_config.username, gerrit_config.host
        );
        gerrit::Connection::connect(
            gerrit_config.host.clone(),
            gerrit_config.username.clone(),
            gerrit_config.priv_key_path.clone(),
        )
        .unwrap_or_else(|e| {
            error!("failed to connect to gerrit: {}", e);
            std::process::exit(1);
        })
    };
    let gerrit_event_stream = gerrit::extended_event_stream(
        connect_to_gerrit(),
        connect_to_gerrit(),
        bot::request_extended_gerrit_info,
    );
    let gerrit_command_runner = gerrit::CommandRunner::new(connect_to_gerrit());

    // run rest of the logic while the tokio runtime is running
    tokio::run(lazy(move || {
        let webhook_url = spark_config.webhook_url.clone();

        spark::Client::new(spark_config.api_uri.clone(), spark_config.bot_token.clone())
            .map_err(|e| error!("failed to create spark client: {}", e))
            .and_then(move |client| {
                info!("created spark client: {}", client.id());

                let next_client = client.clone();

                client
                    .register_webhook(&webhook_url)
                    .map_err(|e| error!("failed to register webhook: {}", e))
                    .map(move |()| next_client)
            })
            .and_then(move |spark_client| {
                let (spark_webhook_server, spark_messages) =
                    create_spark_message_stream(spark_config.clone(), spark_client.clone());

                let bot = bot_builder.build(gerrit_command_runner, spark_client);

                fn ignore<T>(_: T) {}

                // run webhook server or bot to completion - they should never
                // exit unless there's an error, in which case they should print
                // that
                spark_webhook_server
                    .select(bot.run(gerrit_event_stream, spark_messages))
                    .map(ignore)
                    .map_err(ignore)
            })
    }))
}
<commit_msg>always print error messages<commit_after>// need to raise recursion limit because many combinators
#![recursion_limit = "128"]
#![deny(bare_trait_objects)]

use std::time::Duration;

use futures::{future, future::lazy, Future, Stream};
use log::{debug, error, info, warn};

use gerritbot_gerrit as gerrit;
use gerritbot_spark as spark;
use gerritbot as bot;
use gerritbot::args as args;

/// Create spark message stream. Returns a future representing a webhook server
/// and a stream of messages.
fn create_spark_message_stream(
    spark_config: args::SparkConfig,
    spark_client: spark::Client,
) -> (
    impl Future<Item = (), Error = ()>,
    Box<dyn Stream<Item = spark::Message, Error = ()> + Send>,
) {
    match spark_config.mode {
        args::ModeConfig::Direct {
            endpoint: listen_address,
        } => {
            let spark::WebhookServer { server, messages } =
                spark::start_webhook_server(&listen_address, spark_client);
            (
                future::Either::A(server.map_err(|e| error!("webhook server error: {}", e))),
                Box::new(messages),
            )
        }
        args::ModeConfig::Sqs { uri, region } => (
            future::Either::B(future::empty()),
            Box::new(spark::sqs_event_stream(uri, region, spark_client)),
        ),
    }
}

fn main() {
    let args = args::parse_args();
    stderrlog::new()
        .module(module_path!())
        .module("gerritbot_gerrit")
        .module("gerritbot_spark")
        .timestamp(stderrlog::Timestamp::Second)
        .verbosity(match (args.quiet, args.verbose) {
            (true, _) => 0,      // ERROR
            (false, false) => 2, // INFO
            (_, true) => 4,      // TRACE
        })
        .init()
        .unwrap();
    let args::Config {
        gerrit: gerrit_config,
        bot: bot_config,
        spark: spark_config,
    } = args::parse_config(args.config);

    // load or create a new bot
    let bot_state = bot::State::load("state.json")
        .map(|state| {
            info!(
                "Loaded bot from 'state.json' with {} user(s).",
                state.num_users()
            );
            state
        })
        .unwrap_or_else(|err| {
            warn!("Could not load bot from 'state.json': {:?}", err);
            bot::State::new()
        });

    let bot_builder = bot::Builder::new(bot_state);
    let bot_builder = {
        if bot_config.msg_expiration != 0 && bot_config.msg_capacity != 0 {
            debug!(
                "Approval LRU cache: capacity - {}, expiration - {} sec",
                bot_config.msg_capacity, bot_config.msg_expiration
            );
            bot_builder.with_msg_cache(
                bot_config.msg_capacity,
                Duration::from_secs(bot_config.msg_expiration),
            )
        } else {
            bot_builder
        }
    };
    let connect_to_gerrit = || {
        info!(
            "Connecting to gerrit with username {} at {}",
            gerrit_config.username, gerrit_config.host
        );
        gerrit::Connection::connect(
            gerrit_config.host.clone(),
            gerrit_config.username.clone(),
            gerrit_config.priv_key_path.clone(),
        )
        .unwrap_or_else(|e| {
            error!("failed to connect to gerrit: {}", e);
            std::process::exit(1);
        })
    };
    let gerrit_event_stream = gerrit::extended_event_stream(
        connect_to_gerrit(),
        connect_to_gerrit(),
        bot::request_extended_gerrit_info,
    );
    let gerrit_command_runner = gerrit::CommandRunner::new(connect_to_gerrit());

    // run rest of the logic while the tokio runtime is running
    tokio::run(lazy(move || {
        let webhook_url = spark_config.webhook_url.clone();

        spark::Client::new(spark_config.api_uri.clone(), spark_config.bot_token.clone())
            .map_err(|e| error!("failed to create spark client: {}", e))
            .and_then(move |client| {
                info!("created spark client: {}", client.id());

                let next_client = client.clone();

                client
                    .register_webhook(&webhook_url)
                    .map_err(|e| error!("failed to register webhook: {}", e))
                    .map(move |()| next_client)
            })
            .and_then(move |spark_client| {
                let (spark_webhook_server, spark_messages) =
                    create_spark_message_stream(spark_config.clone(), spark_client.clone());

                let bot = bot_builder.build(gerrit_command_runner, spark_client);

                fn ignore<T>(_: T) {}

                // run webhook server or bot to completion - they should never
                // exit unless there's an error, in which case they should print
                // that
                spark_webhook_server
                    .select(bot.run(gerrit_event_stream, spark_messages))
                    .map(ignore)
                    .map_err(ignore)
            })
    }))
}
<|endoftext|>