<commit_before>extern crate libc;

use libc::c_void;

// Rusty Section

/// Represents how memory is mapped for a `Device`
///
/// Different devices present different types of memory; devices intended just to be used
/// as RAM will be mapped to memory differently than devices which provide I/O.
#[repr(C)]
#[derive(Copy, Clone)]
pub enum MappedMemoryType {
    /// No memory will be mapped for the device.
    None = 0,
    /// Memory will be mapped for the device, and it will be mapped in the RAM section of
    /// system memory.
    Ram = 1,
    /// Memory will be mapped for the device, and it will be mapped in the I/O Devices
    /// section of system memory.
    IODevice = 2,
}

/// Represents a device handled by a motherboard
///
/// All of the device functions supplied should return an error code if they fail. However
/// this should only be used for signaling the motherboard of invalid *simulator*
/// behavior. Invalid behavior of a *simulated* part should be handled through in-sim
/// methods like interrupts.
///
/// # Safety
///
/// The device operation functions provided in a `Device` must be made thread-safe by the
/// implementor. The motherboard and other devices may call them freely in a
/// multi-threaded environment.
///
/// The `load_*` functions take a pointer to the memory to place the loaded value in. To
/// comply with Rust's ownership semantics, the actual implementation must not hold on to
/// this pointer past the lifetime of the function.
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(raw_pointer_derive)]
pub struct Device {
    /// Pointer to the actual underlying device being operated on.
    pub device: *mut c_void,

    /// Indicated whether memory mapping should be done for this device, and what type of
    /// mapping should be used.
    pub export_memory: MappedMemoryType,
    /// Indicates the size of exported memory
    pub export_memory_size: u32,
    // Device, Address, Destination/Source
    /// Function to load a byte from the device's memory.
    pub load_byte: Option<extern fn(*mut c_void, u32, *mut u8) -> i32>,
    /// Function to load a word from the device's memory.
    pub load_word: Option<extern fn(*mut c_void, u32, *mut u16) -> i32>,
    /// Function to load a dword from the device's memory.
    pub load_dword: Option<extern fn(*mut c_void, u32, *mut u32) -> i32>,
    /// Function to load a qword from the device's memory.
    pub load_qword: Option<extern fn(*mut c_void, u32, *mut u64) -> i64>,
    /// Function to save a byte to the device's memory.
    pub write_byte: Option<extern fn(*mut c_void, u32, u8) -> i32>,
    /// Function to save a word to the device's memory.
    pub write_word: Option<extern fn(*mut c_void, u32, u16) -> i32>,
    /// Function to save a dword to the device's memory.
    pub write_dword: Option<extern fn(*mut c_void, u32, u32) -> i32>,
    /// Function to save a qword to the device's memory.
    pub write_qword: Option<extern fn(*mut c_void, u32, u64) -> i32>,

    // Device
    /// Function to use to initialize the device before booting.
    pub init: Option<extern fn(*mut c_void) -> i32>,

    // Device
    /// Optional function to use to boot the device.
    pub boot: Option<extern fn(*mut c_void) -> i32>,

    // Device, Interrupt Code
    /// Optional function to use to send an interrupt code to the device.
    pub interrupt: Option<extern fn(*mut c_void, u32) -> i32>,

    // Device, Motherboard, Motherboard Functions
    /// Registers the motherboard's functions with this device
    pub register_motherboard: Option<extern fn(
        *mut c_void, *mut Motherboard, *mut MotherboardFunctions) -> i32>,
}

/// Struct for passing the motherboard's function collection to modules.
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(raw_pointer_derive)]
pub struct MotherboardFunctions {
    // Motherboard, Address, Destination.
    /// Callback for a device to read a byte of memory.
    pub read_byte: Option<extern fn(*mut Motherboard, u64, *mut u8) -> i32>,
    /// Callback for a device to read a word of memory.
    pub read_word: Option<extern fn(*mut Motherboard, u64, *mut u16) -> i32>,
    /// Callback for a device to read a dword of memory.
    pub read_dword: Option<extern fn(*mut Motherboard, u64, *mut u32) -> i32>,
    /// Callback for a device to read a qword of memory.
    pub read_qword: Option<extern fn(*mut Motherboard, u64, *mut u64) -> i32>,

    // Motherboard, Address, Source.
    /// Callback for a device to write a byte of memory.
    pub write_byte: Option<extern fn(*mut Motherboard, u64, u8) -> i32>,
    /// Callback for a device to write a word of memory.
    pub write_word: Option<extern fn(*mut Motherboard, u64, u16) -> i32>,
    /// Callback for a device to write a dword of memory.
    pub write_dword: Option<extern fn(*mut Motherboard, u64, u32) -> i32>,
    /// Callback for a device to write a qword of memory.
    pub write_qword: Option<extern fn(*mut Motherboard, u64, u64) -> i32>,

    // Motherboard, Target Device, Interrupt Code.
    /// Callback for a device to send an interrupt to another device.
    pub send_interrupt: Option<extern fn(*mut Motherboard, u32, u32) -> i32>,
}

/// Represents a motherboard in the bridgesim computer.
///
/// The motherboard has a fixed set of spaces for `Device` objects, which are anything
/// which can do or hold something. The motherboard is the core of the bridgesim computer
/// and is responsible for booting attached devices and memory access control.
pub struct Motherboard {
    devices: Vec<Device>,
}

impl Motherboard {
    /// Constructs a new `Motherboard` with space for `max_devices` devices.
    fn new(max_devices: usize) -> Motherboard {
        Motherboard {
            devices: Vec::with_capacity(max_devices),
        }
    }

    /// The number of slots this motherboard has
    fn num_slots(&self) -> usize {
        self.devices.capacity()
    }

    /// The number of slots filled on this motherboard
    fn slots_filled(&self) -> usize {
        self.devices.len()
    }

    /// Whether or not the motherboard of the device is filled.
    fn is_full(&self) -> bool {
        self.slots_filled() >= self.num_slots()
    }

    /// Adds a new device to the moherboard.
    ///
    /// # Panics
    ///
    /// This method panics if all of the motherboard expansion slots are full.
    fn add_device(&mut self, device: Device) {
        if self.is_full() {
            panic!("No expansion slots left in motherboard!");
        }
        self.devices.push(device);
    }
}

// CFFI

/// Contructs a pointer to a new `Motherboard` with `max_devices` capacity.
///
/// # Safety
///
/// This function will implicitly convert a `Box<Motherboard>` to a `void*` pointer if
/// called from C or another language. In order to make sure that this memory is
/// dealocated, it should always be passed to `bscomp_motherboard_destroy`.
#[no_mangle]
pub extern fn bscomp_motherboard_new(max_devices: u32) -> Box<Motherboard> {
    Box::new(Motherboard::new(max_devices as usize))
}

/// Destroys a motherboard constructed by `bscomp_motherboard_new`
///
/// Any motherboard created by this module must be passed in here to have its resources
/// released.
///
/// # Safety
///
/// This function implicitly converts a pointer to a `Box<Motherboard>`. You must ensure
/// that the pointer passed into it was initially a valid `Box<Motherboard>`, created by
/// `bscomp_motherboard_new`. Passing anything else is undefined behavior.
#[no_mangle]
pub extern fn bscomp_motherboard_destroy(mb: Box<Motherboard>) {
    drop(mb);
}

/// Gets the number of slots total in the motherboard.
///
/// # Safety
///
/// The motherboard must be a valid motherboard created with `bscomp_motherboard_new`. If
/// the motherboard is null, the result is 0. For anything else, the behavior is
/// undefined.
#[no_mangle]
pub extern fn bscomp_motherboard_num_slots(mb: *mut Motherboard) -> u32 {
    if mb.is_null() {
        0
    } else {
        unsafe { (*mb).num_slots() as u32 }
    }
}

/// Gets the number of slots filled in the motherboard.
///
/// # Safety
///
/// The motherboard must be a valid motherboard created with `bscomp_motherboard_new`. If
/// the motherboard is null, the result is 0. For anything else, the behavior is
/// undefined.
#[no_mangle]
pub extern fn bscomp_motherboard_slots_filled(mb: *mut Motherboard) -> u32 {
    if mb.is_null() {
        0
    } else {
        unsafe { (*mb).slots_filled() as u32 }
    }
}

/// Tests if all the slots on the motherboard a full.
///
/// # Safety
///
/// The motherboard must be a valid motherboard created with `bscomp_motherboard_new`. If
/// the motherboard is null, the result is 1. For anything else, the behavior is
/// undefined.
#[no_mangle]
pub extern fn bscomp_motherboard_is_full(mb: *mut Motherboard) -> i32 {
    if mb.is_null() {
        1
    } else {
        unsafe { (*mb).is_full() as i32 }
    }
}

/// Add a device to the given mother board.
///
/// Returns an error code indicating if the addition is successful. It fails if either of
/// the pointers is null or the motherboard is already full.
///
/// # Safety
///
/// The motherboard must be a motherboard allocated with `bscomp_motherboard_new`.
///
/// The device passed in will be copied, so the caller does not need to keep a pointer to
/// the device. However, it is the responsibility of the caller to enure that any function
/// pointers included in the device live longer than the motherboard.
#[no_mangle]
pub extern fn bscomp_motherboard_add_device(mb: *mut Motherboard, device: *mut Device) -> i32 {
    if mb.is_null() {
        return -1;
    }
    if device.is_null() {
        return -2;
    }

    let mb = unsafe { &mut *mb };

    if mb.is_full() {
        return -3;
    }

    let device = unsafe { &mut *device };
    mb.add_device(*device);

    return 0;
}
<commit_msg>changed motherboard add device to return a result instead of panic<commit_after>extern crate libc;

use libc::c_void;

// Rusty Section

/// Represents how memory is mapped for a `Device`
///
/// Different devices present different types of memory; devices intended just to be used
/// as RAM will be mapped to memory differently than devices which provide I/O.
#[repr(C)]
#[derive(Copy, Clone)]
pub enum MappedMemoryType {
    /// No memory will be mapped for the device.
    None = 0,
    /// Memory will be mapped for the device, and it will be mapped in the RAM section of
    /// system memory.
    Ram = 1,
    /// Memory will be mapped for the device, and it will be mapped in the I/O Devices
    /// section of system memory.
    IODevice = 2,
}

/// Represents a device handled by a motherboard
///
/// All of the device functions supplied should return an error code if they fail. However
/// this should only be used for signaling the motherboard of invalid *simulator*
/// behavior. Invalid behavior of a *simulated* part should be handled through in-sim
/// methods like interrupts.
///
/// # Safety
///
/// The device operation functions provided in a `Device` must be made thread-safe by the
/// implementor. The motherboard and other devices may call them freely in a
/// multi-threaded environment.
///
/// The `load_*` functions take a pointer to the memory to place the loaded value in. To
/// comply with Rust's ownership semantics, the actual implementation must not hold on to
/// this pointer past the lifetime of the function.
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(raw_pointer_derive)]
pub struct Device {
    /// Pointer to the actual underlying device being operated on.
    pub device: *mut c_void,

    /// Indicated whether memory mapping should be done for this device, and what type of
    /// mapping should be used.
    pub export_memory: MappedMemoryType,
    /// Indicates the size of exported memory
    pub export_memory_size: u32,
    // Device, Address, Destination/Source
    /// Function to load a byte from the device's memory.
    pub load_byte: Option<extern fn(*mut c_void, u32, *mut u8) -> i32>,
    /// Function to load a word from the device's memory.
    pub load_word: Option<extern fn(*mut c_void, u32, *mut u16) -> i32>,
    /// Function to load a dword from the device's memory.
    pub load_dword: Option<extern fn(*mut c_void, u32, *mut u32) -> i32>,
    /// Function to load a qword from the device's memory.
    pub load_qword: Option<extern fn(*mut c_void, u32, *mut u64) -> i64>,
    /// Function to save a byte to the device's memory.
    pub write_byte: Option<extern fn(*mut c_void, u32, u8) -> i32>,
    /// Function to save a word to the device's memory.
    pub write_word: Option<extern fn(*mut c_void, u32, u16) -> i32>,
    /// Function to save a dword to the device's memory.
    pub write_dword: Option<extern fn(*mut c_void, u32, u32) -> i32>,
    /// Function to save a qword to the device's memory.
    pub write_qword: Option<extern fn(*mut c_void, u32, u64) -> i32>,

    // Device
    /// Function to use to initialize the device before booting.
    pub init: Option<extern fn(*mut c_void) -> i32>,

    // Device
    /// Optional function to use to boot the device.
    pub boot: Option<extern fn(*mut c_void) -> i32>,

    // Device, Interrupt Code
    /// Optional function to use to send an interrupt code to the device.
    pub interrupt: Option<extern fn(*mut c_void, u32) -> i32>,

    // Device, Motherboard, Motherboard Functions
    /// Registers the motherboard's functions with this device
    pub register_motherboard: Option<extern fn(
        *mut c_void, *mut Motherboard, *mut MotherboardFunctions) -> i32>,
}

/// Struct for passing the motherboard's function collection to modules.
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(raw_pointer_derive)]
pub struct MotherboardFunctions {
    // Motherboard, Address, Destination.
    /// Callback for a device to read a byte of memory.
    pub read_byte: Option<extern fn(*mut Motherboard, u64, *mut u8) -> i32>,
    /// Callback for a device to read a word of memory.
    pub read_word: Option<extern fn(*mut Motherboard, u64, *mut u16) -> i32>,
    /// Callback for a device to read a dword of memory.
    pub read_dword: Option<extern fn(*mut Motherboard, u64, *mut u32) -> i32>,
    /// Callback for a device to read a qword of memory.
    pub read_qword: Option<extern fn(*mut Motherboard, u64, *mut u64) -> i32>,

    // Motherboard, Address, Source.
    /// Callback for a device to write a byte of memory.
    pub write_byte: Option<extern fn(*mut Motherboard, u64, u8) -> i32>,
    /// Callback for a device to write a word of memory.
    pub write_word: Option<extern fn(*mut Motherboard, u64, u16) -> i32>,
    /// Callback for a device to write a dword of memory.
    pub write_dword: Option<extern fn(*mut Motherboard, u64, u32) -> i32>,
    /// Callback for a device to write a qword of memory.
    pub write_qword: Option<extern fn(*mut Motherboard, u64, u64) -> i32>,

    // Motherboard, Target Device, Interrupt Code.
    /// Callback for a device to send an interrupt to another device.
    pub send_interrupt: Option<extern fn(*mut Motherboard, u32, u32) -> i32>,
}

/// Represents a motherboard in the bridgesim computer.
///
/// The motherboard has a fixed set of spaces for `Device` objects, which are anything
/// which can do or hold something. The motherboard is the core of the bridgesim computer
/// and is responsible for booting attached devices and memory access control.
pub struct Motherboard {
    devices: Vec<Device>,
}

impl Motherboard {
    /// Constructs a new `Motherboard` with space for `max_devices` devices.
    fn new(max_devices: usize) -> Motherboard {
        Motherboard {
            devices: Vec::with_capacity(max_devices),
        }
    }

    /// The number of slots this motherboard has
    fn num_slots(&self) -> usize {
        self.devices.capacity()
    }

    /// The number of slots filled on this motherboard
    fn slots_filled(&self) -> usize {
        self.devices.len()
    }

    /// Whether or not the motherboard of the device is filled.
    fn is_full(&self) -> bool {
        self.slots_filled() >= self.num_slots()
    }

    /// Adds a new device to the moherboard.
    ///
    /// # Panics
    ///
    /// This method panics if all of the motherboard expansion slots are full.
    fn add_device(&mut self, device: Device) -> Result<(), &'static str>{
        if self.is_full() {
            Err("Cannot add device. Motherboard is full.")
        } else {
            self.devices.push(device);
            Ok(())
        }
    }
}

// CFFI

/// Contructs a pointer to a new `Motherboard` with `max_devices` capacity.
///
/// # Safety
///
/// This function will implicitly convert a `Box<Motherboard>` to a `void*` pointer if
/// called from C or another language. In order to make sure that this memory is
/// dealocated, it should always be passed to `bscomp_motherboard_destroy`.
#[no_mangle]
pub extern fn bscomp_motherboard_new(max_devices: u32) -> Box<Motherboard> {
    Box::new(Motherboard::new(max_devices as usize))
}

/// Destroys a motherboard constructed by `bscomp_motherboard_new`
///
/// Any motherboard created by this module must be passed in here to have its resources
/// released.
///
/// # Safety
///
/// This function implicitly converts a pointer to a `Box<Motherboard>`. You must ensure
/// that the pointer passed into it was initially a valid `Box<Motherboard>`, created by
/// `bscomp_motherboard_new`. Passing anything else is undefined behavior.
#[no_mangle]
pub extern fn bscomp_motherboard_destroy(mb: Box<Motherboard>) {
    drop(mb);
}

/// Gets the number of slots total in the motherboard.
///
/// # Safety
///
/// The motherboard must be a valid motherboard created with `bscomp_motherboard_new`. If
/// the motherboard is null, the result is 0. For anything else, the behavior is
/// undefined.
#[no_mangle]
pub extern fn bscomp_motherboard_num_slots(mb: *mut Motherboard) -> u32 {
    if mb.is_null() {
        0
    } else {
        unsafe { (*mb).num_slots() as u32 }
    }
}

/// Gets the number of slots filled in the motherboard.
///
/// # Safety
///
/// The motherboard must be a valid motherboard created with `bscomp_motherboard_new`. If
/// the motherboard is null, the result is 0. For anything else, the behavior is
/// undefined.
#[no_mangle]
pub extern fn bscomp_motherboard_slots_filled(mb: *mut Motherboard) -> u32 {
    if mb.is_null() {
        0
    } else {
        unsafe { (*mb).slots_filled() as u32 }
    }
}

/// Tests if all the slots on the motherboard a full.
///
/// # Safety
///
/// The motherboard must be a valid motherboard created with `bscomp_motherboard_new`. If
/// the motherboard is null, the result is 1. For anything else, the behavior is
/// undefined.
#[no_mangle]
pub extern fn bscomp_motherboard_is_full(mb: *mut Motherboard) -> i32 {
    if mb.is_null() {
        1
    } else {
        unsafe { (*mb).is_full() as i32 }
    }
}

/// Add a device to the given mother board.
///
/// Returns an error code indicating if the addition is successful. It fails if either of
/// the pointers is null or the motherboard is already full.
///
/// # Safety
///
/// The motherboard must be a motherboard allocated with `bscomp_motherboard_new`.
///
/// The device passed in will be copied, so the caller does not need to keep a pointer to
/// the device. However, it is the responsibility of the caller to enure that any function
/// pointers included in the device live longer than the motherboard.
#[no_mangle]
pub extern fn bscomp_motherboard_add_device(mb: *mut Motherboard, device: *mut Device) -> i32 {
    if mb.is_null() {
        return -1;
    }
    if device.is_null() {
        return -2;
    }

    let mb = unsafe { &mut *mb };
    let device = unsafe { &mut *device };

    match mb.add_device(*device) {
        Ok(_) => 0,
        Err(_) => -3,
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate rand;
extern crate rpsrtsrs;
#[cfg(feature = "include_sdl2")] extern crate sdl2_window;
#[cfg(feature = "include_glfw")] extern crate glfw_window;
#[cfg(feature = "include_glutin")] extern crate glutin_window;

use std::f64::consts::PI;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::*;
use piston::event_loop::*;
#[cfg(feature = "include_sdl2")] use sdl2_window::Sdl2Window as Window;
#[cfg(feature = "include_glfw")] use glfw_window::GlfwWindow as Window;
#[cfg(feature = "include_glutin")] use glutin_window::GlutinWindow as Window;
use rpsrtsrs::shapes::Unit;

pub struct App {
    gl: GlGraphics, // OpenGL drawing backend.
    units: Vec<Unit>,
}

impl App {
    fn select(&mut self, position: &[f64;2]) {
        for s in &mut self.units {
            s.selected = position[0]< s.position[0]+25.0 &&
                position[0]> s.position[0]-25.0 &&
                position[1]< s.position[1]+25.0 &&
                position[1]> s.position[1]-25.0;
        };
    }

    fn render(&mut self, args: &RenderArgs) {
        use graphics::{polygon, clear};
        use graphics::Transformed;
        use graphics::types::Polygon;

        const BLACK:  [f32; 4] = [0.0, 0.0,  0.0, 1.0];
        const YELLOW: [f32; 4] = [1.0, 1.0,  0.22, 1.0];
        const ORANGE: [f32; 4] = [1.0, 0.61, 0.22, 1.0];

        const UNIT_SIZE: f64 = 50.0;

        let units = &self.units;

        self.gl.draw(args.viewport(), |c, gl| {

            // Clear the screen.
            clear(BLACK, gl);

            for s in units.iter() {

                // Create a triangle polygon. The initial orientation is facing east.
                let triangle: Polygon = &[
                    [0.0, UNIT_SIZE / 2.0], // Left
                    [UNIT_SIZE, UNIT_SIZE], // Top right
                    [UNIT_SIZE, 0.0],       // Bottom right
                ];

                // Create the transoformation matrix
                let transform = c.transform.trans(s.position[0], s.position[1])
                    .rot_rad(s.rotation)
                    .trans(-25.0, -25.0);

                // Draw the unit ORANGE if selected
                if s.selected {
                    polygon(ORANGE, triangle, transform, gl);
                } else {
                    polygon(YELLOW, triangle, transform, gl);
                }

            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        for s in &mut self.units {
            let diff = [s.target[0]-s.position[0], s.target[1]-s.position[1]];
            s.position[0] += diff[0]/2.0*args.dt;
            s.position[1] += diff[1]/2.0*args.dt;
        }
    }

    fn move_selected(&mut self, position: [f64;2]) {
        for s in &mut self.units {
            if s.selected {
                s.target = position;
                let dx = position[0] - s.position[0];
                let dy = position[1] - s.position[1];
                if dx.is_sign_negative() {
                    s.rotation = (dy / dx).atan() + PI;
                } else {
                    s.rotation = (dy / dx).atan();
                }
                println!("dx: {}, dy: {}, new rotation: {}", dx, dy, s.rotation);
            }
        }
    }
}

fn main() {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let window : Window = WindowSettings::new(
        "rpsrtsrs",
        [640, 480]
    ).exit_on_esc(true).into();

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        units: vec![],
    };
    for _ in 0..10 {
        // Create new unit in random location
        let x = rand::random::<f64>() * 600.0 + 40.0;
        let y = rand::random::<f64>() * 440.0 + 40.0;
        let r = (rand::random::<f64>() - 0.5) * PI;
        let unit = Unit::new([x,y], r);

        // Register unit
        app.units.push(unit);
    }

    let mut cursor = [0.0,0.0];

    for e in window.events() {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(&cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<commit_msg>Draw a border on the front of a unit<commit_after>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate rand;
extern crate rpsrtsrs;
#[cfg(feature = "include_sdl2")] extern crate sdl2_window;
#[cfg(feature = "include_glfw")] extern crate glfw_window;
#[cfg(feature = "include_glutin")] extern crate glutin_window;

use std::f64::consts::PI;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::*;
use piston::event_loop::*;
#[cfg(feature = "include_sdl2")] use sdl2_window::Sdl2Window as Window;
#[cfg(feature = "include_glfw")] use glfw_window::GlfwWindow as Window;
#[cfg(feature = "include_glutin")] use glutin_window::GlutinWindow as Window;
use rpsrtsrs::shapes::Unit;

pub struct App {
    gl: GlGraphics, // OpenGL drawing backend.
    units: Vec<Unit>,
}

impl App {
    fn select(&mut self, position: &[f64;2]) {
        for s in &mut self.units {
            s.selected = position[0]< s.position[0]+25.0 &&
                position[0]> s.position[0]-25.0 &&
                position[1]< s.position[1]+25.0 &&
                position[1]> s.position[1]-25.0;
        };
    }

    fn render(&mut self, args: &RenderArgs) {
        use graphics::{polygon, clear};
        use graphics::Transformed;
        use graphics::types::Polygon;

        const BLACK:  [f32; 4] = [0.0, 0.0,  0.0,  1.0];
        const YELLOW: [f32; 4] = [1.0, 1.0,  0.22, 1.0];
        const ORANGE: [f32; 4] = [1.0, 0.61, 0.22, 1.0];

        const UNIT_SIZE: f64 = 50.0;
        const FRONT_THICKNESS: f64 = 5.0;

        let units = &self.units;

        self.gl.draw(args.viewport(), |c, gl| {

            // Clear the screen.
            clear(BLACK, gl);

            for s in units.iter() {

                // Create a triangle polygon. The initial orientation is facing east.
                let triangle: Polygon = &[
                    [0.0, UNIT_SIZE / 2.0], // Left
                    [UNIT_SIZE, UNIT_SIZE], // Top right
                    [UNIT_SIZE, 0.0],       // Bottom right
                ];

                // Create a border on the front of the polygon. This is a trapezoid.
                // Because the angle of the trapezoid side is 22.5°, we know that `dx` is always `2 * dy`.
                let front: Polygon = &[
                    [UNIT_SIZE, UNIT_SIZE],                                           // Top right
                    [UNIT_SIZE, 0.0],                                                 // Bottom right
                    [UNIT_SIZE - FRONT_THICKNESS, FRONT_THICKNESS / 2.0],             // Bottom left
                    [UNIT_SIZE - FRONT_THICKNESS, UNIT_SIZE - FRONT_THICKNESS / 2.0], // Top left
                ];

                // Create the transformation matrix
                let transform = c.transform.trans(s.position[0], s.position[1])
                    .rot_rad(s.rotation)
                    .trans(-25.0, -25.0);

                // Draw the unit ORANGE if selected
                if s.selected {
                    polygon(ORANGE, triangle, transform, gl);
                    polygon(YELLOW, front, transform, gl);
                } else {
                    polygon(YELLOW, triangle, transform, gl);
                    polygon(ORANGE, front, transform, gl);
                }

            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        for s in &mut self.units {
            let diff = [s.target[0]-s.position[0], s.target[1]-s.position[1]];
            s.position[0] += diff[0]/2.0*args.dt;
            s.position[1] += diff[1]/2.0*args.dt;
        }
    }

    fn move_selected(&mut self, position: [f64;2]) {
        for s in &mut self.units {
            if s.selected {
                s.target = position;
                let dx = position[0] - s.position[0];
                let dy = position[1] - s.position[1];
                if dx.is_sign_negative() {
                    s.rotation = (dy / dx).atan() + PI;
                } else {
                    s.rotation = (dy / dx).atan();
                }
                println!("dx: {}, dy: {}, new rotation: {}", dx, dy, s.rotation);
            }
        }
    }
}

fn main() {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let window : Window = WindowSettings::new(
        "rpsrtsrs",
        [640, 480]
    ).exit_on_esc(true).into();

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        units: vec![],
    };
    for _ in 0..10 {
        // Create new unit in random location
        let x = rand::random::<f64>() * 600.0 + 40.0;
        let y = rand::random::<f64>() * 440.0 + 40.0;
        let r = (rand::random::<f64>() - 0.5) * PI;
        let unit = Unit::new([x,y], r);

        // Register unit
        app.units.push(unit);
    }

    let mut cursor = [0.0,0.0];

    for e in window.events() {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(&cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

//! The client API itself.
//!
//! This contains three main functions that return three specific types of client:
//!
//! * `connect` returns a pair of `Stream` and `Sink`, clients can write RESP messages to the
//! `Sink` and read RESP messages from the `Stream`. Pairing requests to responses is up to the
//! client.  This is intended to be a low-level interface from which more user-friendly interfaces
//! can be built.
//! * `paired_connect` is used for most of the standard Redis commands, where one request results
//! in one response.
//! * `pubsub_connect` is used for Redis's PUBSUB functionality.

pub mod connect;
#[macro_use]
pub mod paired;
pub mod pubsub;

pub use self::{connect::connect, paired::{paired_connect, PairedConnection},
               pubsub::{pubsub_connect, PubsubConnection}};

#[cfg(test)]
mod test {
    use std::io;

    use futures::sync::oneshot;
    use futures::{stream, Future, Sink, Stream};

    use tokio;

    use error;
    use resp;

    fn run_and_wait<R, E, F>(f: F) -> Result<R, E>
    where
        F: Future<Item = R, Error = E> + Send + 'static,
        R: Send + 'static,
        E: Send + 'static,
    {
        let (tx, rx) = oneshot::channel();
        tokio::run(f.then(|r| tx.send(r).map_err(|_| panic!("Cannot send Result"))));
        rx.wait().expect("Cannot wait for a result")
    }

    #[test]
    fn can_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connection = super::connect(&addr)
            .map_err(|e| e.into())
            .and_then(|connection| {
                connection
                    .send(resp_array!["PING", "TEST"])
                    .map_err(|e| e.into())
            })
            .and_then(|connection| connection.take(1).collect());

        let values = run_and_wait(connection).unwrap();

        assert_eq!(values.len(), 1);
        assert_eq!(values[0], "TEST".into());
    }

    #[test]
    fn complex_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();
        let connection = super::connect(&addr)
            .map_err(|e| e.into())
            .and_then(|connection| {
                let mut ops = Vec::<resp::RespValue>::new();
                ops.push(resp_array!["FLUSH"]);
                ops.extend(
                    (0..1000).map(|i| resp_array!["SADD", "test_set", format!("VALUE: {}", i)]),
                );
                ops.push(resp_array!["SMEMBERS", "test_set"]);
                connection
                    .send_all(stream::iter_ok::<_, io::Error>(ops))
                    .map(|(sender, _)| sender)
                    .map_err(|e| e.into())
            })
            .and_then(|connection| connection.skip(1001).take(1).collect());
        let values = run_and_wait(connection).unwrap();
        assert_eq!(values.len(), 1);
        let values = match &values[0] {
            &resp::RespValue::Array(ref values) => values.clone(),
            _ => panic!("Not an array"),
        };
        assert_eq!(values.len(), 1000);
    }

    #[test]
    fn can_paired_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr).and_then(|connection| {
            let res_f = connection.send(resp_array!["PING", "TEST"]);
            faf!(connection.send(resp_array!["SET", "X", "123"]));
            let wait_f = connection.send(resp_array!["GET", "X"]);
            res_f.join(wait_f)
        });
        let (result_1, result_2): (String, String) = run_and_wait(connect_f).unwrap();
        assert_eq!(result_1, "TEST");
        assert_eq!(result_2, "123");
    }

    #[test]
    fn complex_paired_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr).and_then(|connection| {
            connection
                .send(resp_array!["INCR", "CTR"])
                .and_then(move |value: String| {
                    connection.send(resp_array!["SET", "LASTCTR", value])
                })
        });
        let result: String = run_and_wait(connect_f).unwrap();
        assert_eq!(result, "OK");
    }

    #[test]
    fn sending_a_lot_of_data_test() {
        // let addr = "127.0.0.1:6379".parse().unwrap();

        // let test_f = super::paired_connect(&addr);
        // let send_data = test_f.and_then(|connection| {
        //     let mut futures = Vec::with_capacity(1000);
        //     for i in 0..1000 {
        //         let key = format!("X_{}", i);
        //         faf!(connection.send(resp_array!["SET", &key, i.to_string()]));
        //         futures.push(connection.send(resp_array!["GET", key]));
        //     }
        //     futures.remove(999)
        // });
        // let result: String = run_and_wait(send_data).unwrap();
        // assert_eq!(result, "999");
    }

    #[test]
    fn pubsub_test() {
        // let addr = "127.0.0.1:6379".parse().unwrap();
        // let paired_c = super::paired_connect(&addr);
        // let pubsub_c = super::pubsub_connect(&addr);
        // let msgs = paired_c.join(pubsub_c).and_then(|(paired, pubsub)| {
        //     let subscribe = pubsub.subscribe("test-topic");
        //     subscribe.and_then(move |msgs| {
        //         faf!(paired.send(resp_array!["PUBLISH", "test-topic", "test-message"]));
        //         faf!(paired.send(resp_array!["PUBLISH", "test-not-topic", "test-message-1.5"]));
        //         paired
        //             .send(resp_array!["PUBLISH", "test-topic", "test-message2"])
        //             .map(|_: resp::RespValue| msgs)
        //     })
        // });
        // let tst = msgs.and_then(|msgs| {
        //     msgs.take(2)
        //         .collect()
        //         .map_err(|_| error::internal("unreachable"))
        // });
        // let result = run_and_wait(tst).unwrap();
        // assert_eq!(result.len(), 2);
        // assert_eq!(result[0], "test-message".into());
        // assert_eq!(result[1], "test-message2".into());
    }
}
<commit_msg>Re-enabled test<commit_after>/*
 * Copyright 2017-2018 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

//! The client API itself.
//!
//! This contains three main functions that return three specific types of client:
//!
//! * `connect` returns a pair of `Stream` and `Sink`, clients can write RESP messages to the
//! `Sink` and read RESP messages from the `Stream`. Pairing requests to responses is up to the
//! client.  This is intended to be a low-level interface from which more user-friendly interfaces
//! can be built.
//! * `paired_connect` is used for most of the standard Redis commands, where one request results
//! in one response.
//! * `pubsub_connect` is used for Redis's PUBSUB functionality.

pub mod connect;
#[macro_use]
pub mod paired;
pub mod pubsub;

pub use self::{connect::connect, paired::{paired_connect, PairedConnection},
               pubsub::{pubsub_connect, PubsubConnection}};

#[cfg(test)]
mod test {
    use std::io;

    use futures::sync::oneshot;
    use futures::{stream, Future, Sink, Stream};

    use tokio;

    use error;
    use resp;

    fn run_and_wait<R, E, F>(f: F) -> Result<R, E>
    where
        F: Future<Item = R, Error = E> + Send + 'static,
        R: Send + 'static,
        E: Send + 'static,
    {
        let (tx, rx) = oneshot::channel();
        tokio::run(f.then(|r| tx.send(r).map_err(|_| panic!("Cannot send Result"))));
        rx.wait().expect("Cannot wait for a result")
    }

    #[test]
    fn can_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connection = super::connect(&addr)
            .map_err(|e| e.into())
            .and_then(|connection| {
                connection
                    .send(resp_array!["PING", "TEST"])
                    .map_err(|e| e.into())
            })
            .and_then(|connection| connection.take(1).collect());

        let values = run_and_wait(connection).unwrap();

        assert_eq!(values.len(), 1);
        assert_eq!(values[0], "TEST".into());
    }

    #[test]
    fn complex_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();
        let connection = super::connect(&addr)
            .map_err(|e| e.into())
            .and_then(|connection| {
                let mut ops = Vec::<resp::RespValue>::new();
                ops.push(resp_array!["FLUSH"]);
                ops.extend(
                    (0..1000).map(|i| resp_array!["SADD", "test_set", format!("VALUE: {}", i)]),
                );
                ops.push(resp_array!["SMEMBERS", "test_set"]);
                connection
                    .send_all(stream::iter_ok::<_, io::Error>(ops))
                    .map(|(sender, _)| sender)
                    .map_err(|e| e.into())
            })
            .and_then(|connection| connection.skip(1001).take(1).collect());
        let values = run_and_wait(connection).unwrap();
        assert_eq!(values.len(), 1);
        let values = match &values[0] {
            &resp::RespValue::Array(ref values) => values.clone(),
            _ => panic!("Not an array"),
        };
        assert_eq!(values.len(), 1000);
    }

    #[test]
    fn can_paired_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr).and_then(|connection| {
            let res_f = connection.send(resp_array!["PING", "TEST"]);
            faf!(connection.send(resp_array!["SET", "X", "123"]));
            let wait_f = connection.send(resp_array!["GET", "X"]);
            res_f.join(wait_f)
        });
        let (result_1, result_2): (String, String) = run_and_wait(connect_f).unwrap();
        assert_eq!(result_1, "TEST");
        assert_eq!(result_2, "123");
    }

    #[test]
    fn complex_paired_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr).and_then(|connection| {
            connection
                .send(resp_array!["INCR", "CTR"])
                .and_then(move |value: String| {
                    connection.send(resp_array!["SET", "LASTCTR", value])
                })
        });
        let result: String = run_and_wait(connect_f).unwrap();
        assert_eq!(result, "OK");
    }

    #[test]
    fn sending_a_lot_of_data_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let test_f = super::paired_connect(&addr);
        let send_data = test_f.and_then(|connection| {
            let mut futures = Vec::with_capacity(1000);
            for i in 0..1000 {
                let key = format!("X_{}", i);
                faf!(connection.send(resp_array!["SET", &key, i.to_string()]));
                futures.push(connection.send(resp_array!["GET", key]));
            }
            futures.remove(999)
        });
        let result: String = run_and_wait(send_data).unwrap();
        assert_eq!(result, "999");
    }

    #[test]
    fn pubsub_test() {
        // let addr = "127.0.0.1:6379".parse().unwrap();
        // let paired_c = super::paired_connect(&addr);
        // let pubsub_c = super::pubsub_connect(&addr);
        // let msgs = paired_c.join(pubsub_c).and_then(|(paired, pubsub)| {
        //     let subscribe = pubsub.subscribe("test-topic");
        //     subscribe.and_then(move |msgs| {
        //         faf!(paired.send(resp_array!["PUBLISH", "test-topic", "test-message"]));
        //         faf!(paired.send(resp_array!["PUBLISH", "test-not-topic", "test-message-1.5"]));
        //         paired
        //             .send(resp_array!["PUBLISH", "test-topic", "test-message2"])
        //             .map(|_: resp::RespValue| msgs)
        //     })
        // });
        // let tst = msgs.and_then(|msgs| {
        //     msgs.take(2)
        //         .collect()
        //         .map_err(|_| error::internal("unreachable"))
        // });
        // let result = run_and_wait(tst).unwrap();
        // assert_eq!(result.len(), 2);
        // assert_eq!(result[0], "test-message".into());
        // assert_eq!(result[1], "test-message2".into());
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

extern crate libc;
extern crate net_sys;
extern crate sys_util;

use std::fs::File;
use std::mem;
use std::net;
use std::os::raw::*;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};

use sys_util::{ioctl_with_val, ioctl_with_ref, ioctl_with_mut_ref};

#[derive(Debug)]
pub enum Error {
    /// Failed to create a socket.
    CreateSocket(sys_util::Error),
    /// Couldn't open /dev/net/tun.
    OpenTun(sys_util::Error),
    /// Unable to create tap interface.
    CreateTap(sys_util::Error),
    /// ioctl failed.
    IoctlError(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

/// Create a sockaddr_in from an IPv4 address, and expose it as
/// an opaque sockaddr suitable for usage by socket ioctls.
fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_sys::sockaddr {
    // IPv4 addresses big-endian (network order), but Ipv4Addr will give us
    // a view of those bytes directly so we can avoid any endian trickiness.
    let addr_in = net_sys::sockaddr_in {
        sin_family: net_sys::AF_INET as u16,
        sin_port: 0,
        sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
        __pad: [0; 8usize],
    };

    unsafe { mem::transmute(addr_in) }
}

fn create_socket() -> Result<net::UdpSocket> {
    // This is safe since we check the return value.
    let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
    if sock < 0 {
        return Err(Error::CreateSocket(sys_util::Error::last()));
    }

    // This is safe; nothing else will use or hold onto the raw sock fd.
    Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
}

/// Handle for a network tap interface.
///
/// For now, this simply wraps the file descriptor for the tap device so methods
/// can run ioctls on the interface. The tap interface fd will be closed when
/// Tap goes out of scope, and the kernel will clean up the interface
/// automatically.
pub struct Tap {
    tap_file: File,
    if_name: [u8; 16usize],
}

impl Tap {
    /// Create a new tap interface.
    pub fn new() -> Result<Tap> {
        // Open calls are safe because we give a constant nul-terminated
        // string and verify the result.
        let fd = unsafe {
            libc::open(b"/dev/net/tun\0".as_ptr() as *const i8,
                       libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC)
        };
        if fd < 0 {
            return Err(Error::OpenTun(sys_util::Error::last()));
        }

        // We just checked that the fd is valid.
        let tuntap = unsafe { File::from_raw_fd(fd) };

        const TUNTAP_DEV_FORMAT: &'static [u8; 8usize] = b"vmtap%d\0";

        // This is pretty messy because of the unions used by ifreq. Since we
        // don't call as_mut on the same union field more than once, this block
        // is safe.
        let mut ifreq: net_sys::ifreq = Default::default();
        unsafe {
            let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
            let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut();
            let mut name_slice = &mut ifrn_name[..TUNTAP_DEV_FORMAT.len()];
            name_slice.copy_from_slice(TUNTAP_DEV_FORMAT);
            *ifru_flags = (net_sys::IFF_TAP |
                           net_sys::IFF_NO_PI |
                           net_sys::IFF_VNET_HDR) as c_short;
        }

        // ioctl is safe since we call it with a valid tap fd and check the return
        // value.
        let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_sys::TUNSETIFF(), &mut ifreq) };
        if ret < 0 {
            return Err(Error::CreateTap(sys_util::Error::last()));
        }

        // Safe since only the name is accessed, and it's cloned out.
        Ok(Tap {
            tap_file: tuntap,
            if_name: unsafe { ifreq.ifr_ifrn.ifrn_name.as_ref().clone() },
        })
    }

    /// Set the host-side IP address for the tap interface.
    pub fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
        let sock = create_socket()?;
        let addr = create_sockaddr(ip_addr);

        let mut ifreq = self.get_ifreq();

        // We only access one field of the ifru union, hence this is safe.
        unsafe {
            let ifru_addr = ifreq.ifr_ifru.ifru_addr.as_mut();
            *ifru_addr = addr;
        }

        // ioctl is safe. Called with a valid sock fd, and we check the return.
        let ret = unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFADDR as u64, &ifreq) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    /// Set the netmask for the subnet that the tap interface will exist on.
    pub fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()> {
        let sock = create_socket()?;
        let addr = create_sockaddr(netmask);

        let mut ifreq = self.get_ifreq();

        // We only access one field of the ifru union, hence this is safe.
        unsafe {
            let ifru_addr = ifreq.ifr_ifru.ifru_addr.as_mut();
            *ifru_addr = addr;
        }

        // ioctl is safe. Called with a valid sock fd, and we check the return.
        let ret = unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFNETMASK as u64, &ifreq) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    /// Set the offload flags for the tap interface.
    pub fn set_offload(&self, flags: c_uint) -> Result<()> {
        // ioctl is safe. Called with a valid tap fd, and we check the return.
        let ret = unsafe { ioctl_with_val(&self.tap_file, net_sys::TUNSETOFFLOAD(), flags as u64) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    /// Enable the tap interface.
    pub fn enable(&self) -> Result<()> {
        let sock = create_socket()?;

        let mut ifreq = self.get_ifreq();

        // We only access one field of the ifru union, hence this is safe.
        unsafe {
            let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut();
            *ifru_flags = (net_sys::net_device_flags_IFF_UP |
                           net_sys::net_device_flags_IFF_RUNNING) as i16;
        }

        // ioctl is safe. Called with a valid sock fd, and we check the return.
        let ret = unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFFLAGS as u64, &ifreq) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    /// Set the size of the vnet hdr.
    pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
        // ioctl is safe. Called with a valid tap fd, and we check the return.
        let ret = unsafe { ioctl_with_ref(&self.tap_file, net_sys::TUNSETVNETHDRSZ(), &size) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    fn get_ifreq(&self) -> net_sys::ifreq {
        let mut ifreq: net_sys::ifreq = Default::default();

        // This sets the name of the interface, which is the only entry
        // in a single-field union.
        unsafe {
            let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
            ifrn_name.clone_from_slice(&self.if_name);
        }

        ifreq
    }
}

impl AsRawFd for Tap {
    fn as_raw_fd(&self) -> RawFd {
        self.tap_file.as_raw_fd()
    }
}

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

    #[test]
    fn tap_create() {
        Tap::new().unwrap();
    }

    #[test]
    fn tap_configure() {
        let tap = Tap::new().unwrap();
        let ip_addr: net::Ipv4Addr = "100.115.92.5".parse().unwrap();
        let netmask: net::Ipv4Addr = "255.255.255.252".parse().unwrap();

        tap.set_ip_addr(ip_addr).unwrap();
        tap.set_netmask(netmask).unwrap();
    }

    #[test]
    fn tap_enable() {
        let tap = Tap::new().unwrap();

        tap.enable().unwrap();
    }
}
<commit_msg>net_util: implement Read, Write, and Pollable for Tap<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

extern crate libc;
extern crate net_sys;
extern crate sys_util;

use std::fs::File;
use std::io::{Read, Write, Result as IoResult};
use std::mem;
use std::net;
use std::os::raw::*;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};

use sys_util::Pollable;
use sys_util::{ioctl_with_val, ioctl_with_ref, ioctl_with_mut_ref};

#[derive(Debug)]
pub enum Error {
    /// Failed to create a socket.
    CreateSocket(sys_util::Error),
    /// Couldn't open /dev/net/tun.
    OpenTun(sys_util::Error),
    /// Unable to create tap interface.
    CreateTap(sys_util::Error),
    /// ioctl failed.
    IoctlError(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

/// Create a sockaddr_in from an IPv4 address, and expose it as
/// an opaque sockaddr suitable for usage by socket ioctls.
fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_sys::sockaddr {
    // IPv4 addresses big-endian (network order), but Ipv4Addr will give us
    // a view of those bytes directly so we can avoid any endian trickiness.
    let addr_in = net_sys::sockaddr_in {
        sin_family: net_sys::AF_INET as u16,
        sin_port: 0,
        sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
        __pad: [0; 8usize],
    };

    unsafe { mem::transmute(addr_in) }
}

fn create_socket() -> Result<net::UdpSocket> {
    // This is safe since we check the return value.
    let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
    if sock < 0 {
        return Err(Error::CreateSocket(sys_util::Error::last()));
    }

    // This is safe; nothing else will use or hold onto the raw sock fd.
    Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
}

/// Handle for a network tap interface.
///
/// For now, this simply wraps the file descriptor for the tap device so methods
/// can run ioctls on the interface. The tap interface fd will be closed when
/// Tap goes out of scope, and the kernel will clean up the interface
/// automatically.
pub struct Tap {
    tap_file: File,
    if_name: [u8; 16usize],
}

impl Tap {
    /// Create a new tap interface.
    pub fn new() -> Result<Tap> {
        // Open calls are safe because we give a constant nul-terminated
        // string and verify the result.
        let fd = unsafe {
            libc::open(b"/dev/net/tun\0".as_ptr() as *const i8,
                       libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC)
        };
        if fd < 0 {
            return Err(Error::OpenTun(sys_util::Error::last()));
        }

        // We just checked that the fd is valid.
        let tuntap = unsafe { File::from_raw_fd(fd) };

        const TUNTAP_DEV_FORMAT: &'static [u8; 8usize] = b"vmtap%d\0";

        // This is pretty messy because of the unions used by ifreq. Since we
        // don't call as_mut on the same union field more than once, this block
        // is safe.
        let mut ifreq: net_sys::ifreq = Default::default();
        unsafe {
            let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
            let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut();
            let mut name_slice = &mut ifrn_name[..TUNTAP_DEV_FORMAT.len()];
            name_slice.copy_from_slice(TUNTAP_DEV_FORMAT);
            *ifru_flags = (net_sys::IFF_TAP |
                           net_sys::IFF_NO_PI |
                           net_sys::IFF_VNET_HDR) as c_short;
        }

        // ioctl is safe since we call it with a valid tap fd and check the return
        // value.
        let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_sys::TUNSETIFF(), &mut ifreq) };
        if ret < 0 {
            return Err(Error::CreateTap(sys_util::Error::last()));
        }

        // Safe since only the name is accessed, and it's cloned out.
        Ok(Tap {
            tap_file: tuntap,
            if_name: unsafe { ifreq.ifr_ifrn.ifrn_name.as_ref().clone() },
        })
    }

    /// Set the host-side IP address for the tap interface.
    pub fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
        let sock = create_socket()?;
        let addr = create_sockaddr(ip_addr);

        let mut ifreq = self.get_ifreq();

        // We only access one field of the ifru union, hence this is safe.
        unsafe {
            let ifru_addr = ifreq.ifr_ifru.ifru_addr.as_mut();
            *ifru_addr = addr;
        }

        // ioctl is safe. Called with a valid sock fd, and we check the return.
        let ret = unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFADDR as u64, &ifreq) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    /// Set the netmask for the subnet that the tap interface will exist on.
    pub fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()> {
        let sock = create_socket()?;
        let addr = create_sockaddr(netmask);

        let mut ifreq = self.get_ifreq();

        // We only access one field of the ifru union, hence this is safe.
        unsafe {
            let ifru_addr = ifreq.ifr_ifru.ifru_addr.as_mut();
            *ifru_addr = addr;
        }

        // ioctl is safe. Called with a valid sock fd, and we check the return.
        let ret = unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFNETMASK as u64, &ifreq) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    /// Set the offload flags for the tap interface.
    pub fn set_offload(&self, flags: c_uint) -> Result<()> {
        // ioctl is safe. Called with a valid tap fd, and we check the return.
        let ret = unsafe { ioctl_with_val(&self.tap_file, net_sys::TUNSETOFFLOAD(), flags as u64) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    /// Enable the tap interface.
    pub fn enable(&self) -> Result<()> {
        let sock = create_socket()?;

        let mut ifreq = self.get_ifreq();

        // We only access one field of the ifru union, hence this is safe.
        unsafe {
            let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut();
            *ifru_flags = (net_sys::net_device_flags_IFF_UP |
                           net_sys::net_device_flags_IFF_RUNNING) as i16;
        }

        // ioctl is safe. Called with a valid sock fd, and we check the return.
        let ret = unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFFLAGS as u64, &ifreq) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    /// Set the size of the vnet hdr.
    pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
        // ioctl is safe. Called with a valid tap fd, and we check the return.
        let ret = unsafe { ioctl_with_ref(&self.tap_file, net_sys::TUNSETVNETHDRSZ(), &size) };
        if ret < 0 {
            return Err(Error::IoctlError(sys_util::Error::last()));
        }

        Ok(())
    }

    fn get_ifreq(&self) -> net_sys::ifreq {
        let mut ifreq: net_sys::ifreq = Default::default();

        // This sets the name of the interface, which is the only entry
        // in a single-field union.
        unsafe {
            let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
            ifrn_name.clone_from_slice(&self.if_name);
        }

        ifreq
    }
}

impl Read for Tap {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        self.tap_file.read(buf)
    }
}

impl Write for Tap {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        self.tap_file.write(&buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsRawFd for Tap {
    fn as_raw_fd(&self) -> RawFd {
        self.tap_file.as_raw_fd()
    }
}

// Safe since the tap fd's lifetime lasts as long as this trait object, and the
// tap fd is pollable.
unsafe impl Pollable for Tap {
    fn pollable_fd(&self) -> RawFd {
        self.tap_file.as_raw_fd()
    }
}

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

    #[test]
    fn tap_create() {
        Tap::new().unwrap();
    }

    #[test]
    fn tap_configure() {
        let tap = Tap::new().unwrap();
        let ip_addr: net::Ipv4Addr = "100.115.92.5".parse().unwrap();
        let netmask: net::Ipv4Addr = "255.255.255.252".parse().unwrap();

        tap.set_ip_addr(ip_addr).unwrap();
        tap.set_netmask(netmask).unwrap();
    }

    #[test]
    fn tap_enable() {
        let tap = Tap::new().unwrap();

        tap.enable().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate ext2;
extern crate fuse;
extern crate libc;
extern crate time;

use std::{error, fs, path};
use std::collections::{HashMap};
use std::os::unix::ffi::{OsStrExt};
use std::ffi::{OsStr};

struct Fuse {
  fs: ext2::Filesystem,
  dir_handles: HashMap<u64, ext2::DirHandle>,
  file_handles: HashMap<u64, ext2::FileHandle>,
  next_fh: u64,
}

enum Handle {
  Dir(ext2::DirHandle),
  File(ext2::FileHandle),
}

impl Fuse {
  fn new(fs: ext2::Filesystem) -> Fuse {
    Fuse {
      fs: fs,
      dir_handles: HashMap::new(),
      file_handles: HashMap::new(),
      next_fh: 0,
    }
  }
}

const TTL: time::Timespec = time::Timespec { sec: 1, nsec: 0 };

#[allow(unused_variables)]
impl fuse::Filesystem for Fuse {
  fn lookup(&mut self, _req: &fuse::Request,
    parent_ino: u64, name: &path::Path, reply: fuse::ReplyEntry)
  {
    let res: Result<_, ext2::Error> = (|| {
      let parent_inode = try!(self.fs.read_inode(ext2_ino(parent_ino)));
      let entry = try!(self.fs.dir_lookup(
          parent_inode, name.as_os_str().as_bytes()));
      Ok(match entry {
        Some(entry_ino) => {
          let entry_inode = try!(self.fs.read_inode(entry_ino));
          Some(inode_to_file_attr(entry_ino, &entry_inode))
        },
        None => None,
      })
    })();

    match res {
      Err(_err) => reply.error(65),
      Ok(None) => reply.error(libc::ENOENT),
      Ok(Some(file_attr)) => reply.entry(&TTL, &file_attr, 0),
    }
  }

  fn getattr(&mut self, _req: &fuse::Request, ino: u64, reply: fuse::ReplyAttr) {
    println!("getattr (ino {})", ino);
    match self.fs.read_inode(ext2_ino(ino)) {
      Err(_err) => reply.error(65),
      Ok(inode) => reply.attr(&TTL, &inode_to_file_attr(ext2_ino(ino), &inode)),
    }
  }

  /*
  fn readlink(&mut self, _req: &fuse::Request, ino: u64, reply: fuse::ReplyData) {
    reply.error(65)
  }

  fn open(&mut self, _req: &fuse::Request, ino: u64, flags: u32, reply: fuse::ReplyOpen) {
    reply.error(65)
  }

  fn read(&mut self, _req: &fuse::Request, ino: u64, fh: u64,
    offset: u64, size: u32, reply: fuse::ReplyData)
  {
    reply.error(65)
  }

  fn release(&mut self, _req: &fuse::Request, ino: u64, fh: u64,
    flags: u32, lock_owner: u64, flush: bool, reply: fuse::ReplyEmpty)
  {
    reply.error(65)
  }
  */

  fn opendir(&mut self, _req: &fuse::Request, ino: u64,
    flags: u32, reply: fuse::ReplyOpen)
  {
    let res: Result<_, ext2::Error> = (|| {
      let fh = self.next_fh;
      self.next_fh += 1;
      let dir_inode = try!(self.fs.read_inode(ext2_ino(ino)));
      let dir_handle = try!(self.fs.dir_open(dir_inode));
      self.dir_handles.insert(fh, dir_handle);
      Ok(fh)
    })();

    match res {
      Err(_err) => reply.error(65),
      Ok(fh) => reply.opened(fh, 0),
    }
  }

  fn readdir(&mut self, _req: &fuse::Request, ino: u64, fh: u64,
    offset: u64, mut reply: fuse::ReplyDirectory)
  {
    let res: Result<_, ext2::Error> = (|| {
      let handle = try!(self.dir_handles.get_mut(&fh)
          .ok_or_else(|| ext2::Error::new(format!("Bad dir handle"))));
      while let Some(line) = try!(self.fs.dir_read(handle)) {
        let ino = fuse_ino(line.ino);
        let file_type = fuse_file_type(line.file_type);
        let name = <OsStr as OsStrExt>::from_bytes(&line.name[..]);
        if reply.add(ino, 0, file_type, name) {
          break
        }
      }
      Ok(())
    })();

    match res {
      Err(_err) => reply.error(65),
      Ok(()) => reply.ok(),
    }
  }

  fn releasedir(&mut self, _req: &fuse::Request, _ino: u64, fh: u64,
    _flags: u32, reply: fuse::ReplyEmpty)
  {
    self.dir_handles.remove(&fh);
    reply.ok();
  }
}

fn mein() -> Result<(), ext2::Error> {
  let file = try!(fs::File::open("test.ext2"));
  let reader = ext2::FileReader(file);
  let fs = try!(ext2::Filesystem::new(Box::new(reader)));
  let fuse = Fuse::new(fs);
  fuse::mount(fuse, &"/tmp/test", &[]);
  Ok(())
}

fn main() {
  match mein() {
    Ok(()) => {},
    Err(err) => print_error(&err),
  }
}

fn print_error(err: &error::Error) {
  println!("Error: {}", err);
  match err.cause() {
    Some(cause) => print_error(cause),
    None => (),
  }
}

fn ext2_ino(fuse_ino: u64) -> u64 {
  if fuse_ino == 1 { ext2::Filesystem::ROOT_INO } else { fuse_ino }
}

fn fuse_ino(ext2_ino: u64) -> u64 {
  if ext2_ino == ext2::Filesystem::ROOT_INO { 1 } else { ext2_ino }
}

fn inode_to_file_attr(ext2_ino: u64, inode: &ext2::Inode) -> fuse::FileAttr {
  fuse::FileAttr {
    ino: fuse_ino(ext2_ino),
    size: inode.size,
    blocks: inode.size_512 as u64,
    atime: fuse_timespec(inode.atime),
    ctime: fuse_timespec(inode.ctime),
    mtime: fuse_timespec(inode.mtime),
    crtime: fuse_timespec(0),
    kind: fuse_file_type(inode.file_type),
    perm: inode.access_rights.0,
    nlink: inode.links_count as u32,
    uid: inode.uid,
    gid: inode.gid,
    rdev: 0,
    flags: 0,
  }
}

fn fuse_timespec(epoch: u32) -> time::Timespec {
  time::Timespec::new(epoch as i64, 0)
}

fn fuse_file_type(ftype: ext2::FileType) -> fuse::FileType {
  match ftype {
    ext2::FileType::Regular => fuse::FileType::RegularFile,
    ext2::FileType::Dir => fuse::FileType::Directory,
    ext2::FileType::CharDev => fuse::FileType::CharDevice,
    ext2::FileType::BlockDev => fuse::FileType::BlockDevice,
    ext2::FileType::Fifo => fuse::FileType::NamedPipe,
    ext2::FileType::Socket => panic!("Fuse cannot handle sockets"),
    ext2::FileType::Symlink => fuse::FileType::Symlink,
  }
}

<commit_msg>Implement reading files in Fuse<commit_after>extern crate ext2;
extern crate fuse;
extern crate libc;
extern crate time;

use std::{error, fs, iter, path};
use std::collections::{HashMap};
use std::os::unix::ffi::{OsStrExt};
use std::ffi::{OsStr};

struct Fuse {
  fs: ext2::Filesystem,
  dir_handles: HashMap<u64, ext2::DirHandle>,
  file_handles: HashMap<u64, ext2::FileHandle>,
  next_fh: u64,
}

impl Fuse {
  fn new(fs: ext2::Filesystem) -> Fuse {
    Fuse {
      fs: fs,
      dir_handles: HashMap::new(),
      file_handles: HashMap::new(),
      next_fh: 0,
    }
  }
}

const TTL: time::Timespec = time::Timespec { sec: 1, nsec: 0 };

#[allow(unused_variables)]
impl fuse::Filesystem for Fuse {
  fn lookup(&mut self, _req: &fuse::Request,
    parent_ino: u64, name: &path::Path, reply: fuse::ReplyEntry)
  {
    println!("lookup (ino {}, name {:?})", parent_ino,
             &name.to_string_lossy());
    let res: Result<_, ext2::Error> = (|| {
      let parent_inode = try!(self.fs.read_inode(ext2_ino(parent_ino)));
      let entry = try!(self.fs.dir_lookup(
          parent_inode, name.as_os_str().as_bytes()));
      Ok(match entry {
        Some(entry_ino) => {
          let entry_inode = try!(self.fs.read_inode(entry_ino));
          Some(inode_to_file_attr(entry_ino, &entry_inode))
        },
        None => None,
      })
    })();

    match res {
      Err(_err) => reply.error(65),
      Ok(None) => reply.error(libc::ENOENT),
      Ok(Some(file_attr)) => reply.entry(&TTL, &file_attr, 0),
    }
  }

  fn getattr(&mut self, _req: &fuse::Request, ino: u64, reply: fuse::ReplyAttr) {
    println!("getattr (ino {})", ino);
    match self.fs.read_inode(ext2_ino(ino)) {
      Err(_err) => reply.error(65),
      Ok(inode) => reply.attr(&TTL, &inode_to_file_attr(ext2_ino(ino), &inode)),
    }
  }

  /*
  fn readlink(&mut self, _req: &fuse::Request, ino: u64, reply: fuse::ReplyData) {
    reply.error(65)
  }
  */

  fn open(&mut self, _req: &fuse::Request, ino: u64, flags: u32, reply: fuse::ReplyOpen) {
    println!("open (ino {})", ino);
    let res: Result<_, ext2::Error> = (|| {
      let inode = try!(self.fs.read_inode(ext2_ino(ino)));
      let handle = try!(self.fs.file_open(inode));
      self.file_handles.insert(self.next_fh, handle);
      self.next_fh += 1;
      Ok(self.next_fh - 1)
    })();

    match res {
      Err(_err) => reply.error(65),
      Ok(fh) => reply.opened(fh, 0),
    }
  }

  fn read(&mut self, _req: &fuse::Request, _ino: u64, fh: u64,
    offset: u64, size: u32, reply: fuse::ReplyData)
  {
    println!("read (ino {}, fh {}, offset {}, size {})", _ino, fh, offset, size);
    let res: Result<_, ext2::Error> = (|| {
      let handle = try!(self.file_handles.get_mut(&fh)
          .ok_or_else(|| ext2::Error::new(format!("Bad file handle"))));
      let mut buffer: Vec<u8> = iter::repeat(0).take(size as usize).collect();
      let length = try!(self.fs.file_read(handle, offset, &mut buffer[..]));
      buffer.truncate(length as usize);
      Ok(buffer)
    })();

    match res {
      Err(_err) => reply.error(65),
      Ok(data) => reply.data(&data[..]),
    }
  }

  fn release(&mut self, _req: &fuse::Request, _ino: u64, fh: u64,
    _flags: u32, _lock_owner: u64, _flush: bool, reply: fuse::ReplyEmpty)
  {
    println!("release (ino {}, fh {})", _ino, fh);
    self.dir_handles.remove(&fh);
    reply.ok();
  }

  fn opendir(&mut self, _req: &fuse::Request, ino: u64,
    flags: u32, reply: fuse::ReplyOpen)
  {
    println!("opendir (ino {})", ino);
    let res: Result<_, ext2::Error> = (|| {
      let dir_inode = try!(self.fs.read_inode(ext2_ino(ino)));
      let dir_handle = try!(self.fs.dir_open(dir_inode));
      self.dir_handles.insert(self.next_fh, dir_handle);
      self.next_fh += 1;
      Ok(self.next_fh - 1)
    })();

    match res {
      Err(_err) => reply.error(65),
      Ok(fh) => reply.opened(fh, 0),
    }
  }

  fn readdir(&mut self, _req: &fuse::Request, ino: u64, fh: u64,
    offset: u64, mut reply: fuse::ReplyDirectory)
  {
    println!("readdir (ino {}, fh {}, offset {})", ino, fh, offset);
    let res: Result<_, ext2::Error> = (|| {
      let handle = try!(self.dir_handles.get_mut(&fh)
          .ok_or_else(|| ext2::Error::new(format!("Bad dir handle"))));
      while let Some(line) = try!(self.fs.dir_read(handle)) {
        let ino = fuse_ino(line.ino);
        let file_type = fuse_file_type(line.file_type);
        let name = <OsStr as OsStrExt>::from_bytes(&line.name[..]);
        if reply.add(ino, 0, file_type, name) {
          break
        }
      }
      Ok(())
    })();

    match res {
      Err(_err) => reply.error(65),
      Ok(()) => reply.ok(),
    }
  }

  fn releasedir(&mut self, _req: &fuse::Request, _ino: u64, fh: u64,
    _flags: u32, reply: fuse::ReplyEmpty)
  {
    println!("releasedir (ino {}, fh {})", _ino, fh);
    self.dir_handles.remove(&fh);
    reply.ok();
  }
}

fn mein() -> Result<(), ext2::Error> {
  let file = try!(fs::File::open("test.ext2"));
  let reader = ext2::FileReader(file);
  let fs = try!(ext2::Filesystem::new(Box::new(reader)));
  let fuse = Fuse::new(fs);
  fuse::mount(fuse, &"/tmp/test", &[]);
  Ok(())
}

fn main() {
  match mein() {
    Ok(()) => {},
    Err(err) => print_error(&err),
  }
}

fn print_error(err: &error::Error) {
  println!("Error: {}", err);
  match err.cause() {
    Some(cause) => print_error(cause),
    None => (),
  }
}

fn ext2_ino(fuse_ino: u64) -> u64 {
  if fuse_ino == 1 { ext2::Filesystem::ROOT_INO } else { fuse_ino }
}

fn fuse_ino(ext2_ino: u64) -> u64 {
  if ext2_ino == ext2::Filesystem::ROOT_INO { 1 } else { ext2_ino }
}

fn inode_to_file_attr(ext2_ino: u64, inode: &ext2::Inode) -> fuse::FileAttr {
  fuse::FileAttr {
    ino: fuse_ino(ext2_ino),
    size: inode.size,
    blocks: inode.size_512 as u64,
    atime: fuse_timespec(inode.atime),
    ctime: fuse_timespec(inode.ctime),
    mtime: fuse_timespec(inode.mtime),
    crtime: fuse_timespec(0),
    kind: fuse_file_type(inode.file_type),
    perm: inode.access_rights.0,
    nlink: inode.links_count as u32,
    uid: inode.uid,
    gid: inode.gid,
    rdev: 0,
    flags: 0,
  }
}

fn fuse_timespec(epoch: u32) -> time::Timespec {
  time::Timespec::new(epoch as i64, 0)
}

fn fuse_file_type(ftype: ext2::FileType) -> fuse::FileType {
  match ftype {
    ext2::FileType::Regular => fuse::FileType::RegularFile,
    ext2::FileType::Dir => fuse::FileType::Directory,
    ext2::FileType::CharDev => fuse::FileType::CharDevice,
    ext2::FileType::BlockDev => fuse::FileType::BlockDevice,
    ext2::FileType::Fifo => fuse::FileType::NamedPipe,
    ext2::FileType::Socket => panic!("Fuse cannot handle sockets"),
    ext2::FileType::Symlink => fuse::FileType::Symlink,
  }
}

<|endoftext|>


<commit_before>use std::mem;
use std::collections::{VecDeque, HashMap, HashSet};

use rand::{self, Rng, ChaChaRng};

use ogg::{OggTrack, OggTrackBuf};
use ogg::vorbis::{Comments, VorbisHeader};
use ireul_interface::proxy::track::model::{self, Handle};

struct HandleAllocator<R> {
    rng: R,
    limit: usize,
    allocated: HashSet<u64>,
}

impl<R> HandleAllocator<R> where R: Rng {
    pub fn new(rng: R, limit: usize) -> HandleAllocator<R> {
        HandleAllocator {
            rng: rng,
            limit: limit,
            allocated: HashSet::new(),
        }
    }

    pub fn generate(&mut self) -> Result<Handle, ()> {
        if self.limit <= self.allocated.len() {
            return Err(());
        }

        let new_handle;
        loop {
            let foo = self.rng.next_u64();
            if !self.allocated.contains(&foo) {
                new_handle = foo;
                break;
            }
        }

        println!("EMITTING HANDLE {:#x}", new_handle);
        self.allocated.insert(new_handle);
        Ok(Handle(new_handle))
    }

    pub fn dispose(&mut self, handle: Handle) -> Result<(), Handle> {
        match self.allocated.remove(&handle.0) {
            true => Ok(()),
            false => Err(handle),
        }
    }
}

#[derive(Clone)]
pub struct Track {
    handle: Handle,
    data: OggTrackBuf,
    comments: Comments,

    artist: String,
    album: String,
    title: String,

    sample_rate: u64,
    sample_count: u64,
}

impl Track {
    pub fn from_ogg_track(handle: Handle, ogg: OggTrackBuf) -> Track {
        use std::ascii::AsciiExt;

        let id_header = match VorbisHeader::find_identification(ogg.pages()) {
            Ok(header) => header.identification_header(),
            Err(_) => None
        }.expect("Invalid OggTrackBuf");

        let comments = match VorbisHeader::find_comments(ogg.pages()) {
            Ok(header) => header.comments(),
            Err(_) => None
        }.expect("Invalid OggTrackBuf");

        let mut sample_count = 0;
        for page in ogg.pages() {
            let page_pos = page.position();
            if sample_count < page_pos {
                sample_count = page_pos;
            }
        }

        let mut artist: Option<String> = None;
        let mut album: Option<String> = None;
        let mut title: Option<String> = None;

        for &(ref key, ref val) in comments.comments.iter() {
            if key.eq_ignore_ascii_case("ARTIST") {
                artist = Some(val.clone());
            }
            if key.eq_ignore_ascii_case("ALBUM") {
                album = Some(val.clone());
            }
            if key.eq_ignore_ascii_case("TITLE") {
                title = Some(val.clone());
            }
        }

        Track {
            handle: handle,
            data: ogg,
            comments: comments,

            artist: artist.unwrap_or_else(|| "".to_string()),
            album: album.unwrap_or_else(|| "".to_string()),
            title: title.unwrap_or_else(|| "".to_string()),

            sample_rate: id_header.audio_sample_rate as u64,
            sample_count: sample_count,
        }
    }

    pub fn into_inner(self) -> OggTrackBuf {
        self.data
    }

    pub fn get_track_info(&self) -> model::TrackInfo {
        model::TrackInfo {
            handle: self.handle,

            artist: self.artist.clone(),
            album: self.album.clone(),
            title: self.title.clone(),

            sample_rate: self.sample_rate,
            sample_count: self.sample_count,
            sample_position: 0,
        }
    }
}

pub struct PlayQueue {
    halloc: HandleAllocator<ChaChaRng>,
    items: VecDeque<Track>,
}

impl PlayQueue {
    pub fn new(limit: usize) -> PlayQueue {
        let rng: ChaChaRng = rand::thread_rng().gen();
        PlayQueue {
            halloc: HandleAllocator::new(rng, limit),
            items: VecDeque::new(),
        }
    }

    #[allow(dead_code)] // queue manip stub
    pub fn reorder(&mut self, handle_ord: &[Handle]) {
        let old_items: VecDeque<Track> = mem::replace(&mut self.items, VecDeque::new());

        let mut map: HashMap<Handle, Track> = old_items.into_iter().map(|pq| (pq.handle, pq)).collect();

        for handle in handle_ord.iter() {
            match map.remove(handle) {
                Some(item) => {
                    self.items.push_back(item);
                },
                None => (),
            }
        }
    }

    #[allow(dead_code)] // queue manip stub
    pub fn remove_by_handle(&mut self, handle: Handle) {
        let old_items: VecDeque<Track> = mem::replace(&mut self.items, VecDeque::new());
        for item in old_items.into_iter() {
            if item.handle != handle {
                self.items.push_back(item);
            }
        }
    }

    pub fn add_track(&mut self, track: &OggTrack) -> Result<Handle, PlayQueueError> {
        let handle = try!(self.halloc.generate()
                .map_err(|()| PlayQueueError::Full));

        self.items.push_back(Track::from_ogg_track(handle, track.to_owned()));
        Ok(handle)
    }

    pub fn pop_track(&mut self) -> Option<Track> {
        match self.items.pop_front() {
            Some(track) => {
                self.halloc.dispose(track.handle).unwrap();
                Some(track)
            },
            None => None,
        }
    }

    pub fn track_infos(&self) -> Vec<model::TrackInfo> {
        self.items.iter()
            .map(Track::get_track_info)
            .collect()
    }
}

pub enum PlayQueueError {
    Full,
}

#[cfg(test)]
mod test {
    use ogg::OggTrack;
    use super::PlayQueue;

    static SAMPLE_OGG: &'static [u8] = include_bytes!("../../ogg/testdata/Hydrate-Kenny_Beltrey.ogg");

    #[test]
    fn test_get_queue_comments_by_fields() {
        let mut queue = PlayQueue::new(2);
        let track1 = OggTrack::new(SAMPLE_OGG).unwrap();
        let track2 = OggTrack::new(SAMPLE_OGG).unwrap();

        queue.add_track(&track1).ok();
        queue.add_track(&track2).ok();

        let expected = vec!(
            vec!(
                ("TITLE".to_string(), "Hydrate - Kenny Beltrey".to_string()),
                ("ARTIST".to_string(), "Kenny Beltrey".to_string())
            ),
            vec!(
                ("TITLE".to_string(), "Hydrate - Kenny Beltrey".to_string()),
                ("ARTIST".to_string(), "Kenny Beltrey".to_string())
            )
        );

        let got = queue.get_queue_comments_by_fields(&["ARTIST", "TITLE", "NOTAFIELD"]);
        assert_eq!(expected, got);
    }
}
<commit_msg>core: Remove test of removed functionality<commit_after>use std::mem;
use std::collections::{VecDeque, HashMap, HashSet};

use rand::{self, Rng, ChaChaRng};

use ogg::{OggTrack, OggTrackBuf};
use ogg::vorbis::{Comments, VorbisHeader};
use ireul_interface::proxy::track::model::{self, Handle};

struct HandleAllocator<R> {
    rng: R,
    limit: usize,
    allocated: HashSet<u64>,
}

impl<R> HandleAllocator<R> where R: Rng {
    pub fn new(rng: R, limit: usize) -> HandleAllocator<R> {
        HandleAllocator {
            rng: rng,
            limit: limit,
            allocated: HashSet::new(),
        }
    }

    pub fn generate(&mut self) -> Result<Handle, ()> {
        if self.limit <= self.allocated.len() {
            return Err(());
        }

        let new_handle;
        loop {
            let foo = self.rng.next_u64();
            if !self.allocated.contains(&foo) {
                new_handle = foo;
                break;
            }
        }

        println!("EMITTING HANDLE {:#x}", new_handle);
        self.allocated.insert(new_handle);
        Ok(Handle(new_handle))
    }

    pub fn dispose(&mut self, handle: Handle) -> Result<(), Handle> {
        match self.allocated.remove(&handle.0) {
            true => Ok(()),
            false => Err(handle),
        }
    }
}

#[derive(Clone)]
pub struct Track {
    handle: Handle,
    data: OggTrackBuf,
    comments: Comments,

    artist: String,
    album: String,
    title: String,

    sample_rate: u64,
    sample_count: u64,
}

impl Track {
    pub fn from_ogg_track(handle: Handle, ogg: OggTrackBuf) -> Track {
        use std::ascii::AsciiExt;

        let id_header = match VorbisHeader::find_identification(ogg.pages()) {
            Ok(header) => header.identification_header(),
            Err(_) => None
        }.expect("Invalid OggTrackBuf");

        let comments = match VorbisHeader::find_comments(ogg.pages()) {
            Ok(header) => header.comments(),
            Err(_) => None
        }.expect("Invalid OggTrackBuf");

        let mut sample_count = 0;
        for page in ogg.pages() {
            let page_pos = page.position();
            if sample_count < page_pos {
                sample_count = page_pos;
            }
        }

        let mut artist: Option<String> = None;
        let mut album: Option<String> = None;
        let mut title: Option<String> = None;

        for &(ref key, ref val) in comments.comments.iter() {
            if key.eq_ignore_ascii_case("ARTIST") {
                artist = Some(val.clone());
            }
            if key.eq_ignore_ascii_case("ALBUM") {
                album = Some(val.clone());
            }
            if key.eq_ignore_ascii_case("TITLE") {
                title = Some(val.clone());
            }
        }

        Track {
            handle: handle,
            data: ogg,
            comments: comments,

            artist: artist.unwrap_or_else(|| "".to_string()),
            album: album.unwrap_or_else(|| "".to_string()),
            title: title.unwrap_or_else(|| "".to_string()),

            sample_rate: id_header.audio_sample_rate as u64,
            sample_count: sample_count,
        }
    }

    pub fn into_inner(self) -> OggTrackBuf {
        self.data
    }

    pub fn get_track_info(&self) -> model::TrackInfo {
        model::TrackInfo {
            handle: self.handle,

            artist: self.artist.clone(),
            album: self.album.clone(),
            title: self.title.clone(),

            sample_rate: self.sample_rate,
            sample_count: self.sample_count,
            sample_position: 0,
        }
    }
}

pub struct PlayQueue {
    halloc: HandleAllocator<ChaChaRng>,
    items: VecDeque<Track>,
}

impl PlayQueue {
    pub fn new(limit: usize) -> PlayQueue {
        let rng: ChaChaRng = rand::thread_rng().gen();
        PlayQueue {
            halloc: HandleAllocator::new(rng, limit),
            items: VecDeque::new(),
        }
    }

    #[allow(dead_code)] // queue manip stub
    pub fn reorder(&mut self, handle_ord: &[Handle]) {
        let old_items: VecDeque<Track> = mem::replace(&mut self.items, VecDeque::new());

        let mut map: HashMap<Handle, Track> = old_items.into_iter().map(|pq| (pq.handle, pq)).collect();

        for handle in handle_ord.iter() {
            match map.remove(handle) {
                Some(item) => {
                    self.items.push_back(item);
                },
                None => (),
            }
        }
    }

    #[allow(dead_code)] // queue manip stub
    pub fn remove_by_handle(&mut self, handle: Handle) {
        let old_items: VecDeque<Track> = mem::replace(&mut self.items, VecDeque::new());
        for item in old_items.into_iter() {
            if item.handle != handle {
                self.items.push_back(item);
            }
        }
    }

    pub fn add_track(&mut self, track: &OggTrack) -> Result<Handle, PlayQueueError> {
        let handle = try!(self.halloc.generate()
                .map_err(|()| PlayQueueError::Full));

        self.items.push_back(Track::from_ogg_track(handle, track.to_owned()));
        Ok(handle)
    }

    pub fn pop_track(&mut self) -> Option<Track> {
        match self.items.pop_front() {
            Some(track) => {
                self.halloc.dispose(track.handle).unwrap();
                Some(track)
            },
            None => None,
        }
    }

    pub fn track_infos(&self) -> Vec<model::TrackInfo> {
        self.items.iter()
            .map(Track::get_track_info)
            .collect()
    }
}

pub enum PlayQueueError {
    Full,
}
<|endoftext|>


<commit_before>extern crate polydraw;

use polydraw::{Application, Renderer, Frame};
use polydraw::geom::point::Point;
use polydraw::draw::RGB;

struct Poly {
   points: Vec<Point>,
   color: RGB,
}

impl Poly {
   fn min_max_y_index(&self) -> (usize, usize) {
      let (first, rest) = self.points.split_first().unwrap();

      let mut min_y = first.y;
      let mut max_y = min_y;
      let mut min_index: usize = 0;
      let mut max_index: usize = 0;

      for (index, point) in rest.iter().enumerate() {
         if point.y < min_y {
            min_index = index + 1;
            min_y = point.y;
         } else if point.y > max_y {
            max_index = index + 1;
            max_y = point.y;
         }
      }

      (min_index, max_index)
   }
}

struct Scene {
   polys: Vec<Poly>,
}

impl Scene {
   #[inline]
   fn new() -> Self {
      Scene {
         polys: Vec::new(),
      }
   }

   #[inline]
   pub fn push(&mut self, poly: Poly) {
      self.polys.push(poly);
   }
}

struct DevRenderer {
   scene: Scene,
}

impl DevRenderer {
   fn new(scene: Scene) -> Self {
      DevRenderer {
         scene: scene,
      }
   }

   fn _render_poly(&self, frame: &mut Frame, poly: &Poly) {
      let (min_y_index, max_y_index) = poly.min_max_y_index();

      println!("MIN [{:?}] = {:?}", min_y_index, poly.points[min_y_index]);

      println!("MAX [{:?}] = {:?}", max_y_index, poly.points[max_y_index]);

      let points_len = poly.points.len();
      let clockwise_count = if max_y_index > min_y_index {
         max_y_index - min_y_index + 1
      } else {
         points_len - min_y_index + max_y_index + 1
      };

      let counter_count = points_len - clockwise_count + 2;

      println!("CLOCKWISE COUNT = {}", clockwise_count);

      let mut index = min_y_index;
      for _ in 0..clockwise_count {
         if index == points_len {
            index = 0;
         }

         println!("[{}] = {:?}", index, poly.points[index]);

         index += 1;
      }

      println!("COUNTER COUNT = {}", counter_count);

      let mut index = min_y_index;
      for _ in 0..counter_count {
         println!("[{}] = {:?}", index, poly.points[index]);

         if index == 0 {
            index = points_len - 1;
         } else {
            index -= 1;
         }
      }

      for point in poly.points.iter() {
         frame.put_pixel(point.x as i32, point.y as i32, &poly.color)
      }
   }
}

impl Renderer for DevRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      for poly in self.scene.polys.iter() {
         self._render_poly(frame, poly);
      }

      panic!("Bye!");
   }
}

fn main() {
   let mut scene = Scene::new();

   let poly_a = Poly {
      points: vec![
         Point::new(1100, 400),
         Point::new(500, 700),
         Point::new(200, 200),
      ],
      color: RGB::new(34, 78, 29),
   };

   let poly_b = Poly {
      points: vec![
         Point::new(100, 500),
         Point::new(700, 100),
         Point::new(900, 200),
         Point::new(900, 1000),
      ],
      color: RGB::new(128, 59, 89),
   };

   scene.push(poly_a);
   scene.push(poly_b);

   let mut renderer = DevRenderer::new(scene);

   Application::new()
      .renderer(&mut renderer)
      .title("Dev Rasterizer")
      .size(800, 450)
      .run();
}

<commit_msg>Moving left and right vector points algorithms inside the Poly struct<commit_after>extern crate polydraw;

use polydraw::{Application, Renderer, Frame};
use polydraw::geom::point::Point;
use polydraw::draw::RGB;

struct Poly {
   points: Vec<Point>,
   color: RGB,
}

impl Poly {
   fn left_right_points(&self) -> (Vec<Point>, Vec<Point>) {
      let (min_y_i, max_y_i) = self._min_max_y_index();

      let (left_count, right_count) = self._left_right_count(min_y_i, max_y_i);

      return (
         self._left_points(min_y_i, left_count),
         self._right_points(min_y_i, right_count)
      )
   }

   fn _left_points(&self, min_y_i: usize, left_count: usize) -> Vec<Point> {
      let mut left = Vec::with_capacity(left_count);

      let points_len = self.points.len();

      let mut index = min_y_i;

      for _ in 0..left_count {
         left.push(self.points[index]);

         if index == 0 {
            index = points_len - 1;
         } else {
            index -= 1;
         }
      }

      return left;
   }

   fn _right_points(&self, min_y_i: usize, right_count: usize) -> Vec<Point> {
      let mut right = Vec::with_capacity(right_count);

      let points_len = self.points.len();

      let mut index = min_y_i;

      for _ in 0..right_count {
         if index == points_len {
            index = 0;
         }

         right.push(self.points[index]);

         index += 1;
      }

      return right;
   }

   fn _left_right_count(&self, min_y_i: usize, max_y_i: usize) -> (usize, usize) {
      let points_len = self.points.len();

      let left_count = if max_y_i > min_y_i {
         max_y_i - min_y_i + 1
      } else {
         points_len - min_y_i + max_y_i + 1
      };

      let right_count = points_len - left_count + 2;

      return (left_count, right_count)
   }

   fn _min_max_y_index(&self) -> (usize, usize) {
      let (first, rest) = self.points.split_first().unwrap();

      let mut min_y = first.y;
      let mut max_y = min_y;
      let mut min_index: usize = 0;
      let mut max_index: usize = 0;

      for (index, point) in rest.iter().enumerate() {
         if point.y < min_y {
            min_index = index + 1;
            min_y = point.y;
         } else if point.y > max_y {
            max_index = index + 1;
            max_y = point.y;
         }
      }

      (min_index, max_index)
   }
}

struct Scene {
   polys: Vec<Poly>,
}

impl Scene {
   #[inline]
   fn new() -> Self {
      Scene {
         polys: Vec::new(),
      }
   }

   #[inline]
   pub fn push(&mut self, poly: Poly) {
      self.polys.push(poly);
   }
}

struct DevRenderer {
   scene: Scene,
}

impl DevRenderer {
   fn new(scene: Scene) -> Self {
      DevRenderer {
         scene: scene,
      }
   }

   fn _render_poly(&self, frame: &mut Frame, poly: &Poly) {
      let (left_points, right_points) = poly.left_right_points();

      println!("LEFT");

      for (index, point) in left_points.iter().enumerate() {
         println!("[{}] = {:?}", index, point);
      }

      println!("RIGHT");

      for (index, point) in right_points.iter().enumerate() {
         println!("[{}] = {:?}", index, point);
      }

      for point in poly.points.iter() {
         frame.put_pixel(point.x as i32, point.y as i32, &poly.color)
      }
   }
}

impl Renderer for DevRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      for poly in self.scene.polys.iter() {
         self._render_poly(frame, poly);
      }

      panic!("Bye!");
   }
}

fn main() {
   let mut scene = Scene::new();

   let poly_a = Poly {
      points: vec![
         Point::new(1100, 400),
         Point::new(500, 700),
         Point::new(200, 200),
      ],
      color: RGB::new(34, 78, 29),
   };

   let poly_b = Poly {
      points: vec![
         Point::new(100, 500),
         Point::new(700, 100),
         Point::new(900, 200),
         Point::new(900, 1000),
      ],
      color: RGB::new(128, 59, 89),
   };

   scene.push(poly_a);
   scene.push(poly_b);

   let mut renderer = DevRenderer::new(scene);

   Application::new()
      .renderer(&mut renderer)
      .title("Dev Rasterizer")
      .size(800, 450)
      .run();
}

<|endoftext|>


<commit_before>extern crate glium;
extern crate gltile;
extern crate looper;
extern crate pixset;

use glium::DisplayBuild;

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(1536, 1024)
        .build_glium()
        .unwrap();

    let mut renderer = gltile::Renderer::new(&display, pixset::TILESET, pixset::Pix::Empty);

    for (pix, offset) in pixset::Str::from("Yo, Dawg;").iter() {
        let tile = gltile::Tile::make(*gltile::colors::YELLOW, *gltile::colors::BLACK, pix);
        renderer.set(gltile::units::ScreenTile2D::new(5 + offset.0, 10), tile);
    }

    let render = |_| {
        renderer.render();
        looper::Action::Continue
    };

    let update = |_| {
        for ev in display.poll_events() {
            match ev {
                glium::glutin::Event::Closed => return looper::Action::Stop,
                _ => (),
            }
        }
        looper::Action::Continue
    };

    looper::Looper::new(60.0).run(render, update);
}
<commit_msg>chore(pixset): PixStr is the new name<commit_after>extern crate glium;
extern crate gltile;
extern crate looper;
extern crate pixset;

use glium::DisplayBuild;

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(1536, 1024)
        .build_glium()
        .unwrap();

    let mut renderer = gltile::Renderer::new(&display, pixset::TILESET, pixset::Pix::Empty);

    for (pix, offset) in pixset::PixStr::from("Yo, Dawg;").iter() {
        let tile = gltile::Tile::make(*gltile::colors::YELLOW, *gltile::colors::BLACK, pix);
        renderer.set(gltile::units::ScreenTile2D::new(5 + offset.0, 10), tile);
    }

    let render = |_| {
        renderer.render();
        looper::Action::Continue
    };

    let update = |_| {
        for ev in display.poll_events() {
            match ev {
                glium::glutin::Event::Closed => return looper::Action::Stop,
                _ => (),
            }
        }
        looper::Action::Continue
    };

    looper::Looper::new(60.0).run(render, update);
}
<|endoftext|>