<commit_before>#![deny(missing_docs)]

//! A SDL2 window back-end for the Piston game engine.

extern crate sdl2;
extern crate window;
extern crate input;
extern crate shader_version;
extern crate gl;

// External crates.
use window::{
    BuildFromWindowSettings,
    OpenGLWindow,
    ProcAddress,
    Window,
    AdvancedWindow,
    WindowSettings,
    Size,
};
use input::{ keyboard, Button, MouseButton, Input, Motion };

pub use shader_version::OpenGL;

/// A widow implemented by SDL2 back-end.
pub struct Sdl2Window {
    /// SDL window handle.
    pub window: sdl2::video::Window,
    /// Allow dead code because this keeps track of the OpenGL context.
    /// Will be released on drop.
    #[allow(dead_code)]
    pub context: sdl2::video::GLContext,
    /// SDL context.
    pub sdl_context: sdl2::Sdl,
    /// Video subsystem.
    pub video_subsystem: sdl2::VideoSubsystem,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    exit_on_esc: bool,
    title: String,
    size: Size,
    draw_size: Size,
}

impl Sdl2Window {
    /// Creates a new game window for SDL2. This will initialize SDL and the video subsystem.
    /// You can retrieve both via the public fields on the `Sdl2Window` struct.
    pub fn new(settings: WindowSettings) -> Result<Self, String> {
        let sdl = try!(sdl2::init().map_err(|e| format!("{}", e)));
        let video_subsystem = try!(sdl.video()
            .map_err(|e| format!("{}", e)));
        Self::with_subsystem(video_subsystem, settings)
    }

    /// Creates a window with the supplied SDL Video subsystem.
    pub fn with_subsystem(video_subsystem: sdl2::VideoSubsystem, settings: WindowSettings) -> Result<Self, String> {
        use sdl2::video::GLProfile;

        let sdl_context = video_subsystem.sdl();

        let opengl = settings.get_maybe_opengl().unwrap_or(OpenGL::V3_2);
        let (major, minor) = opengl.get_major_minor();

        {
            let gl_attr = video_subsystem.gl_attr();

            // Not all drivers default to 32bit color, so explicitly set it to 32bit color.
            gl_attr.set_red_size(8);
            gl_attr.set_green_size(8);
            gl_attr.set_blue_size(8);
            gl_attr.set_alpha_size(8);
            gl_attr.set_stencil_size(8);
            gl_attr.set_context_version(major as u8, minor as u8);
        }

        if opengl >= OpenGL::V3_2 {
            video_subsystem.gl_attr().set_context_profile(GLProfile::Core);
        }
        if settings.get_samples() != 0 {
            let gl_attr = video_subsystem.gl_attr();
            gl_attr.set_multisample_buffers(1);
            gl_attr.set_multisample_samples(settings.get_samples());
        }

        let mut window_builder = video_subsystem.window(
            &settings.get_title(),
            settings.get_size().width as u32,
            settings.get_size().height as u32
        );

        let window_builder = window_builder.position_centered()
            .opengl()
            .resizable();

        let window_builder = if settings.get_fullscreen() {
            window_builder.fullscreen()
        } else {
            window_builder
        };

        let window = window_builder.build();

        let window = match window {
            Ok(w) => w,
            Err(_) =>
                if settings.get_samples() != 0 {
                    // Retry without requiring anti-aliasing.
                    let gl_attr = video_subsystem.gl_attr();
                    gl_attr.set_multisample_buffers(0);
                    gl_attr.set_multisample_samples(0);
                    try!(window_builder.build().map_err(|e| format!("{}", e)))
                } else {
                    try!(window.map_err(|e| format!("{}", e)))
                }
        };

        // Send text input events.
        video_subsystem.text_input().start();

        let context = try!(window.gl_create_context()
            .map_err(|e| format!("{}", e)));

        // Load the OpenGL function pointers.
        gl::load_with(|name| video_subsystem.gl_get_proc_address(name));

        if settings.get_vsync() {
            video_subsystem.gl_set_swap_interval(1);
        } else {
            video_subsystem.gl_set_swap_interval(0);
        }

        let mut window = Sdl2Window {
            exit_on_esc: settings.get_exit_on_esc(),
            should_close: false,
            window: window,
            context: context,
            sdl_context: sdl_context,
            video_subsystem: video_subsystem,
            mouse_relative: None,
            title: settings.get_title() ,
            size: settings.get_size(),
            draw_size: settings.get_size(),
        };
        window.update_draw_size();
        Ok(window)
    }

    fn update_draw_size(&mut self) {
        let (w, h) = self.window.drawable_size();
        self.draw_size = Size { width: w as u32, height: h as u32 };
    }

    fn poll_event(&mut self) -> Option<Input> {
        // First check for a pending relative mouse move event.
        if let Some((x, y)) = self.mouse_relative {
            self.mouse_relative = None;
            return Some(Input::Move(Motion::MouseRelative(x, y)));
        }

        // Even though we create a new EventPump each time we poll an event
        // this should not be a problem since it only contains phantom data
        // and therefore should actually not have any overhead.
        let event = match self.sdl_context.event_pump().unwrap().poll_event() {
            Some( ev ) => ev,
            None => return None
        };
        match event {
            sdl2::event::Event::Quit{..} => {
                self.should_close = true;
            }
            sdl2::event::Event::TextInput { text, .. } => {
                return Some(Input::Text(text));
            }
            sdl2::event::Event::KeyDown { keycode: Some(key), repeat, ..} => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                if repeat {
                    return self.poll_event()
                }

                if self.exit_on_esc
                && key == sdl2::keyboard::Keycode::Escape {
                    self.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(sdl2_map_key(key))));
                }
            }
            sdl2::event::Event::KeyUp { keycode: Some(key), repeat, .. } => {
                if repeat {
                    return self.poll_event()
                }
                return Some(Input::Release(Button::Keyboard(sdl2_map_key(key))));
            }
            sdl2::event::Event::MouseButtonDown { mouse_btn: button, .. } => {
                return Some(Input::Press(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseButtonUp { mouse_btn: button, .. } => {
                return Some(Input::Release(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseMotion { x, y, xrel: dx, yrel: dy, .. } => {
                // Send relative move movement next time.
                self.mouse_relative = Some((dx as f64, dy as f64));
                return Some(Input::Move(Motion::MouseCursor(x as f64, y as f64)));
            },
            sdl2::event::Event::MouseWheel { x, y, .. } => {
                return Some(Input::Move(Motion::MouseScroll(x as f64, y as f64)));
            }
            sdl2::event::Event::Window {
                win_event_id: sdl2::event::WindowEventId::Resized, data1: w, data2: h, .. } => {
                self.size.width = w as u32;
                self.size.height = h as u32;
                self.update_draw_size();
                return Some(Input::Resize(w as u32, h as u32));
            }
            sdl2::event::Event::Window { win_event_id: sdl2::event::WindowEventId::FocusGained, .. } => {
                return Some(Input::Focus(true));
            }
            sdl2::event::Event::Window { win_event_id: sdl2::event::WindowEventId::FocusLost, .. } => {
                return Some(Input::Focus(false));
            }
            sdl2::event::Event::Window { win_event_id: sdl2::event::WindowEventId::Enter, .. } => {
                return Some(Input::Cursor(true));
            }
            sdl2::event::Event::Window { win_event_id: sdl2::event::WindowEventId::Leave, .. } => {
                return Some(Input::Cursor(false));
            }
            _ => {}
        }
        None
    }
}

impl BuildFromWindowSettings for Sdl2Window {
    fn build_from_window_settings(settings: WindowSettings)
    -> Result<Self, String> {
        Sdl2Window::new(settings)
    }
}

impl Drop for Sdl2Window {
    fn drop(&mut self) {
        self.set_capture_cursor(false);
    }
}

impl Window for Sdl2Window {
    type Event = Input;

    fn should_close(&self) -> bool { self.should_close }
    fn set_should_close(&mut self, value: bool) { self.should_close = value; }
    fn swap_buffers(&mut self) { self.window.gl_swap_window(); }
    fn size(&self) -> Size { self.size }
    fn poll_event(&mut self) -> Option<Input> { self.poll_event() }
    fn draw_size(&self) -> Size { self.draw_size }
}

impl AdvancedWindow for Sdl2Window {
    fn get_title(&self) -> String {
        self.title.clone()
    }
    fn set_title(&mut self, value: String) {
        let _ = self.window.set_title(&value);
        self.title = value
    }
    fn get_exit_on_esc(&self) -> bool { self.exit_on_esc }
    fn set_exit_on_esc(&mut self, value: bool) { self.exit_on_esc = value; }
    fn set_capture_cursor(&mut self, value: bool) {
        self.sdl_context.mouse().set_relative_mouse_mode(value);
    }
}

impl OpenGLWindow for Sdl2Window {
    fn get_proc_address(&mut self, proc_name: &str) -> ProcAddress {
        self.video_subsystem.gl_get_proc_address(proc_name)
    }

    fn is_current(&self) -> bool {
        self.context.is_current()
    }

    fn make_current(&mut self) {
        self.window.gl_make_current(&self.context).unwrap();
    }
}

/// Maps a SDL2 key to piston-input key.
pub fn sdl2_map_key(keycode: sdl2::keyboard::Keycode) -> keyboard::Key {
    (keycode as u32).into()
}

/// Maps a SDL2 mouse button to piston-input button.
pub fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> MouseButton {
    match button {
        sdl2::mouse::Mouse::Left => MouseButton::Left,
        sdl2::mouse::Mouse::Right => MouseButton::Right,
        sdl2::mouse::Mouse::Middle => MouseButton::Middle,
        sdl2::mouse::Mouse::X1 => MouseButton::X1,
        sdl2::mouse::Mouse::X2 => MouseButton::X2,
        sdl2::mouse::Mouse::Unknown(_) => MouseButton::Unknown,
    }
}
<commit_msg>Cleaned up with some imports<commit_after>#![deny(missing_docs)]

//! A SDL2 window back-end for the Piston game engine.

extern crate sdl2;
extern crate window;
extern crate input;
extern crate shader_version;
extern crate gl;

// External crates.
use window::{
    BuildFromWindowSettings,
    OpenGLWindow,
    ProcAddress,
    Window,
    AdvancedWindow,
    WindowSettings,
    Size,
};
use input::{ keyboard, Button, MouseButton, Input, Motion };

pub use shader_version::OpenGL;

/// A widow implemented by SDL2 back-end.
pub struct Sdl2Window {
    /// SDL window handle.
    pub window: sdl2::video::Window,
    /// Allow dead code because this keeps track of the OpenGL context.
    /// Will be released on drop.
    #[allow(dead_code)]
    pub context: sdl2::video::GLContext,
    /// SDL context.
    pub sdl_context: sdl2::Sdl,
    /// Video subsystem.
    pub video_subsystem: sdl2::VideoSubsystem,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    exit_on_esc: bool,
    title: String,
    size: Size,
    draw_size: Size,
}

impl Sdl2Window {
    /// Creates a new game window for SDL2. This will initialize SDL and the video subsystem.
    /// You can retrieve both via the public fields on the `Sdl2Window` struct.
    pub fn new(settings: WindowSettings) -> Result<Self, String> {
        let sdl = try!(sdl2::init().map_err(|e| format!("{}", e)));
        let video_subsystem = try!(sdl.video()
            .map_err(|e| format!("{}", e)));
        Self::with_subsystem(video_subsystem, settings)
    }

    /// Creates a window with the supplied SDL Video subsystem.
    pub fn with_subsystem(video_subsystem: sdl2::VideoSubsystem, settings: WindowSettings) -> Result<Self, String> {
        use sdl2::video::GLProfile;

        let sdl_context = video_subsystem.sdl();

        let opengl = settings.get_maybe_opengl().unwrap_or(OpenGL::V3_2);
        let (major, minor) = opengl.get_major_minor();

        {
            let gl_attr = video_subsystem.gl_attr();

            // Not all drivers default to 32bit color, so explicitly set it to 32bit color.
            gl_attr.set_red_size(8);
            gl_attr.set_green_size(8);
            gl_attr.set_blue_size(8);
            gl_attr.set_alpha_size(8);
            gl_attr.set_stencil_size(8);
            gl_attr.set_context_version(major as u8, minor as u8);
        }

        if opengl >= OpenGL::V3_2 {
            video_subsystem.gl_attr().set_context_profile(GLProfile::Core);
        }
        if settings.get_samples() != 0 {
            let gl_attr = video_subsystem.gl_attr();
            gl_attr.set_multisample_buffers(1);
            gl_attr.set_multisample_samples(settings.get_samples());
        }

        let mut window_builder = video_subsystem.window(
            &settings.get_title(),
            settings.get_size().width as u32,
            settings.get_size().height as u32
        );

        let window_builder = window_builder.position_centered()
            .opengl()
            .resizable();

        let window_builder = if settings.get_fullscreen() {
            window_builder.fullscreen()
        } else {
            window_builder
        };

        let window = window_builder.build();

        let window = match window {
            Ok(w) => w,
            Err(_) =>
                if settings.get_samples() != 0 {
                    // Retry without requiring anti-aliasing.
                    let gl_attr = video_subsystem.gl_attr();
                    gl_attr.set_multisample_buffers(0);
                    gl_attr.set_multisample_samples(0);
                    try!(window_builder.build().map_err(|e| format!("{}", e)))
                } else {
                    try!(window.map_err(|e| format!("{}", e)))
                }
        };

        // Send text input events.
        video_subsystem.text_input().start();

        let context = try!(window.gl_create_context()
            .map_err(|e| format!("{}", e)));

        // Load the OpenGL function pointers.
        gl::load_with(|name| video_subsystem.gl_get_proc_address(name));

        if settings.get_vsync() {
            video_subsystem.gl_set_swap_interval(1);
        } else {
            video_subsystem.gl_set_swap_interval(0);
        }

        let mut window = Sdl2Window {
            exit_on_esc: settings.get_exit_on_esc(),
            should_close: false,
            window: window,
            context: context,
            sdl_context: sdl_context,
            video_subsystem: video_subsystem,
            mouse_relative: None,
            title: settings.get_title() ,
            size: settings.get_size(),
            draw_size: settings.get_size(),
        };
        window.update_draw_size();
        Ok(window)
    }

    fn update_draw_size(&mut self) {
        let (w, h) = self.window.drawable_size();
        self.draw_size = Size { width: w as u32, height: h as u32 };
    }

    fn poll_event(&mut self) -> Option<Input> {
        use sdl2::event::{ Event, WindowEventId };

        // First check for a pending relative mouse move event.
        if let Some((x, y)) = self.mouse_relative {
            self.mouse_relative = None;
            return Some(Input::Move(Motion::MouseRelative(x, y)));
        }

        // Even though we create a new EventPump each time we poll an event
        // this should not be a problem since it only contains phantom data
        // and therefore should actually not have any overhead.
        let event = match self.sdl_context.event_pump().unwrap().poll_event() {
            Some( ev ) => ev,
            None => return None
        };
        match event {
            Event::Quit{..} => {
                self.should_close = true;
            }
            Event::TextInput { text, .. } => {
                return Some(Input::Text(text));
            }
            Event::KeyDown { keycode: Some(key), repeat, ..} => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                if repeat {
                    return self.poll_event()
                }

                if self.exit_on_esc
                && key == sdl2::keyboard::Keycode::Escape {
                    self.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(sdl2_map_key(key))));
                }
            }
            Event::KeyUp { keycode: Some(key), repeat, .. } => {
                if repeat {
                    return self.poll_event()
                }
                return Some(Input::Release(Button::Keyboard(sdl2_map_key(key))));
            }
            Event::MouseButtonDown { mouse_btn: button, .. } => {
                return Some(Input::Press(Button::Mouse(sdl2_map_mouse(button))));
            }
            Event::MouseButtonUp { mouse_btn: button, .. } => {
                return Some(Input::Release(Button::Mouse(sdl2_map_mouse(button))));
            }
            Event::MouseMotion { x, y, xrel: dx, yrel: dy, .. } => {
                // Send relative move movement next time.
                self.mouse_relative = Some((dx as f64, dy as f64));
                return Some(Input::Move(Motion::MouseCursor(x as f64, y as f64)));
            },
            Event::MouseWheel { x, y, .. } => {
                return Some(Input::Move(Motion::MouseScroll(x as f64, y as f64)));
            }
            Event::Window {
                win_event_id: sdl2::event::WindowEventId::Resized, data1: w, data2: h, .. } => {
                self.size.width = w as u32;
                self.size.height = h as u32;
                self.update_draw_size();
                return Some(Input::Resize(w as u32, h as u32));
            }
            Event::Window { win_event_id: WindowEventId::FocusGained, .. } => {
                return Some(Input::Focus(true));
            }
            Event::Window { win_event_id: WindowEventId::FocusLost, .. } => {
                return Some(Input::Focus(false));
            }
            Event::Window { win_event_id: WindowEventId::Enter, .. } => {
                return Some(Input::Cursor(true));
            }
            Event::Window { win_event_id: WindowEventId::Leave, .. } => {
                return Some(Input::Cursor(false));
            }
            _ => {}
        }
        None
    }
}

impl BuildFromWindowSettings for Sdl2Window {
    fn build_from_window_settings(settings: WindowSettings)
    -> Result<Self, String> {
        Sdl2Window::new(settings)
    }
}

impl Drop for Sdl2Window {
    fn drop(&mut self) {
        self.set_capture_cursor(false);
    }
}

impl Window for Sdl2Window {
    type Event = Input;

    fn should_close(&self) -> bool { self.should_close }
    fn set_should_close(&mut self, value: bool) { self.should_close = value; }
    fn swap_buffers(&mut self) { self.window.gl_swap_window(); }
    fn size(&self) -> Size { self.size }
    fn poll_event(&mut self) -> Option<Input> { self.poll_event() }
    fn draw_size(&self) -> Size { self.draw_size }
}

impl AdvancedWindow for Sdl2Window {
    fn get_title(&self) -> String {
        self.title.clone()
    }
    fn set_title(&mut self, value: String) {
        let _ = self.window.set_title(&value);
        self.title = value
    }
    fn get_exit_on_esc(&self) -> bool { self.exit_on_esc }
    fn set_exit_on_esc(&mut self, value: bool) { self.exit_on_esc = value; }
    fn set_capture_cursor(&mut self, value: bool) {
        self.sdl_context.mouse().set_relative_mouse_mode(value);
    }
}

impl OpenGLWindow for Sdl2Window {
    fn get_proc_address(&mut self, proc_name: &str) -> ProcAddress {
        self.video_subsystem.gl_get_proc_address(proc_name)
    }

    fn is_current(&self) -> bool {
        self.context.is_current()
    }

    fn make_current(&mut self) {
        self.window.gl_make_current(&self.context).unwrap();
    }
}

/// Maps a SDL2 key to piston-input key.
pub fn sdl2_map_key(keycode: sdl2::keyboard::Keycode) -> keyboard::Key {
    (keycode as u32).into()
}

/// Maps a SDL2 mouse button to piston-input button.
pub fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> MouseButton {
    match button {
        sdl2::mouse::Mouse::Left => MouseButton::Left,
        sdl2::mouse::Mouse::Right => MouseButton::Right,
        sdl2::mouse::Mouse::Middle => MouseButton::Middle,
        sdl2::mouse::Mouse::X1 => MouseButton::X1,
        sdl2::mouse::Mouse::X2 => MouseButton::X2,
        sdl2::mouse::Mouse::Unknown(_) => MouseButton::Unknown,
    }
}
<|endoftext|>


<commit_before>#![feature(unique, alloc, heap_api, question_mark)]
#![warn(missing_docs)]

/*!
# Owning bytes

This crate allows you to wrap up and parse around structs that have members that reference a block
of bytes. This is especially useful for writing protocol parses where you want to do zero copy
parsing.

For example:

```
use owning_bytes::OwningByteBuf;

struct ExampleParsed<'a> {
    payload: &'a [u8],
}

impl<'a> ExampleParsed<'a> {
    pub fn parse_buf(buf: &'a [u8]) -> ExampleParsed<'a> {
        ExampleParsed { payload: &buf[1..3] }
    }
}

fn create_from_vec(vec: Vec<u8>) -> OwningByteBuf<ExampleParsed<'static>> {
    OwningByteBuf::from_vec(vec, ExampleParsed::parse_buf)
}

fn main() {
    let vec = vec![1, 2, 3, 4];

    let parsed = create_from_vec(vec);

    assert_eq!(&parsed.get().payload, &[2, 3]);
}
```

There are also methods for dealing with constructors that may fail:

```
use owning_bytes::OwningByteBuf;
use std::str::{self, Utf8Error};

fn create_from_vec(vec: Vec<u8>) -> Result<OwningByteBuf<&'static str>, Utf8Error> {
    OwningByteBuf::from_vec_res(vec, str::from_utf8).map_err(|(err, _vec)| err)
}

fn main() {
    let vec = b"Hello".to_vec();

    let parsed = create_from_vec(vec).unwrap();

    assert_eq!(*parsed.get(), "Hello");
}
```
*/

extern crate alloc;

use std::mem;
use std::ptr::Unique;
use std::slice;
use alloc::heap;

use std::convert::AsRef;

/// A wrapper around an array of bytes and an object T that references those bytes.
pub struct OwningByteBuf<T> {
    resource: Unique<u8>,
    len: usize,
    cap: usize,
    inner: T,
}

impl<T> OwningByteBuf<T> {
    /// Creates an OwningByteBuf from a vector and a constructing function
    pub fn from_vec<'a, F>(mut buf: Vec<u8>, f: F) -> OwningByteBuf<T> where F: FnOnce(&'a[u8]) -> T {
        let res = unsafe {
            let ptr = buf.as_mut_ptr();
            let len = buf.len();
            let cap = buf.capacity();
            OwningByteBuf {
                resource: Unique::new(ptr),
                len: len,
                cap: cap,
                inner: f(slice::from_raw_parts(ptr, len)),
            }
        };
        mem::forget(buf);
        res
    }

    /// Creates an OwningByteBuf from a vector and a constructing function that may fail
    ///
    /// ```
    /// use std::str;
    /// use owning_bytes::OwningByteBuf;
    ///
    /// let vec = b"Hello World".to_vec();
    /// let string = OwningByteBuf::from_vec_res(vec, str::from_utf8).unwrap();
    /// assert_eq!(*string.get(), "Hello World");
    /// ```
    pub fn from_vec_res<'a, F, E>(mut buf: Vec<u8>, f: F) -> Result<OwningByteBuf<T>, (E, Vec<u8>)>
        where F: FnOnce(&'a[u8]) -> Result<T, E>
    {
        let res = unsafe {
            let ptr = buf.as_mut_ptr();
            let len = buf.len();
            let cap = buf.capacity();
            OwningByteBuf {
                resource: Unique::new(ptr),
                len: len,
                cap: cap,
                inner: match f(slice::from_raw_parts(ptr, len)) {
                    Ok(t) => t,
                    Err(e) => return Err((e, buf)),
                },
            }
        };
        mem::forget(buf);
        Ok(res)
    }

    /// Creates an OwningByteBuf from a boxed slice and a constructing function
    pub fn from_box<'a, F>(mut buf: Box<[u8]>, f: F) -> OwningByteBuf<T> where F: FnOnce(&'a[u8]) -> T {
        let res = unsafe {
            let ptr = buf.as_mut_ptr();
            let len = buf.len();
            OwningByteBuf {
                resource: Unique::new(ptr),
                len: len,
                cap: len,
                inner: f(slice::from_raw_parts(ptr, len)),
            }
        };
        mem::forget(buf);
        res
    }

    /// Creates an OwningByteBuf from a boxed slice and a constructing function that may fail
    pub fn from_box_res<'a, F, E>(mut buf: Box<[u8]>, f: F) -> Result<OwningByteBuf<T>, (E, Box<[u8]>)>
        where F: FnOnce(&'a[u8]) -> Result<T, E>
    {
        let res = unsafe {
            let ptr = buf.as_mut_ptr();
            let len = buf.len();
            OwningByteBuf {
                resource: Unique::new(ptr),
                len: len,
                cap: len,
                inner: match f(slice::from_raw_parts(ptr, len)) {
                    Ok(t) => t,
                    Err(e) => return Err((e, buf)),
                },
            }
        };
        mem::forget(buf);
        Ok(res)
    }

    /// Returns a reference to the wrapped type.
    pub fn get(&self) -> &T {
        &self.inner
    }

    /// Drops the wrapped type and returns the underlying buffer back as a Vec.
    pub fn into_vec(mut self) -> Vec<u8> {
        let vec = {
            let OwningByteBuf { ref resource, len, cap, .. } = self;

            unsafe {
                Vec::from_raw_parts(**resource, len, cap)
            }
        };

        self.cap = 0;
        self.len = 0;

        vec
    }
}

impl <T> AsRef<T> for OwningByteBuf<T> {
    fn as_ref(&self) -> &T {
        self.get()
    }
}

impl<T> Drop for OwningByteBuf<T> {
    fn drop(&mut self) {
        let elem_size = mem::size_of::<u8>();
        let align = mem::align_of::<u8>();

        let num_bytes = elem_size * self.cap;
        if num_bytes > 0 {
            unsafe {
                heap::deallocate(*self.resource as *mut _, num_bytes, align);
            }
        }
    }
}

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

    struct Test<'a> {
        buf: &'a [u8]
    }

    #[test]
    fn test() {
        let foo = {
            let vec = vec![0,1,2,3];
            OwningByteBuf::from_vec(vec, |buf| Test { buf: &buf[0..2] } )
        };

        assert_eq!(foo.get().buf, &[0, 1]);

        let vec = foo.into_vec();

        assert_eq!(vec, vec![0,1,2,3]);
    }

    #[test]
    fn test_res() {
        let vec = vec![0,1,2,3];
        let res: Result<_,((),_)> = OwningByteBuf::from_vec_res(vec, |buf| Ok(Test { buf: &buf[0..2] }) );
        assert_eq!(res.unwrap().get().buf, &[0, 1]);

        let vec = vec![0,1,2,3];
        let res: Result<OwningByteBuf<()>, _> = OwningByteBuf::from_vec_res(vec, |_| Err(()) );
        assert!(res.is_err());
    }
}
<commit_msg>Move construction of inner to before construction of Unique<commit_after>#![feature(unique, alloc, heap_api, question_mark)]
#![warn(missing_docs)]

/*!
# Owning bytes

This crate allows you to wrap up and parse around structs that have members that reference a block
of bytes. This is especially useful for writing protocol parses where you want to do zero copy
parsing.

For example:

```
use owning_bytes::OwningByteBuf;

struct ExampleParsed<'a> {
    payload: &'a [u8],
}

impl<'a> ExampleParsed<'a> {
    pub fn parse_buf(buf: &'a [u8]) -> ExampleParsed<'a> {
        ExampleParsed { payload: &buf[1..3] }
    }
}

fn create_from_vec(vec: Vec<u8>) -> OwningByteBuf<ExampleParsed<'static>> {
    OwningByteBuf::from_vec(vec, ExampleParsed::parse_buf)
}

fn main() {
    let vec = vec![1, 2, 3, 4];

    let parsed = create_from_vec(vec);

    assert_eq!(&parsed.get().payload, &[2, 3]);
}
```

There are also methods for dealing with constructors that may fail:

```
use owning_bytes::OwningByteBuf;
use std::str::{self, Utf8Error};

fn create_from_vec(vec: Vec<u8>) -> Result<OwningByteBuf<&'static str>, Utf8Error> {
    OwningByteBuf::from_vec_res(vec, str::from_utf8).map_err(|(err, _vec)| err)
}

fn main() {
    let vec = b"Hello".to_vec();

    let parsed = create_from_vec(vec).unwrap();

    assert_eq!(*parsed.get(), "Hello");
}
```
*/

extern crate alloc;

use std::mem;
use std::ptr::Unique;
use std::slice;
use alloc::heap;

use std::convert::AsRef;

/// A wrapper around an array of bytes and an object T that references those bytes.
pub struct OwningByteBuf<T> {
    resource: Unique<u8>,
    len: usize,
    cap: usize,
    inner: T,
}

impl<T> OwningByteBuf<T> {
    /// Creates an OwningByteBuf from a vector and a constructing function
    pub fn from_vec<'a, F>(mut buf: Vec<u8>, f: F) -> OwningByteBuf<T> where F: FnOnce(&'a[u8]) -> T {
        let res = unsafe {
            let ptr = buf.as_mut_ptr();
            let len = buf.len();
            let cap = buf.capacity();
            let inner = f(slice::from_raw_parts(ptr, len));

            OwningByteBuf {
                resource: Unique::new(ptr),
                len: len,
                cap: cap,
                inner: inner,
            }
        };
        mem::forget(buf);
        res
    }

    /// Creates an OwningByteBuf from a vector and a constructing function that may fail
    ///
    /// ```
    /// use std::str;
    /// use owning_bytes::OwningByteBuf;
    ///
    /// let vec = b"Hello World".to_vec();
    /// let string = OwningByteBuf::from_vec_res(vec, str::from_utf8).unwrap();
    /// assert_eq!(*string.get(), "Hello World");
    /// ```
    pub fn from_vec_res<'a, F, E>(mut buf: Vec<u8>, f: F) -> Result<OwningByteBuf<T>, (E, Vec<u8>)>
        where F: FnOnce(&'a[u8]) -> Result<T, E>
    {
        let res = unsafe {
            let ptr = buf.as_mut_ptr();
            let len = buf.len();
            let cap = buf.capacity();
            OwningByteBuf {
                resource: Unique::new(ptr),
                len: len,
                cap: cap,
                inner: match f(slice::from_raw_parts(ptr, len)) {
                    Ok(t) => t,
                    Err(e) => return Err((e, buf)),
                },
            }
        };
        mem::forget(buf);
        Ok(res)
    }

    /// Creates an OwningByteBuf from a boxed slice and a constructing function
    pub fn from_box<'a, F>(mut buf: Box<[u8]>, f: F) -> OwningByteBuf<T> where F: FnOnce(&'a[u8]) -> T {
        let res = unsafe {
            let ptr = buf.as_mut_ptr();
            let len = buf.len();
            OwningByteBuf {
                resource: Unique::new(ptr),
                len: len,
                cap: len,
                inner: f(slice::from_raw_parts(ptr, len)),
            }
        };
        mem::forget(buf);
        res
    }

    /// Creates an OwningByteBuf from a boxed slice and a constructing function that may fail
    pub fn from_box_res<'a, F, E>(mut buf: Box<[u8]>, f: F) -> Result<OwningByteBuf<T>, (E, Box<[u8]>)>
        where F: FnOnce(&'a[u8]) -> Result<T, E>
    {
        let res = unsafe {
            let ptr = buf.as_mut_ptr();
            let len = buf.len();
            OwningByteBuf {
                resource: Unique::new(ptr),
                len: len,
                cap: len,
                inner: match f(slice::from_raw_parts(ptr, len)) {
                    Ok(t) => t,
                    Err(e) => return Err((e, buf)),
                },
            }
        };
        mem::forget(buf);
        Ok(res)
    }

    /// Returns a reference to the wrapped type.
    pub fn get(&self) -> &T {
        &self.inner
    }

    /// Drops the wrapped type and returns the underlying buffer back as a Vec.
    pub fn into_vec(mut self) -> Vec<u8> {
        let vec = {
            let OwningByteBuf { ref resource, len, cap, .. } = self;

            unsafe {
                Vec::from_raw_parts(**resource, len, cap)
            }
        };

        self.cap = 0;
        self.len = 0;

        vec
    }
}

impl <T> AsRef<T> for OwningByteBuf<T> {
    fn as_ref(&self) -> &T {
        self.get()
    }
}

impl<T> Drop for OwningByteBuf<T> {
    fn drop(&mut self) {
        let elem_size = mem::size_of::<u8>();
        let align = mem::align_of::<u8>();

        let num_bytes = elem_size * self.cap;
        if num_bytes > 0 {
            unsafe {
                heap::deallocate(*self.resource as *mut _, num_bytes, align);
            }
        }
    }
}

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

    struct Test<'a> {
        buf: &'a [u8]
    }

    #[test]
    fn test() {
        let foo = {
            let vec = vec![0,1,2,3];
            OwningByteBuf::from_vec(vec, |buf| Test { buf: &buf[0..2] } )
        };

        assert_eq!(foo.get().buf, &[0, 1]);

        let vec = foo.into_vec();

        assert_eq!(vec, vec![0,1,2,3]);
    }

    #[test]
    fn test_res() {
        let vec = vec![0,1,2,3];
        let res: Result<_,((),_)> = OwningByteBuf::from_vec_res(vec, |buf| Ok(Test { buf: &buf[0..2] }) );
        assert_eq!(res.unwrap().get().buf, &[0, 1]);

        let vec = vec![0,1,2,3];
        let res: Result<OwningByteBuf<()>, _> = OwningByteBuf::from_vec_res(vec, |_| Err(()) );
        assert!(res.is_err());
    }
}
<|endoftext|>


<commit_before>//! Modified 2016 Garrett Berg <vitiral@gmail.com>
//! Copyright 2015 Dawid Ciężarkiewicz
//! See LICENSE-MPL
//!
//! Non-thread-shareable, simple and efficient Circular Buffer
//! implementation that can store N elements when full (typical circular
//! buffer implementations store N-1) without using separate flags.
//!
//! Uses only `core` so can be used in `#[no_std]` projects by using
//! `no_std` feature.
#![no_std]
#![feature(const_fn)]
#![feature(test)]

use core::option::Option::{self, Some, None};
use core::marker::PhantomData;

extern crate test as test;

const CBUF_DATA_BIT: usize = !((usize::max_value() << 1) >> 1);

/// Circular Buffer
///
/// Turns a slice into a Circular buffer with head and tail indexes.
#[derive(Debug)]
pub struct CBuf<'a, T: 'a> {
    buf: &'a mut [T],
    ctrl: CBufControl<T>,
}

/// Circular Buffer Control
///
/// Implements the actual logic of Circular Buffer, but requires passing &[T]
/// to `get` and `put`.
#[derive(Debug)]
pub struct CBufControl<T> {
    head: usize,
    tail: usize,
    phantom: PhantomData<T>,
}

#[cfg(not(feature = "no_std"))]
impl<'a, T: Clone> CBuf<'a, T>
    where T: Clone
{
    /// Create new CBuf
    ///
    /// Length (not capacity) will be used to store elements
    /// in the circular buffer.
    pub fn new(buf: &'a mut [T]) -> CBuf<T> {
        debug_assert!(buf.len() < CBUF_DATA_BIT);

        CBuf {
            buf: buf,
            ctrl: CBufControl::new(),
        }
    }

    /// Is buffer full?
    #[inline]
    pub fn is_full(&self) -> bool {
        self.ctrl.is_full()
    }

    /// Is buffer empty?
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.ctrl.is_empty()
    }

    /// Peek next element from the CBuf without removing it
    ///
    /// Returns `None` if buffer is empty.
    #[inline]
    pub fn peek(&mut self) -> Option<T> {
        self.ctrl.peek(self.buf)
    }

    /// Peek next element from the CBuf without removing it
    ///
    /// Makes the buffer misbehave if it's empty.
    #[inline]
    pub fn peek_unchecked(&mut self) -> T {
        self.ctrl.peek_unchecked(self.buf)
    }

    /// Remove one element from the CBuf
    ///
    /// Returns `None` if buffer is empty.
    #[inline]
    pub fn get(&mut self) -> Option<T> {
        self.ctrl.get(self.buf)
    }

    /// Remove one element from the CBuf
    ///
    /// Makes the buffer misbehave if it's empty.
    #[inline]
    pub fn get_unchecked(&mut self) -> T {
        self.ctrl.get_unchecked(self.buf)
    }

    /// Add element the buffer
    ///
    /// Ignores the write if buffer is full.
    #[inline]
    pub fn put(&mut self, val: T) {
        self.ctrl.put(self.buf, val)
    }

    /// Add element the buffer
    ///
    /// Makes the buffer misbehave if it's full.
    #[inline]
    pub fn put_unchecked(&mut self, val: T) {
        self.ctrl.put_unchecked(self.buf, val)
    }
}

impl<T: Clone> CBufControl<T> {
    pub fn new() -> CBufControl<T> {
        CBufControl {
            tail: 0,
            head: 0,
            phantom: PhantomData,
        }
    }

    /// See corresponding method of CBuf
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.head == self.tail
    }

    /// See corresponding method of CBuf
    #[inline]
    pub fn is_full(&self) -> bool {
        (self.head ^ self.tail) == CBUF_DATA_BIT
    }

    /// See corresponding method of CBuf
    pub fn get(&mut self, buf: &[T]) -> Option<T> {
        if self.is_empty() {
            return None;
        }
        Some(self.get_unchecked(buf))
    }

    /// See corresponding method of CBuf
    pub fn get_unchecked(&mut self, buf: &[T]) -> T {
        let val = buf[self.tail & !CBUF_DATA_BIT].clone();

        self.tail += 1;

        if (self.tail & !CBUF_DATA_BIT) >= buf.len() {
            self.tail = (self.tail - buf.len()) ^ CBUF_DATA_BIT;
        }

        val
    }

    /// See corresponding method of CBuf
    pub fn peek(&mut self, buf: &[T]) -> Option<T> {
        if self.is_empty() {
            return None;
        }
        Some(self.peek_unchecked(buf))
    }

    /// See corresponding method of CBuf
    pub fn peek_unchecked(&mut self, buf: &[T]) -> T {
        buf[self.tail & !CBUF_DATA_BIT].clone()
    }

    /// See corresponding method of CBuf
    pub fn put(&mut self, buf: &mut [T], val: T) {
        if self.is_full() {
            return;
        }
        self.put_unchecked(buf, val)
    }

    /// See corresponding method of CBuf
    pub fn put_unchecked(&mut self, buf: &mut [T], val: T) {
        buf[self.head & !CBUF_DATA_BIT] = val;

        self.head += 1;

        if (self.head & !CBUF_DATA_BIT) >= buf.len() {
            self.head = (self.head - buf.len()) ^ CBUF_DATA_BIT;
        }
    }
}

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

    #[test]
    fn basic_ctl() {
        let mut buf = &mut [0u8, 2];
        let mut cbuf = CBufControl::<u8>::new();

        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        cbuf.put(buf, 3);
        cbuf.put(buf, 4);
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.peek(buf).unwrap(), 3);
        cbuf.peek(buf).unwrap();
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.get(buf).unwrap(), 3);
        assert_eq!(cbuf.get(buf).unwrap(), 4);
        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());
    }

    #[test]
    fn basic_cbuf() {
        let mut buf = &mut [0u8, 0u8];
        let mut cbuf = CBuf::new(buf);

        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        cbuf.put(3);
        cbuf.put(4);
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.peek().unwrap(), 3);
        cbuf.peek().unwrap();
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.get().unwrap(), 3);
        assert_eq!(cbuf.get().unwrap(), 4);
        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());
    }

    #[test]
    fn patterns() {
        let mut buf = [0u8, 7];
        let mut cbuf = CBufControl::<u8>::new();

        let mut cur_len = 0;
        let mut put_val = 0;
        let mut get_val = 0;

        for pattern in 0..256 {
            if cur_len == 0 {
                assert!(cbuf.is_empty());
            }
            if cur_len == buf.len() {
                assert!(cbuf.is_full());
            }

            for bit_i in 0..8 {
                match pattern & (1 << bit_i) == 0 {
                    true => {
                        if cbuf.is_empty() {
                            assert!(cbuf.peek(&buf).is_none());
                            assert!(cbuf.get(&buf).is_none());
                        } else {
                            assert!(cbuf.peek(&buf).unwrap() == get_val);
                            let val = cbuf.get(&buf).unwrap();
                            assert!(val == get_val);
                            get_val = get_val.wrapping_add(1);
                            cur_len -= 1;
                        }
                    }
                    false => {
                        if cbuf.is_full() {
                            cbuf.put(&mut buf, put_val);
                            assert!(cbuf.is_full());
                        } else {
                            cbuf.put(&mut buf, put_val);
                            put_val = put_val.wrapping_add(1);
                            cur_len += 1;
                        }
                    }
                }
            }
        }
    }

    #[bench]
    pub fn put_and_get(b: &mut Bencher) {
        let buf = &mut [0u8; 256];
        let mut cbuf = CBuf::new(buf);

        b.iter(|| {
            cbuf.put(0u8);
            cbuf.get();
        });

        test::black_box(cbuf.get());
    }

    #[bench]
    pub fn put_unchecked_and_get(b: &mut Bencher) {
        let buf = &mut [0u8; 256];
        let mut cbuf = CBuf::new(buf);

        b.iter(|| {
            cbuf.put_unchecked(0u8);
            cbuf.get_unchecked();
        });

        test::black_box(cbuf.get());
    }
}
<commit_msg>improve tests<commit_after>//! Modified 2016 Garrett Berg <vitiral@gmail.com>
//! Copyright 2015 Dawid Ciężarkiewicz
//! See LICENSE-MPL
//!
//! Non-thread-shareable, simple and efficient Circular Buffer
//! implementation that can store N elements when full (typical circular
//! buffer implementations store N-1) without using separate flags.
//!
//! Uses only `core` so can be used in `#[no_std]` projects by using
//! `no_std` feature.
#![no_std]
#![feature(const_fn)]
#![feature(test)]

use core::option::Option::{self, Some, None};
use core::marker::PhantomData;

extern crate test as test;

const CBUF_DATA_BIT: usize = !((usize::max_value() << 1) >> 1);

/// Circular Buffer
///
/// Turns a slice into a Circular buffer with head and tail indexes.
#[derive(Debug)]
pub struct CBuf<'a, T: 'a> {
    buf: &'a mut [T],
    ctrl: CBufControl<T>,
}

/// Circular Buffer Control
///
/// Implements the actual logic of Circular Buffer, but requires passing &[T]
/// to `get` and `put`.
#[derive(Debug)]
pub struct CBufControl<T> {
    head: usize,
    tail: usize,
    phantom: PhantomData<T>,
}

#[cfg(not(feature = "no_std"))]
impl<'a, T: Clone> CBuf<'a, T>
    where T: Clone
{
    /// Create new CBuf
    ///
    /// Length (not capacity) will be used to store elements
    /// in the circular buffer.
    pub fn new(buf: &'a mut [T]) -> CBuf<T> {
        debug_assert!(buf.len() < CBUF_DATA_BIT);

        CBuf {
            buf: buf,
            ctrl: CBufControl::new(),
        }
    }

    /// Is buffer full?
    #[inline]
    pub fn is_full(&self) -> bool {
        self.ctrl.is_full()
    }

    /// Is buffer empty?
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.ctrl.is_empty()
    }

    /// Peek next element from the CBuf without removing it
    ///
    /// Returns `None` if buffer is empty.
    #[inline]
    pub fn peek(&mut self) -> Option<T> {
        self.ctrl.peek(self.buf)
    }

    /// Peek next element from the CBuf without removing it
    ///
    /// Makes the buffer misbehave if it's empty.
    #[inline]
    pub fn peek_unchecked(&mut self) -> T {
        self.ctrl.peek_unchecked(self.buf)
    }

    /// Remove one element from the CBuf
    ///
    /// Returns `None` if buffer is empty.
    #[inline]
    pub fn get(&mut self) -> Option<T> {
        self.ctrl.get(self.buf)
    }

    /// Remove one element from the CBuf
    ///
    /// Makes the buffer misbehave if it's empty.
    #[inline]
    pub fn get_unchecked(&mut self) -> T {
        self.ctrl.get_unchecked(self.buf)
    }

    /// Add element the buffer
    ///
    /// Ignores the write if buffer is full.
    #[inline]
    pub fn put(&mut self, val: T) {
        self.ctrl.put(self.buf, val)
    }

    /// Add element the buffer
    ///
    /// Makes the buffer misbehave if it's full.
    #[inline]
    pub fn put_unchecked(&mut self, val: T) {
        self.ctrl.put_unchecked(self.buf, val)
    }
}

impl<T: Clone> CBufControl<T> {
    pub fn new() -> CBufControl<T> {
        CBufControl {
            tail: 0,
            head: 0,
            phantom: PhantomData,
        }
    }

    /// See corresponding method of CBuf
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.head == self.tail
    }

    /// See corresponding method of CBuf
    #[inline]
    pub fn is_full(&self) -> bool {
        (self.head ^ self.tail) == CBUF_DATA_BIT
    }

    /// See corresponding method of CBuf
    pub fn get(&mut self, buf: &[T]) -> Option<T> {
        if self.is_empty() {
            return None;
        }
        Some(self.get_unchecked(buf))
    }

    /// See corresponding method of CBuf
    pub fn get_unchecked(&mut self, buf: &[T]) -> T {
        let val = buf[self.tail & !CBUF_DATA_BIT].clone();

        self.tail += 1;

        if (self.tail & !CBUF_DATA_BIT) >= buf.len() {
            self.tail = (self.tail - buf.len()) ^ CBUF_DATA_BIT;
        }

        val
    }

    /// See corresponding method of CBuf
    pub fn peek(&mut self, buf: &[T]) -> Option<T> {
        if self.is_empty() {
            return None;
        }
        Some(self.peek_unchecked(buf))
    }

    /// See corresponding method of CBuf
    pub fn peek_unchecked(&mut self, buf: &[T]) -> T {
        buf[self.tail & !CBUF_DATA_BIT].clone()
    }

    /// See corresponding method of CBuf
    pub fn put(&mut self, buf: &mut [T], val: T) {
        if self.is_full() {
            return;
        }
        self.put_unchecked(buf, val)
    }

    /// See corresponding method of CBuf
    pub fn put_unchecked(&mut self, buf: &mut [T], val: T) {
        buf[self.head & !CBUF_DATA_BIT] = val;

        self.head += 1;

        if (self.head & !CBUF_DATA_BIT) >= buf.len() {
            self.head = (self.head - buf.len()) ^ CBUF_DATA_BIT;
        }
    }
}

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

    #[test]
    fn basic_ctl() {
        let mut buf = &mut [0u8, 2];
        let mut cbuf = CBufControl::<u8>::new();

        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        cbuf.put(buf, 3);
        cbuf.put(buf, 4);
        cbuf.put(buf, 42); // will have no effect
        cbuf.put(buf, 42); // will have no effect
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.peek(buf).unwrap(), 3);
        cbuf.peek(buf).unwrap();
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.get(buf).unwrap(), 3);
        assert_eq!(cbuf.get(buf).unwrap(), 4);
        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        assert!(cbuf.get(buf).is_none());
        assert!(cbuf.get(buf).is_none());
        cbuf.put(buf, 42);
        assert_eq!(cbuf.get(buf).unwrap(), 42);
    }

    #[test]
    fn basic_cbuf() {
        let mut buf = &mut [0u8, 0u8];
        let mut cbuf = CBuf::new(buf);

        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        cbuf.put(3);
        cbuf.put(4);
        cbuf.put(42); // will have no effect
        cbuf.put(42); // will have no effect
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.peek().unwrap(), 3);
        cbuf.peek().unwrap();
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.get().unwrap(), 3);
        assert_eq!(cbuf.get().unwrap(), 4);
        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        assert!(cbuf.get().is_none());
        assert!(cbuf.get().is_none());
        cbuf.put(42);
        assert_eq!(cbuf.get().unwrap(), 42);
    }

    #[test]
    fn patterns() {
        let mut buf = [0u8, 7];
        let mut cbuf = CBufControl::<u8>::new();

        let mut cur_len = 0;
        let mut put_val = 0;
        let mut get_val = 0;

        for pattern in 0..256 {
            if cur_len == 0 {
                assert!(cbuf.is_empty());
            }
            if cur_len == buf.len() {
                assert!(cbuf.is_full());
            }

            for bit_i in 0..8 {
                match pattern & (1 << bit_i) == 0 {
                    true => {
                        if cbuf.is_empty() {
                            assert!(cbuf.peek(&buf).is_none());
                            assert!(cbuf.get(&buf).is_none());
                        } else {
                            assert!(cbuf.peek(&buf).unwrap() == get_val);
                            let val = cbuf.get(&buf).unwrap();
                            assert!(val == get_val);
                            get_val = get_val.wrapping_add(1);
                            cur_len -= 1;
                        }
                    }
                    false => {
                        if cbuf.is_full() {
                            cbuf.put(&mut buf, put_val);
                            assert!(cbuf.is_full());
                        } else {
                            cbuf.put(&mut buf, put_val);
                            put_val = put_val.wrapping_add(1);
                            cur_len += 1;
                        }
                    }
                }
            }
        }
    }

    #[bench]
    pub fn put_and_get(b: &mut Bencher) {
        let buf = &mut [0u8; 256];
        let mut cbuf = CBuf::new(buf);

        b.iter(|| {
            cbuf.put(0u8);
            cbuf.get();
        });

        test::black_box(cbuf.get());
    }

    #[bench]
    pub fn put_unchecked_and_get(b: &mut Bencher) {
        let buf = &mut [0u8; 256];
        let mut cbuf = CBuf::new(buf);

        b.iter(|| {
            cbuf.put_unchecked(0u8);
            cbuf.get_unchecked();
        });

        test::black_box(cbuf.get());
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq, Eq)]
struct GitStatus {
    branch: Option<BranchInfo>,
    staged: bool,
    unstaged: bool,
    untracked: bool,
    ignored: bool,
}

#[derive(Debug, PartialEq, Eq)]
struct BranchInfo {
    object_id: String,
    name: Option<String>,
    upstream: Option<UpstreamInfo>,
}

#[derive(Debug, PartialEq, Eq)]
struct UpstreamInfo {
    name: String,
    ahead: bool,
    behind: bool,
}

impl GitStatus {
    fn new(status_txt: &str) -> Result<GitStatus, &'static str> {
        let mut s = GitStatus {
            branch: None,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        let mut object_id: Option<String> = None;
        let mut branch_name: Option<String> = None;
        let mut upstream_name: Option<String> = None;
        let mut ahead = false;
        let mut behind = false;
        for line in status_txt.lines() {
            let mut words = line.split(' ');
            match words.next() {
                Some("#") => {
                    match words.next() {
                        Some("branch.oid") => {
                            if let Some(oid) = words.next() {
                                object_id = Some(String::from(oid));
                            }
                        },
                        Some("branch.head") => {
                            if let Some(head) = words.next() {
                                branch_name = Some(String::from(head));
                            }
                        }
                        Some("branch.upstream") => {
                            if let Some(upstream) = words.next() {
                                upstream_name = Some(String::from(upstream));
                            }
                        },
                        Some("branch.ab") => {
                            match words.next() {
                                Some("+0") | None => {},
                                Some(_) => ahead = true,
                            }
                            match words.next() {
                                Some("-0") | None => {},
                                Some(_) => behind = true,
                            }
                        },
                        _ => {},
                    }
                },
                Some("1") | Some("2") => {
                    if let Some(changes) = words.next() {
                        let mut changes = changes.chars();
                        match changes.next() {
                            Some('.') | None => {},
                            Some(_) => s.staged = true,
                        }
                        match changes.next() {
                            Some('.') | None => {},
                            Some(_) => s.unstaged = true,
                        }
                    }
                },
                Some("?") => s.untracked = true,
                Some("!") => s.ignored = true,
                Some("") | None => {},
                _ => return Err("Unrecognized line in status"),
            }
        }
        if branch_name == Some(String::from("(detached)")) {
            branch_name = None;
        }
        if let Some(oid) = object_id {
            let mut b_info = BranchInfo {
                object_id: oid,
                name: branch_name,
                upstream: None,
            };
            if let Some(up) = upstream_name {
                b_info.upstream = Some(UpstreamInfo {
                    name: up,
                    ahead: ahead,
                    behind: behind,
                });
            }
            s.branch = Some(b_info);
        }
        Ok(s)
    }

    fn to_line(&self) -> String {
        let mut line = String::from("(");
        if self.staged {
            line.push('+');
        }
        if self.unstaged {
            line.push('*');
        }
        if self.untracked {
            line.push('?');
        }
        if self.ignored {
            line.push('!');
        }
        line.push_str(") ");
        line
    }
}

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

    #[test]
    fn parse_clean() {
        let test_status = "\n";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                branch: None,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_branch() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().branch,
            Some(BranchInfo {
                object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                name: Some(String::from("master")),
                upstream: None,

            })
        );
    }

    #[test]
    fn parse_detached_head() {
        let test_status = "\
# branch.oid 2a7bb916bba69a5fc9d428acc80b1bce64e3e0bc
# branch.head (detached)
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().branch,
            Some(BranchInfo {
                object_id: String::from("2a7bb916bba69a5fc9d428acc80b1bce64e3e0bc"),
                name: None,
                upstream: None,
            })
        );
    }

    #[test]
    fn parse_upstream() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
";
        assert_eq!(
            GitStatus::new(test_status).unwrap().branch,
            Some(BranchInfo {
                object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                name: Some(String::from("master")),
                upstream: Some(UpstreamInfo {
                    name: String::from("origin/master"),
                    ahead: true,
                    behind: true,
                }),
            })
        );
    }

    #[test]
    fn parse_staged_only() {
        let test_status = "1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md\n";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unstaged_only() {
        let test_status = "1 .M N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 README.md\n";
        let s = GitStatus::new(test_status).unwrap();
        assert!(!s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_both_staged_and_unstaged() {
        let test_status = "1 MM N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md\n";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_deleted() {
        let test_status = "1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md\n";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_renamed() {
        let test_status = "2 R. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 R100 README	README.md\n";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_untracked() {
        let test_status = "? foo.txt\n";
        assert!(GitStatus::new(test_status).unwrap().untracked);
    }

    #[test]
    fn parse_ignored() {
        let test_status = "! node_modules/\n";
        assert!(GitStatus::new(test_status).unwrap().ignored);
    }

    #[test]
    fn parse_very_dirty() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
1 .M N... 100644 100644 100644 5e8a8090976077ddf16252a560460a20dbbdd6a5 5e8a8090976077ddf16252a560460a20dbbdd6a5 gh-pages.sh
? foo.txt
! ignored.txt
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                branch: Some(BranchInfo {
                    object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                    name: Some(String::from("master")),
                    upstream: Some(UpstreamInfo {
                        name: String::from("origin/master"),
                        ahead: true,
                        behind: true,
                    }),
                }),
                staged: true,
                unstaged: true,
                untracked: true,
                ignored: true,
            }
        );
    }

    #[test]
    fn parse_improper_status() {
        assert_eq!(GitStatus::new("foo"), Err("Unrecognized line in status"));
    }

    #[test]
    fn test_to_line_clean_no_branch() {
        let s = GitStatus {
            branch: None,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("() "));
    }

    #[test]
    fn test_to_line_clean_with_branch() {
        let s = GitStatus {
            branch: Some(BranchInfo {
                object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                name: Some(String::from("master")),
                upstream: None,
            }),
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("(master) "));
    }

    #[test]
    fn test_to_line_dirty() {
        let s = GitStatus {
            branch: Some(BranchInfo {
                object_id: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                name: Some(String::from("master")),
                upstream: Some(UpstreamInfo {
                    name: String::from("origin/master"),
                    ahead: true,
                    behind: true,
                }),
            }),
            staged: true,
            unstaged: true,
            untracked: true,
            ignored: true,
        };
        assert_eq!(s.to_line(), String::from("(master AB+*?!) "));
    }
}
<commit_msg>Refactor, branch information is now mandatory<commit_after>#[derive(Debug, PartialEq, Eq)]
struct GitStatus {
    oid: String,
    branch: String,
    upstream: Option<String>,
    ahead: bool,
    behind: bool,
    staged: bool,
    unstaged: bool,
    untracked: bool,
    ignored: bool,
}

impl GitStatus {
    fn new(status_txt: &str) -> Result<GitStatus, &'static str> {
        let mut s = GitStatus {
            oid: String::new(),
            branch: String::new(),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        for line in status_txt.lines() {
            let mut words = line.split(' ');
            match words.next() {
                Some("#") => {
                    match words.next() {
                        Some("branch.oid") => {
                            match words.next() {
                                Some(oid) => s.oid = String::from(oid),
                                None => return Err("Bad input"),
                            }
                        },
                        Some("branch.head") => {
                            match words.next() {
                                Some(branch) => s.branch = String::from(branch),
                                None => return Err("Bad input"),
                            }
                        }
                        Some("branch.upstream") => {
                            match words.next() {
                                Some(upstream) => s.upstream = Some(String::from(upstream)),
                                None => return Err("Bad input"),
                            }
                        },
                        Some("branch.ab") => {
                            match words.next() {
                                Some("+0") => {},
                                Some(_) => s.ahead = true,
                                None => return Err("Bad input"),
                            }
                            match words.next() {
                                Some("-0") => {},
                                Some(_) => s.behind = true,
                                None => return Err("Bad input"),
                            }
                        },
                        _ => return Err("Bad input"),
                    }
                },
                Some("1") | Some("2") => {
                    if let Some(changes) = words.next() {
                        let mut changes = changes.chars();
                        match changes.next() {
                            Some('.') => {},
                            Some(_) => s.staged = true,
                            None => return Err("Bad input"),
                        }
                        match changes.next() {
                            Some('.') => {},
                            Some(_) => s.unstaged = true,
                            None => return Err("Bad input"),
                        }
                    }
                },
                Some("?") => s.untracked = true,
                Some("!") => s.ignored = true,
                Some("") | None => {},
                _ => return Err("Bad input"),
            }
        }
        Ok(s)
    }

    fn to_line(&self) -> String {
        let mut line = String::from("[");
        if self.staged {
            line.push('+');
        }
        if self.unstaged {
            line.push('*');
        }
        if self.untracked {
            line.push('?');
        }
        if self.ignored {
            line.push('!');
        }
        line.push_str("] ");
        line
    }
}

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

    #[test]
    fn parse_clean() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: None,
                ahead: false,
                behind: false,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_clean_upstream() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_staged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unstaged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 .M N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(!s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_both_staged_and_unstaged() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 MM N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_deleted() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_renamed() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
2 R. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 R100 README	README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_untracked() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
? foo.txt
";
        assert!(GitStatus::new(test_status).unwrap().untracked);
    }

    #[test]
    fn parse_ignored() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
! node_modules/
";
        assert!(GitStatus::new(test_status).unwrap().ignored);
    }

    #[test]
    fn parse_very_dirty() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
1 .M N... 100644 100644 100644 5e8a8090976077ddf16252a560460a20dbbdd6a5 5e8a8090976077ddf16252a560460a20dbbdd6a5 gh-pages.sh
? foo.txt
! ignored.txt
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                staged: true,
                unstaged: true,
                untracked: true,
                ignored: true,
            }
        );
    }

    #[test]
    fn parse_bad_input() {
        assert_eq!(GitStatus::new("foo"), Err("Bad input"));
    }

    #[test]
    fn test_to_line_clean() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a] "));
    }

    #[test]
    fn test_to_line_dirty() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: Some(String::from("origin/master")),
            ahead: true,
            behind: true,
            staged: true,
            unstaged: true,
            untracked: true,
            ignored: true,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a AB+*?!] "));
    }
}
<|endoftext|>


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

//! `Genmesh`'s is a library that offers ways to generate and manipulate vertex streams.
//!
//! The core problem that this library solves is to find a nice way to build meshes that
//! does not just result in throwing all the vertices and indices into a `Vec<T>` and
//! calling it done. While doing so is simple from a library writers point of view, the
//! consumer will often have to translate that buffer to the format that they need before
//! it can be used. This produces needless buffering that can be avoided.
//!
//! `Genmesh`'s solution is to utilize the `Iterator` trait to build a vertex processing
//! pipeline. The `Iterator` trait has a number of useful functions like `zip`, `map` and
//! `collect` that are useful in themselves. `Genmesh` includes a number of traits that
//! can be used with the built in `Iterator` traits to build the meshes that your engine
//! needs.

#![deny(missing_docs)]

extern crate core;

pub use poly::{
    Quad,
    Triangle,
    Polygon,
    Vertices,
    VerticesIterator,
    MapToVertices,
    MapVertex
};

pub use triangulate::{
    EmitTriangles,
    Triangulate,
    TriangulateIterator
};

pub use indexer::{
    Indexer,
    LruIndexer
};

mod triangulate;
mod poly;
mod indexer;
mod generator;

mod cube;
mod plane;
mod sphere;

/// a collection of utilties that can be used to build
/// meshes programmatically
pub mod generators {
    pub use generator::{
        SharedVertex,
        IndexedPolygon,
        SharedVertexIterator,
        IndexedPolygonIterator,
    };
    pub use cube::Cube;
    pub use plane::Plane;
    pub use sphere::SphereUV;
}
<commit_msg>add feature(core)<commit_after>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

//! `Genmesh`'s is a library that offers ways to generate and manipulate vertex streams.
//!
//! The core problem that this library solves is to find a nice way to build meshes that
//! does not just result in throwing all the vertices and indices into a `Vec<T>` and
//! calling it done. While doing so is simple from a library writers point of view, the
//! consumer will often have to translate that buffer to the format that they need before
//! it can be used. This produces needless buffering that can be avoided.
//!
//! `Genmesh`'s solution is to utilize the `Iterator` trait to build a vertex processing
//! pipeline. The `Iterator` trait has a number of useful functions like `zip`, `map` and
//! `collect` that are useful in themselves. `Genmesh` includes a number of traits that
//! can be used with the built in `Iterator` traits to build the meshes that your engine
//! needs.

#![deny(missing_docs)]
#![feature(core)]

extern crate core;

pub use poly::{
    Quad,
    Triangle,
    Polygon,
    Vertices,
    VerticesIterator,
    MapToVertices,
    MapVertex
};

pub use triangulate::{
    EmitTriangles,
    Triangulate,
    TriangulateIterator
};

pub use indexer::{
    Indexer,
    LruIndexer
};

mod triangulate;
mod poly;
mod indexer;
mod generator;

mod cube;
mod plane;
mod sphere;

/// a collection of utilties that can be used to build
/// meshes programmatically
pub mod generators {
    pub use generator::{
        SharedVertex,
        IndexedPolygon,
        SharedVertexIterator,
        IndexedPolygonIterator,
    };
    pub use cube::Cube;
    pub use plane::Plane;
    pub use sphere::SphereUV;
}
<|endoftext|>


<commit_before>//! Growable struct-of-array types with heap allocated contents.
#![allow(unused_features)]

#![feature(alloc)]
#![feature(collections)]
#![feature(core)]
#![feature(hash)]
#![feature(test)]

#![feature(unsafe_no_drop_flag)]
#![feature(filling_drop)]

extern crate alloc;
extern crate collections;
extern crate core;

pub mod soa2;
pub mod soa3;
pub mod soa4;

mod unadorned;
#[cfg(test)] mod test;

pub use soa2::Soa2;
pub use soa3::Soa3;
pub use soa4::Soa4;
<commit_msg>feature cleanup<commit_after>//! Growable struct-of-array types with 16-byte aligned heap allocated contents.
#![feature(alloc)]
#![feature(collections)]
#![feature(core)]

#![feature(unsafe_no_drop_flag)]
#![feature(filling_drop)]

extern crate alloc;
extern crate collections;
extern crate core;

pub mod soa2;
pub mod soa3;
pub mod soa4;

mod unadorned;
#[cfg(test)] mod test;

pub use soa2::Soa2;
pub use soa3::Soa3;
pub use soa4::Soa4;
<|endoftext|>


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

// Crate dependencies
extern crate libc;
extern crate pam_sys as pam;
extern crate users;

// Modules
mod ffi;
mod simple;

// Re-Exports
pub use simple::*;

// Usings
use pam::{PamConversation, PamFlag, PamHandle, PamReturnCode};

/// Main struct to authenticate a user
/// Currently closes the session on drop() but this might change!
pub struct Authenticator<'a> {
    handle:         *mut PamHandle,
    credentials:    Box<[&'a str; 2]>
}

impl <'a> Authenticator<'a> {
    /// Creates a new Authenticator with a given service name
    pub fn new(service: &str) -> Option<Authenticator> {
        use std::ffi::CString;
        use std::ptr;

        let creds = Box::new([""; 2]);
        let conv = PamConversation {
            conv:       Some(ffi::converse),
            data_ptr:   creds.as_ptr() as *mut ::libc::c_void
        };
        let mut handle: *mut PamHandle = ptr::null_mut();

        match unsafe {
            pam::start(CString::new(service).unwrap().as_ptr(), ptr::null(), &conv, &mut handle)
        } {
            PamReturnCode::SUCCESS => Some(Authenticator {
                handle:         handle,
                credentials:    creds
            }),
            _   => None
        }
    }

    /// Set the credentials which should be used in the authentication process
    pub fn set_credentials(&mut self, user: &'a str, password: &'a str) {
        self.credentials[0] = user;
        self.credentials[1] = password;
    }

    /// Perform the authentication with the provided credentials
    pub fn authenticate(&self) -> Result<(), PamReturnCode> {
        let success = PamReturnCode::SUCCESS;

        let mut res = unsafe { pam::authenticate(self.handle, PamFlag::NONE) };
        if res != success {
            return self.cleanup(res);
        }

        res = unsafe { pam::acct_mgmt(self.handle, PamFlag::NONE) };
        if res != success {
            return self.cleanup(res);
        }

        res = unsafe { pam::setcred(self.handle, PamFlag::ESTABLISH_CRED) };
        if res != success {
            return self.cleanup(res);
        }
        Ok(())
    }

    /// Open a session for a previously authenticated user and
    /// initialize the environment appropriately (in PAM and regular enviroment variables).
    ///
    /// Does not currently check for authentication and just calls the ffi method,
    /// but clients should not rely on that.
    pub fn open_session(&self) -> Result<(), PamReturnCode> {
        let res = unsafe { pam::open_session(self.handle, PamFlag::NONE) };
        if res != PamReturnCode::SUCCESS {
            return self.cleanup(res);
        }

        self.initialize_environment()
    }

    // Initialize the client environment with common variables.
    // Currently always called from Authenticator.open_session()
    fn initialize_environment(&self) -> Result<(), PamReturnCode> {
        let user = users::get_user_by_name(self.credentials[0])
            .expect(&format!("Could not get user by name: {:?}", self.credentials[0]));

        self.set_env("USER", &user.name)
            .and(self.set_env("LOGNAME", &user.name))
            .and(self.set_env("HOME", &user.home_dir))
            .and(self.set_env("PWD", &user.home_dir))
            .and(self.set_env("SHELL", &user.shell))
            // Taken from https://github.com/gsingh93/display-manager/blob/master/pam.c
            // Should be a better way to get this. Revisit later.
            .and(self.set_env("PATH", "$PATH:/usr/local/sbin:/usr/local/bin:/usr/bin"))
    }

    // Utility function to set an environment variable in PAM and the process
    fn set_env(&self, key: &str, value: &str) -> Result<(), PamReturnCode> {
        use std::env;
        use std::ffi::CString;

        // Set regular environment variable
        env::set_var(key, value);

        // Set pam environment variable
        let name_value = CString::new(format!("{}={}", key, value)).unwrap();
        match unsafe { pam::putenv(self.handle, name_value.as_ptr()) } {
            PamReturnCode::SUCCESS  => Ok(()),
            code                    => Err(code)
        }
    }

    // Utility function to properly clean up pam
    fn cleanup(&self, code: PamReturnCode) -> Result<(), PamReturnCode> {
        unsafe {
            // Currently the session is closed if PamReturnCode::SUCCESS is passed //TODO: change this
            if code == PamReturnCode::SUCCESS {
                pam::close_session(self.handle, PamFlag::NONE);
            }
            pam::setcred(self.handle, pam::PamFlag::DELETE_CRED);
            pam::end(self.handle, 0);
        }
        Err(code)
    }
}

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

// Crate dependencies
extern crate libc;
extern crate pam_sys as pam;
extern crate users;

// Modules
mod ffi;
mod simple;

// Re-Exports
pub use simple::*;

// Usings
use pam::{PamConversation, PamFlag, PamHandle, PamReturnCode};

/// Main struct to authenticate a user
/// Currently closes the session on drop() but this might change!
pub struct Authenticator<'a> {
    handle:         *mut PamHandle,
    credentials:    Box<[&'a str; 2]>
}

impl <'a> Authenticator<'a> {
    /// Creates a new Authenticator with a given service name
    pub fn new(service: &str) -> Option<Authenticator> {
        use std::ffi::CString;
        use std::ptr;

        let creds = Box::new([""; 2]);
        let conv = PamConversation {
            conv:       Some(ffi::converse),
            data_ptr:   creds.as_ptr() as *mut ::libc::c_void
        };
        let mut handle: *mut PamHandle = ptr::null_mut();

        match unsafe {
            pam::start(CString::new(service).unwrap().as_ptr(), ptr::null(), &conv, &mut handle)
        } {
            PamReturnCode::SUCCESS => Some(Authenticator {
                handle:         handle,
                credentials:    creds
            }),
            _   => None
        }
    }

    /// Set the credentials which should be used in the authentication process
    pub fn set_credentials(&mut self, user: &'a str, password: &'a str) {
        self.credentials[0] = user;
        self.credentials[1] = password;
    }

    /// Perform the authentication with the provided credentials
    pub fn authenticate(&self) -> Result<(), PamReturnCode> {
        let success = PamReturnCode::SUCCESS;

        let mut res = unsafe { pam::authenticate(self.handle, PamFlag::NONE) };
        if res != success {
            return self.cleanup(res);
        }

        res = unsafe { pam::acct_mgmt(self.handle, PamFlag::NONE) };
        if res != success {
            return self.cleanup(res);
        }

        res = unsafe { pam::setcred(self.handle, PamFlag::ESTABLISH_CRED) };
        if res != success {
            return self.cleanup(res);
        }
        Ok(())
    }

    /// Open a session for a previously authenticated user and
    /// initialize the environment appropriately (in PAM and regular enviroment variables).
    ///
    /// Does not currently check for authentication and just calls the ffi method,
    /// but clients should not rely on that.
    pub fn open_session(&self) -> Result<(), PamReturnCode> {
        let res = unsafe { pam::open_session(self.handle, PamFlag::NONE) };
        if res != PamReturnCode::SUCCESS {
            return self.cleanup(res);
        }

        self.initialize_environment()
    }

    // Initialize the client environment with common variables.
    // Currently always called from Authenticator.open_session()
    fn initialize_environment(&self) -> Result<(), PamReturnCode> {
        let user = users::get_user_by_name(self.credentials[0])
            .expect(&format!("Could not get user by name: {:?}", self.credentials[0]));

        self.set_env("USER", &user.name)
            .and(self.set_env("LOGNAME", &user.name))
            .and(self.set_env("HOME", &user.home_dir))
            .and(self.set_env("PWD", &user.home_dir))
            .and(self.set_env("SHELL", &user.shell))
            // Taken from https://github.com/gsingh93/display-manager/blob/master/pam.c
            // Should be a better way to get this. Revisit later.
            .and(self.set_env("PATH", "$PATH:/usr/local/sbin:/usr/local/bin:/usr/bin"))
    }

    // Utility function to set an environment variable in PAM and the process
    fn set_env(&self, key: &str, value: &str) -> Result<(), PamReturnCode> {
        use std::env;
        use std::ffi::CString;

        // Set regular environment variable
        env::set_var(key, value);

        // Set pam environment variable
        let name_value = CString::new(format!("{}={}", key, value)).unwrap();
        match unsafe { pam::putenv(self.handle, name_value.as_ptr()) } {
            PamReturnCode::SUCCESS  => Ok(()),
            code                    => Err(code)
        }
    }

    // Utility function to properly clean up pam
    fn cleanup(&self, code: PamReturnCode) -> Result<(), PamReturnCode> {
        unsafe {
            // Currently the session is closed if PamReturnCode::SUCCESS is passed //TODO: change this
            if code == PamReturnCode::SUCCESS {
                pam::close_session(self.handle, PamFlag::NONE);
            }
            pam::setcred(self.handle, pam::PamFlag::DELETE_CRED);
            pam::end(self.handle, 0);
        }
        Err(code)
    }
}

impl <'a> Drop for Authenticator<'a> {
    fn drop(&mut self) {
        let _ = self.cleanup(PamReturnCode::SUCCESS);
    }
}
<|endoftext|>