<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::convert::From;
use std::fmt::{self, Display};
use std::ops::Deref;

use gl;
use glutin::{self, EventsLoop, WindowBuilder, Event, CursorState, ControlFlow, ContextBuilder};
use glutin::GlContext;

/// Window errors
#[derive(Debug)]
pub enum Error {
    /// Error creating the window
    ContextCreation(glutin::CreationError),

    /// Error manipulating the rendering context
    Context(glutin::ContextError),
}

/// Result of fallible operations concerning a Window.
type Result<T> = ::std::result::Result<T, Error>;

/// A window which can be used for displaying the terminal
///
/// Wraps the underlying windowing library to provide a stable API in Alacritty
pub struct Window {
    event_loop: EventsLoop,
    window: glutin::GlWindow,
    cursor_visible: bool,

    /// Whether or not the window is the focused window.
    pub is_focused: bool,
}

/// Threadsafe APIs for the window
pub struct Proxy {
    inner: glutin::EventsLoopProxy,
}

/// Information about where the window is being displayed
///
/// Useful for subsystems like the font rasterized which depend on DPI and scale
/// factor.
pub struct DeviceProperties {
    /// Scale factor for pixels <-> points.
    ///
    /// This will be 1. on standard displays and may have a different value on
    /// hidpi displays.
    pub scale_factor: f32,
}

/// Size of the window
#[derive(Debug, Copy, Clone)]
pub struct Size<T> {
    pub width: T,
    pub height: T,
}

/// Strongly typed Pixels unit
#[derive(Debug, Copy, Clone)]
pub struct Pixels<T>(pub T);

/// Strongly typed Points unit
///
/// Points are like pixels but adjusted for DPI.
#[derive(Debug, Copy, Clone)]
pub struct Points<T>(pub T);

pub trait ToPoints {
    fn to_points(&self, scale: f32) -> Size<Points<u32>>;
}

impl ToPoints for Size<Points<u32>> {
    #[inline]
    fn to_points(&self, _scale: f32) -> Size<Points<u32>> {
        *self
    }
}

impl ToPoints for Size<Pixels<u32>> {
    fn to_points(&self, scale: f32) -> Size<Points<u32>> {
        let width_pts = (*self.width as f32 / scale) as u32;
        let height_pts = (*self.height as f32 / scale) as u32;

        Size {
            width: Points(width_pts),
            height: Points(height_pts)
        }
    }
}

impl<T: Display> Display for Size<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} × {}", self.width, self.height)
    }
}

macro_rules! deref_newtype {
    ($($src:ty),+) => {
        $(
        impl<T> Deref for $src {
            type Target = T;

            #[inline]
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        )+
    }
}

deref_newtype! { Points<T>, Pixels<T> }

impl<T: Display> Display for Pixels<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.0)
    }
}

impl<T: Display> Display for Points<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}pts", self.0)
    }
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::ContextCreation(ref err) => Some(err),
            Error::Context(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::ContextCreation(ref _err) => "Error creating gl context",
            Error::Context(ref _err) => "Error operating on render context",
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::ContextCreation(ref err) => {
                write!(f, "Error creating GL context; {}", err)
            },
            Error::Context(ref err) => {
                write!(f, "Error operating on render context; {}", err)
            },
        }
    }
}

impl From<glutin::CreationError> for Error {
    fn from(val: glutin::CreationError) -> Error {
        Error::ContextCreation(val)
    }
}

impl From<glutin::ContextError> for Error {
    fn from(val: glutin::ContextError) -> Error {
        Error::Context(val)
    }
}

impl Window {
    /// Create a new window
    ///
    /// This creates a window and fully initializes a window.
    pub fn new(
        title: &str
    ) -> Result<Window> {
        let event_loop = EventsLoop::new();

        Window::platform_window_init();
        let window = WindowBuilder::new()
            .with_title(title)
            .with_transparency(true);
        let context = ContextBuilder::new()
            .with_vsync(true);
        let window = ::glutin::GlWindow::new(window, context, &event_loop)?;

        // Set OpenGL symbol loader
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

        // Make the context current so OpenGL operations can run
        unsafe {
            window.make_current()?;
        }

        let window = Window {
            event_loop: event_loop,
            window: window,
            cursor_visible: true,
            is_focused: true,
        };

        window.run_os_extensions();

        Ok(window)
    }

    /// Get some properties about the device
    ///
    /// Some window properties are provided since subsystems like font
    /// rasterization depend on DPI and scale factor.
    pub fn device_properties(&self) -> DeviceProperties {
        DeviceProperties {
            scale_factor: self.window.hidpi_factor(),
        }
    }

    pub fn inner_size_pixels(&self) -> Option<Size<Pixels<u32>>> {
        self.window
            .get_inner_size_pixels()
            .map(|(w, h)| Size { width: Pixels(w), height: Pixels(h) })
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        self.window.hidpi_factor()
    }

    #[inline]
    pub fn create_window_proxy(&self) -> Proxy {
        Proxy {
            inner: self.event_loop.create_proxy(),
        }
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<()> {
        self.window
            .swap_buffers()
            .map_err(From::from)
    }

    /// Poll for any available events
    #[inline]
    pub fn poll_events<F>(&mut self, func: F)
        where F: FnMut(Event)
    {
        self.event_loop.poll_events(func);
    }

    #[inline]
    pub fn resize(&self, width: u32, height: u32) {
        self.window.resize(width, height);
    }

    /// Block waiting for events
    #[inline]
    pub fn wait_events<F>(&mut self, func: F)
        where F: FnMut(Event) -> ControlFlow
    {
        self.event_loop.run_forever(func);
    }

    /// Set the window title
    #[inline]
    pub fn set_title(&self, title: &str) {
        self.window.set_title(title);
    }

    /// Set cursor visible
    pub fn set_cursor_visible(&mut self, visible: bool) {
        if visible != self.cursor_visible {
            self.cursor_visible = visible;
            if let Err(err) = self.window.set_cursor_state(if visible {
                CursorState::Normal
            } else {
                CursorState::Hide
            }) {
                warn!("Failed to set cursor visibility: {}", err);
            }
        }
    }

    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
    pub fn platform_window_init() {
        /// Set up env to make XIM work correctly
        use x11_dl::xlib;
        use libc::{setlocale, LC_CTYPE};
        let xlib = xlib::Xlib::open().expect("get xlib");
        unsafe {
            // Use empty c string to fallback to LC_CTYPE in environment variables
            setlocale(LC_CTYPE, b"\0".as_ptr() as *const _);
            // Use empty c string for implementation dependent behavior,
            // which might be the XMODIFIERS set in env
            (xlib.XSetLocaleModifiers)(b"\0".as_ptr() as *const _);
        }
    }

    /// TODO: change this directive when adding functions for other platforms
    #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))]
    pub fn platform_window_init() {
    }

    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
    pub fn set_urgent(&self, is_urgent: bool) {
        use glutin::os::unix::WindowExt;
        use std::os::raw;
        use x11_dl::xlib::{self, XUrgencyHint};

        let xlib_display = self.window.get_xlib_display();
        let xlib_window = self.window.get_xlib_window();

        if let (Some(xlib_window), Some(xlib_display)) = (xlib_window, xlib_display) {
            let xlib = xlib::Xlib::open().expect("get xlib");

            unsafe {
                let mut hints = (xlib.XGetWMHints)(xlib_display as _, xlib_window as _);

                if hints.is_null() {
                    hints = (xlib.XAllocWMHints)();
                }

                if is_urgent {
                    (*hints).flags |= XUrgencyHint;
                } else {
                    (*hints).flags &= !XUrgencyHint;
                 }

                (xlib.XSetWMHints)(xlib_display as _, xlib_window as _, hints);

                (xlib.XFree)(hints as *mut raw::c_void);
            }
        }

    }

    #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))]
    pub fn set_urgent(&self, is_urgent: bool) {
    }

    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
    pub fn send_xim_spot(&self, x: i16, y: i16) {
        use glutin::os::unix::WindowExt;
        self.window.send_xim_spot(x, y);
    }

    #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))]
    pub fn send_xim_spot(&self, _x: i16, _y: i16) {
    }

    #[cfg(not(target_os = "macos"))]
    pub fn get_window_id(&self) -> Option<usize> {
        use glutin::os::unix::WindowExt;

        match self.window.get_xlib_window() {
            Some(xlib_window) => Some(xlib_window as usize),
            None => None
        }
    }

    #[cfg(target_os = "macos")]
    pub fn get_window_id(&self) -> Option<usize> {
        None
    }
}

pub trait OsExtensions {
    fn run_os_extensions(&self) {}
}

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd")))]
impl OsExtensions for Window { }

#[cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))]
impl OsExtensions for Window {
    fn run_os_extensions(&self) {
        use glutin::os::unix::WindowExt;
        use x11_dl::xlib::{self, XA_CARDINAL, PropModeReplace};
        use std::ffi::{CStr};
        use std::ptr;
        use libc::getpid;

        let xlib_display = self.window.get_xlib_display();
        let xlib_window = self.window.get_xlib_window();

        if let (Some(xlib_window), Some(xlib_display)) = (xlib_window, xlib_display) {
            let xlib = xlib::Xlib::open().expect("get xlib");

            // Set _NET_WM_PID to process pid
            unsafe {
                let _net_wm_pid = CStr::from_ptr(b"_NET_WM_PID\0".as_ptr() as *const _);
                let atom = (xlib.XInternAtom)(xlib_display as *mut _, _net_wm_pid.as_ptr(), 0);
                let pid = getpid();

                (xlib.XChangeProperty)(xlib_display as _, xlib_window as _, atom,
                    XA_CARDINAL, 32, PropModeReplace, &pid as *const i32 as *const u8, 1);

            }
            // Although this call doesn't actually pass any data, it does cause
            // WM_CLIENT_MACHINE to be set. WM_CLIENT_MACHINE MUST be set if _NET_WM_PID is set
            // (which we do above).
            unsafe {
                (xlib.XSetWMProperties)(xlib_display as _, xlib_window as _, ptr::null_mut(),
                    ptr::null_mut(), ptr::null_mut(), 0, ptr::null_mut(), ptr::null_mut(),
                    ptr::null_mut());
            }
        }
    }
}

impl Proxy {
    /// Wakes up the event loop of the window
    ///
    /// This is useful for triggering a draw when the renderer would otherwise
    /// be waiting on user input.
    pub fn wakeup_event_loop(&self) {
        self.inner.wakeup().unwrap();
    }
}

pub trait SetInnerSize<T> {
    fn set_inner_size<S: ToPoints>(&mut self, size: &S);
}

impl SetInnerSize<Pixels<u32>> for Window {
    fn set_inner_size<T: ToPoints>(&mut self, size: &T) {
        let size = size.to_points(self.hidpi_factor());
        self.window.set_inner_size(*size.width as _, *size.height as _);
    }
}
<commit_msg>Change cursor from pointer to text (#778)<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::convert::From;
use std::fmt::{self, Display};
use std::ops::Deref;

use gl;
use glutin::{self, EventsLoop, WindowBuilder, Event, MouseCursor, CursorState, ControlFlow, ContextBuilder};
use glutin::GlContext;

/// Window errors
#[derive(Debug)]
pub enum Error {
    /// Error creating the window
    ContextCreation(glutin::CreationError),

    /// Error manipulating the rendering context
    Context(glutin::ContextError),
}

/// Result of fallible operations concerning a Window.
type Result<T> = ::std::result::Result<T, Error>;

/// A window which can be used for displaying the terminal
///
/// Wraps the underlying windowing library to provide a stable API in Alacritty
pub struct Window {
    event_loop: EventsLoop,
    window: glutin::GlWindow,
    cursor_visible: bool,

    /// Whether or not the window is the focused window.
    pub is_focused: bool,
}

/// Threadsafe APIs for the window
pub struct Proxy {
    inner: glutin::EventsLoopProxy,
}

/// Information about where the window is being displayed
///
/// Useful for subsystems like the font rasterized which depend on DPI and scale
/// factor.
pub struct DeviceProperties {
    /// Scale factor for pixels <-> points.
    ///
    /// This will be 1. on standard displays and may have a different value on
    /// hidpi displays.
    pub scale_factor: f32,
}

/// Size of the window
#[derive(Debug, Copy, Clone)]
pub struct Size<T> {
    pub width: T,
    pub height: T,
}

/// Strongly typed Pixels unit
#[derive(Debug, Copy, Clone)]
pub struct Pixels<T>(pub T);

/// Strongly typed Points unit
///
/// Points are like pixels but adjusted for DPI.
#[derive(Debug, Copy, Clone)]
pub struct Points<T>(pub T);

pub trait ToPoints {
    fn to_points(&self, scale: f32) -> Size<Points<u32>>;
}

impl ToPoints for Size<Points<u32>> {
    #[inline]
    fn to_points(&self, _scale: f32) -> Size<Points<u32>> {
        *self
    }
}

impl ToPoints for Size<Pixels<u32>> {
    fn to_points(&self, scale: f32) -> Size<Points<u32>> {
        let width_pts = (*self.width as f32 / scale) as u32;
        let height_pts = (*self.height as f32 / scale) as u32;

        Size {
            width: Points(width_pts),
            height: Points(height_pts)
        }
    }
}

impl<T: Display> Display for Size<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} × {}", self.width, self.height)
    }
}

macro_rules! deref_newtype {
    ($($src:ty),+) => {
        $(
        impl<T> Deref for $src {
            type Target = T;

            #[inline]
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        )+
    }
}

deref_newtype! { Points<T>, Pixels<T> }

impl<T: Display> Display for Pixels<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.0)
    }
}

impl<T: Display> Display for Points<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}pts", self.0)
    }
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::ContextCreation(ref err) => Some(err),
            Error::Context(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::ContextCreation(ref _err) => "Error creating gl context",
            Error::Context(ref _err) => "Error operating on render context",
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::ContextCreation(ref err) => {
                write!(f, "Error creating GL context; {}", err)
            },
            Error::Context(ref err) => {
                write!(f, "Error operating on render context; {}", err)
            },
        }
    }
}

impl From<glutin::CreationError> for Error {
    fn from(val: glutin::CreationError) -> Error {
        Error::ContextCreation(val)
    }
}

impl From<glutin::ContextError> for Error {
    fn from(val: glutin::ContextError) -> Error {
        Error::Context(val)
    }
}

impl Window {
    /// Create a new window
    ///
    /// This creates a window and fully initializes a window.
    pub fn new(
        title: &str
    ) -> Result<Window> {
        let event_loop = EventsLoop::new();

        Window::platform_window_init();
        let window = WindowBuilder::new()
            .with_title(title)
            .with_transparency(true);
        let context = ContextBuilder::new()
            .with_vsync(true);
        let window = ::glutin::GlWindow::new(window, context, &event_loop)?;

        // Text cursor
        window.set_cursor(MouseCursor::Text);

        // Set OpenGL symbol loader
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

        // Make the context current so OpenGL operations can run
        unsafe {
            window.make_current()?;
        }

        let window = Window {
            event_loop: event_loop,
            window: window,
            cursor_visible: true,
            is_focused: true,
        };

        window.run_os_extensions();

        Ok(window)
    }

    /// Get some properties about the device
    ///
    /// Some window properties are provided since subsystems like font
    /// rasterization depend on DPI and scale factor.
    pub fn device_properties(&self) -> DeviceProperties {
        DeviceProperties {
            scale_factor: self.window.hidpi_factor(),
        }
    }

    pub fn inner_size_pixels(&self) -> Option<Size<Pixels<u32>>> {
        self.window
            .get_inner_size_pixels()
            .map(|(w, h)| Size { width: Pixels(w), height: Pixels(h) })
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        self.window.hidpi_factor()
    }

    #[inline]
    pub fn create_window_proxy(&self) -> Proxy {
        Proxy {
            inner: self.event_loop.create_proxy(),
        }
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<()> {
        self.window
            .swap_buffers()
            .map_err(From::from)
    }

    /// Poll for any available events
    #[inline]
    pub fn poll_events<F>(&mut self, func: F)
        where F: FnMut(Event)
    {
        self.event_loop.poll_events(func);
    }

    #[inline]
    pub fn resize(&self, width: u32, height: u32) {
        self.window.resize(width, height);
    }

    /// Block waiting for events
    #[inline]
    pub fn wait_events<F>(&mut self, func: F)
        where F: FnMut(Event) -> ControlFlow
    {
        self.event_loop.run_forever(func);
    }

    /// Set the window title
    #[inline]
    pub fn set_title(&self, title: &str) {
        self.window.set_title(title);
    }

    /// Set cursor visible
    pub fn set_cursor_visible(&mut self, visible: bool) {
        if visible != self.cursor_visible {
            self.cursor_visible = visible;
            if let Err(err) = self.window.set_cursor_state(if visible {
                CursorState::Normal
            } else {
                CursorState::Hide
            }) {
                warn!("Failed to set cursor visibility: {}", err);
            }
        }
    }

    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
    pub fn platform_window_init() {
        /// Set up env to make XIM work correctly
        use x11_dl::xlib;
        use libc::{setlocale, LC_CTYPE};
        let xlib = xlib::Xlib::open().expect("get xlib");
        unsafe {
            // Use empty c string to fallback to LC_CTYPE in environment variables
            setlocale(LC_CTYPE, b"\0".as_ptr() as *const _);
            // Use empty c string for implementation dependent behavior,
            // which might be the XMODIFIERS set in env
            (xlib.XSetLocaleModifiers)(b"\0".as_ptr() as *const _);
        }
    }

    /// TODO: change this directive when adding functions for other platforms
    #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))]
    pub fn platform_window_init() {
    }

    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
    pub fn set_urgent(&self, is_urgent: bool) {
        use glutin::os::unix::WindowExt;
        use std::os::raw;
        use x11_dl::xlib::{self, XUrgencyHint};

        let xlib_display = self.window.get_xlib_display();
        let xlib_window = self.window.get_xlib_window();

        if let (Some(xlib_window), Some(xlib_display)) = (xlib_window, xlib_display) {
            let xlib = xlib::Xlib::open().expect("get xlib");

            unsafe {
                let mut hints = (xlib.XGetWMHints)(xlib_display as _, xlib_window as _);

                if hints.is_null() {
                    hints = (xlib.XAllocWMHints)();
                }

                if is_urgent {
                    (*hints).flags |= XUrgencyHint;
                } else {
                    (*hints).flags &= !XUrgencyHint;
                 }

                (xlib.XSetWMHints)(xlib_display as _, xlib_window as _, hints);

                (xlib.XFree)(hints as *mut raw::c_void);
            }
        }

    }

    #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))]
    pub fn set_urgent(&self, is_urgent: bool) {
    }

    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
    pub fn send_xim_spot(&self, x: i16, y: i16) {
        use glutin::os::unix::WindowExt;
        self.window.send_xim_spot(x, y);
    }

    #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))]
    pub fn send_xim_spot(&self, _x: i16, _y: i16) {
    }

    #[cfg(not(target_os = "macos"))]
    pub fn get_window_id(&self) -> Option<usize> {
        use glutin::os::unix::WindowExt;

        match self.window.get_xlib_window() {
            Some(xlib_window) => Some(xlib_window as usize),
            None => None
        }
    }

    #[cfg(target_os = "macos")]
    pub fn get_window_id(&self) -> Option<usize> {
        None
    }
}

pub trait OsExtensions {
    fn run_os_extensions(&self) {}
}

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd")))]
impl OsExtensions for Window { }

#[cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))]
impl OsExtensions for Window {
    fn run_os_extensions(&self) {
        use glutin::os::unix::WindowExt;
        use x11_dl::xlib::{self, XA_CARDINAL, PropModeReplace};
        use std::ffi::{CStr};
        use std::ptr;
        use libc::getpid;

        let xlib_display = self.window.get_xlib_display();
        let xlib_window = self.window.get_xlib_window();

        if let (Some(xlib_window), Some(xlib_display)) = (xlib_window, xlib_display) {
            let xlib = xlib::Xlib::open().expect("get xlib");

            // Set _NET_WM_PID to process pid
            unsafe {
                let _net_wm_pid = CStr::from_ptr(b"_NET_WM_PID\0".as_ptr() as *const _);
                let atom = (xlib.XInternAtom)(xlib_display as *mut _, _net_wm_pid.as_ptr(), 0);
                let pid = getpid();

                (xlib.XChangeProperty)(xlib_display as _, xlib_window as _, atom,
                    XA_CARDINAL, 32, PropModeReplace, &pid as *const i32 as *const u8, 1);

            }
            // Although this call doesn't actually pass any data, it does cause
            // WM_CLIENT_MACHINE to be set. WM_CLIENT_MACHINE MUST be set if _NET_WM_PID is set
            // (which we do above).
            unsafe {
                (xlib.XSetWMProperties)(xlib_display as _, xlib_window as _, ptr::null_mut(),
                    ptr::null_mut(), ptr::null_mut(), 0, ptr::null_mut(), ptr::null_mut(),
                    ptr::null_mut());
            }
        }
    }
}

impl Proxy {
    /// Wakes up the event loop of the window
    ///
    /// This is useful for triggering a draw when the renderer would otherwise
    /// be waiting on user input.
    pub fn wakeup_event_loop(&self) {
        self.inner.wakeup().unwrap();
    }
}

pub trait SetInnerSize<T> {
    fn set_inner_size<S: ToPoints>(&mut self, size: &S);
}

impl SetInnerSize<Pixels<u32>> for Window {
    fn set_inner_size<T: ToPoints>(&mut self, size: &T) {
        let size = size.to_points(self.hidpi_factor());
        self.window.set_inner_size(*size.width as _, *size.height as _);
    }
}
<|endoftext|>


<commit_before>use std::io::Write;

use serde::ser;

use super::Error;

pub struct Serializer<W> {
  writer : W
}

impl<W> Serializer<W> where W : Write {
  pub fn new (wr: W) -> Serializer<W> {
    Serializer{ writer : wr }
  }

  fn write_str(&mut self, s: &str) -> Result<(), Error> {
    self.write_bytes(s.as_bytes())
  }

  fn write_bytes(&mut self, s: &[u8]) -> Result<(), Error> {
    let pfx = format!("{}:", s.len());
    try!(self.writer.write_all(pfx.into_bytes().as_slice()));
    try!(self.writer.write_all(s));
    Ok(())
  }

  fn open(&mut self) -> Result<(), Error> {
    Ok(try!(self.writer.write_all(b"(")))
  }
  fn close(&mut self) -> Result<(), Error> {
    Ok(try!(self.writer.write_all(b")")))
  }
}

 impl<W> ser::Serializer for Serializer<W> where W: Write {
   type Error = Error;
//
  fn serialize_unit(&mut self) -> Result<(), Error> {
    Ok(())
  }

//
  fn serialize_bool(&mut self, val: bool) -> Result<(), Error> {
    //writeln!(std::io::stderr(), "Serializer::serialize_bool: {:?}", val).unwrap();
    if val {
      try!(self.write_str("true"))
    } else {
      try!(self.write_str("false"))
    }
    Ok(())
  }
//   // TODO: Consider using display-hints for types of atoms.
  fn serialize_u64(&mut self, v: u64) -> Result<(), Error> {
//     writeln!(std::io::stderr(), "Serializer::serialize_u64: {:?}", v).unwrap();
    Ok(try!(self.write_str(&format!("{}", v))))
  }
  fn serialize_i64(&mut self, v: i64) -> Result<(), Error> {
//    writeln!(std::io::stderr(), "Serializer::serialize_i64: {:?}", v).unwrap();
    Ok(try!(self.write_str(&format!("{}", v))))
  }
  fn serialize_f64(&mut self, v: f64) -> Result<(), Error> {
//    writeln!(std::io::stderr(), "Serializer::serialize_f64: {:?}", v).unwrap();
    Ok(try!(self.write_str(&format!("{}", v))))
  }
  fn serialize_str(&mut self, v: &str) -> Result<(), Error> {
    self.write_str(v)
  }
  fn serialize_bytes(&mut self, v: &[u8]) -> Result<(), Error> {
    self.write_bytes(v)
  }
  fn serialize_none(&mut self) -> Result<(), Error> {
//    writeln!(std::io::stderr(), "Serializer::serialize_none").unwrap();
    self.write_str("none")
  }
  fn serialize_some<T>(&mut self, v: T) -> Result<(), Error> where T: ser::Serialize {
 //    writeln!(std::io::stderr(), "Serializer::serialize_some(?)").unwrap();
    try!(self.open());
    try!(self.write_str("some"));
    try!(v.serialize(self));
    self.close()
  }
  fn serialize_seq<V>(&mut self, mut visitor: V) -> Result<(), Error> where V: ser::SeqVisitor {
    // writeln!(std::io::stderr(), "Serializer::serialize_seq").unwrap();
    try!(self.open());
    while let Some(()) = try!(visitor.visit(self)) {}
    self.close()
  }
//
//   fn serialize_named_seq<V>(&mut self, name: &'static str, mut visitor: V) -> Result<(), Error> where V: ser::SeqVisitor {
//     // writeln!(std::io::stderr(), "Serializer::serialize_named_seq:{}", name).unwrap();
//     try!(self.open());
//     try!(self.write_str(name));
//     while let Some(()) = try!(visitor.visit(self)) {}
//     self.close()
//   }
//
  fn serialize_seq_elt<T>(&mut self, v: T) -> Result<(), Error> where T: ser::Serialize {
//     writeln!(std::io::stderr(), "Serializer::serialize_seq_elt").unwrap();
    v.serialize(self)
  }
  fn serialize_map<V>(&mut self, mut visitor: V) -> Result<(), Error> where V: ser::MapVisitor {
//    writeln!(std::io::stderr(), "Serializer::serialize_map").unwrap();
    try!(self.open());
    while let Some(()) = try!(visitor.visit(self)) {}
    self.close()
  }

  fn serialize_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
    where K: ser::Serialize, V:  ser::Serialize {
//     writeln!(std::io::stderr(), "Serializer::serialize_map_elt").unwrap();
    try!(key.serialize(self));
    value.serialize(self)
  }

   fn serialize_unit_variant(&mut self, _name: &'static str,
                          _variant_index: usize,
                          variant: &'static str) -> Result<(), Error> {
     // writeln!(std::io::stderr(), "Serializer::serialize_named_unit:{:?}", name).unwrap();
    try!(self.open());
    try!(self.write_str(variant));
    Ok(try!(self.close()))
   }

   fn serialize_tuple_variant<V: ser::SeqVisitor>(&mut self, _name: &'static str,
                              _variant_index: usize,
                              variant: &'static str, mut visitor: V)  -> Result<(), Error> {
     // writeln!(std::io::stderr(), "Serializer::serialize_named_unit:{:?}", name).unwrap();
    try!(self.open());
    try!(self.write_str(variant));
    while let Some(()) = try!(visitor.visit(self)) {}
    self.close()
   }

   fn serialize_struct_variant<V: ser::MapVisitor>(&mut self, _name: &'static str,
                              _variant_index: usize,
                              variant: &'static str, mut visitor: V)  -> Result<(), Error> {
    try!(self.open());
    try!(self.write_str(variant));
    while let Some(()) = try!(visitor.visit(self)) {}
    self.close()
   }
}
<commit_msg>Avoid more heap allocations.<commit_after>use std::io::{Write,Cursor};
use std::fmt;

use serde::ser;

use super::Error;

pub struct Serializer<W> {
  writer : W
}

impl<W> Serializer<W> where W : Write {
  pub fn new (wr: W) -> Serializer<W> {
    Serializer{ writer : wr }
  }

  fn write_str(&mut self, s: &str) -> Result<(), Error> {
    self.write_bytes(s.as_bytes())
  }

  fn write_bytes(&mut self, s: &[u8]) -> Result<(), Error> {
    let mut pfx = [0u8; 22];
    let off = {
        let mut cur = Cursor::new(pfx.as_mut());
        try!(write!(cur, "{}:", s.len()));
        cur.position() as usize
    };
    try!(self.writer.write_all(&pfx[..off]));
    try!(self.writer.write_all(s));
    Ok(())
  }

  fn write_displayable<T: fmt::Display>(&mut self, v: T) -> Result<(), Error> {
    let mut bytes = [0u8; 22];
    let off = {
        let mut cur = Cursor::new(bytes.as_mut());
        try!(write!(cur, "{}", v));
        cur.position() as usize
    };

    Ok(try!(self.write_bytes(&bytes[..off])))
  }

  fn open(&mut self) -> Result<(), Error> {
    Ok(try!(self.writer.write_all(b"(")))
  }
  fn close(&mut self) -> Result<(), Error> {
    Ok(try!(self.writer.write_all(b")")))
  }
}

 impl<W> ser::Serializer for Serializer<W> where W: Write {
   type Error = Error;
//
  fn serialize_unit(&mut self) -> Result<(), Error> {
    Ok(())
  }

  fn serialize_bool(&mut self, val: bool) -> Result<(), Error> {
    //writeln!(std::io::stderr(), "Serializer::serialize_bool: {:?}", val).unwrap();
    if val {
      try!(self.write_str("true"))
    } else {
      try!(self.write_str("false"))
    }
    Ok(())
  }
//   // TODO: Consider using display-hints for types of atoms.
  fn serialize_u64(&mut self, v: u64) -> Result<(), Error> {
      self.write_displayable(v)
  }

  fn serialize_i64(&mut self, v: i64) -> Result<(), Error> {
      self.write_displayable(v)
  }
  fn serialize_f64(&mut self, v: f64) -> Result<(), Error> {
      self.write_displayable(v)
  }
  fn serialize_str(&mut self, v: &str) -> Result<(), Error> {
    self.write_str(v)
  }
  fn serialize_bytes(&mut self, v: &[u8]) -> Result<(), Error> {
    self.write_bytes(v)
  }
  fn serialize_none(&mut self) -> Result<(), Error> {
//    writeln!(std::io::stderr(), "Serializer::serialize_none").unwrap();
    self.write_str("none")
  }
  fn serialize_some<T>(&mut self, v: T) -> Result<(), Error> where T: ser::Serialize {
 //    writeln!(std::io::stderr(), "Serializer::serialize_some(?)").unwrap();
    try!(self.open());
    try!(self.write_str("some"));
    try!(v.serialize(self));
    self.close()
  }
  fn serialize_seq<V>(&mut self, mut visitor: V) -> Result<(), Error> where V: ser::SeqVisitor {
    // writeln!(std::io::stderr(), "Serializer::serialize_seq").unwrap();
    try!(self.open());
    while let Some(()) = try!(visitor.visit(self)) {}
    self.close()
  }
//
//   fn serialize_named_seq<V>(&mut self, name: &'static str, mut visitor: V) -> Result<(), Error> where V: ser::SeqVisitor {
//     // writeln!(std::io::stderr(), "Serializer::serialize_named_seq:{}", name).unwrap();
//     try!(self.open());
//     try!(self.write_str(name));
//     while let Some(()) = try!(visitor.visit(self)) {}
//     self.close()
//   }
//
  fn serialize_seq_elt<T>(&mut self, v: T) -> Result<(), Error> where T: ser::Serialize {
//     writeln!(std::io::stderr(), "Serializer::serialize_seq_elt").unwrap();
    v.serialize(self)
  }
  fn serialize_map<V>(&mut self, mut visitor: V) -> Result<(), Error> where V: ser::MapVisitor {
//    writeln!(std::io::stderr(), "Serializer::serialize_map").unwrap();
    try!(self.open());
    while let Some(()) = try!(visitor.visit(self)) {}
    self.close()
  }

  fn serialize_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
    where K: ser::Serialize, V:  ser::Serialize {
//     writeln!(std::io::stderr(), "Serializer::serialize_map_elt").unwrap();
    try!(key.serialize(self));
    value.serialize(self)
  }

   fn serialize_unit_variant(&mut self, _name: &'static str,
                          _variant_index: usize,
                          variant: &'static str) -> Result<(), Error> {
     // writeln!(std::io::stderr(), "Serializer::serialize_named_unit:{:?}", name).unwrap();
    try!(self.open());
    try!(self.write_str(variant));
    Ok(try!(self.close()))
   }

   fn serialize_tuple_variant<V: ser::SeqVisitor>(&mut self, _name: &'static str,
                              _variant_index: usize,
                              variant: &'static str, mut visitor: V)  -> Result<(), Error> {
     // writeln!(std::io::stderr(), "Serializer::serialize_named_unit:{:?}", name).unwrap();
    try!(self.open());
    try!(self.write_str(variant));
    while let Some(()) = try!(visitor.visit(self)) {}
    self.close()
   }

   fn serialize_struct_variant<V: ser::MapVisitor>(&mut self, _name: &'static str,
                              _variant_index: usize,
                              variant: &'static str, mut visitor: V)  -> Result<(), Error> {
    try!(self.open());
    try!(self.write_str(variant));
    while let Some(()) = try!(visitor.visit(self)) {}
    self.close()
   }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::PathBuf;
use std::path::Path;

use error::*;

#[derive(Debug, Clone)]
pub struct VfsConfig {
	pub mount_points: HashMap<String, PathBuf>,
}

impl VfsConfig {
    pub fn new() -> VfsConfig {
        VfsConfig {
            mount_points: HashMap::new(),
        }
    }
}

pub struct Vfs {
    mount_points: HashMap<String, PathBuf>,
}

impl Vfs {
    pub fn new(config: VfsConfig) -> Vfs {
        Vfs { mount_points: config.mount_points }
    }

    pub fn real_to_virtual(&self, real_path: &Path) -> Result<PathBuf, PError> {
        for (name, target) in &self.mount_points {
            match real_path.strip_prefix(target) {
                Ok(p) => {
                    let mount_path = Path::new(&name);
                    return Ok(mount_path.join(p));
                }
                Err(_) => (),
            }
        }
        Err(PError::PathNotInVfs)
    }

    pub fn virtual_to_real(&self, virtual_path: &Path) -> Result<PathBuf, PError> {
        for (name, target) in &self.mount_points {
            let mount_path = Path::new(&name);
            match virtual_path.strip_prefix(mount_path) {
                Ok(p) => return if p.components().count() == 0 {
                    Ok(target.clone())
                } else {
                    Ok(target.join(p))
                },
                Err(_) => (),
            }
        }
        Err(PError::PathNotInVfs)
    }

    pub fn get_mount_points(&self) -> &HashMap<String, PathBuf> {
        return &self.mount_points;
    }
}

#[test]
fn test_virtual_to_real() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);
    let correct_path = Path::new(r"test_dir\somewhere\something.png");
    let found_path = vfs.virtual_to_real(Path::new(r"root\somewhere\something.png")).unwrap();
    assert!(found_path.to_str() == correct_path.to_str());
}

#[test]
fn test_virtual_to_real_no_trail() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);
    let correct_path = Path::new("test_dir");
    let found_path = vfs.virtual_to_real(Path::new("root")).unwrap();
    assert!(found_path.to_str() == correct_path.to_str());
}

#[test]
fn test_real_to_virtual() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);

    let correct_path = Path::new("root/somewhere/something.png");
    let found_path = vfs.real_to_virtual(Path::new("test_dir/somewhere/something.png")).unwrap();
    assert!(found_path == correct_path);
}
<commit_msg>Made VFS unit tests platform agnostic<commit_after>use std::collections::HashMap;
use std::path::PathBuf;
use std::path::Path;

use error::*;

#[derive(Debug, Clone)]
pub struct VfsConfig {
	pub mount_points: HashMap<String, PathBuf>,
}

impl VfsConfig {
    pub fn new() -> VfsConfig {
        VfsConfig {
            mount_points: HashMap::new(),
        }
    }
}

pub struct Vfs {
    mount_points: HashMap<String, PathBuf>,
}

impl Vfs {
    pub fn new(config: VfsConfig) -> Vfs {
        Vfs { mount_points: config.mount_points }
    }

    pub fn real_to_virtual(&self, real_path: &Path) -> Result<PathBuf, PError> {
        for (name, target) in &self.mount_points {
            match real_path.strip_prefix(target) {
                Ok(p) => {
                    let mount_path = Path::new(&name);
                    return Ok(mount_path.join(p));
                }
                Err(_) => (),
            }
        }
        Err(PError::PathNotInVfs)
    }

    pub fn virtual_to_real(&self, virtual_path: &Path) -> Result<PathBuf, PError> {
        for (name, target) in &self.mount_points {
            let mount_path = Path::new(&name);
            match virtual_path.strip_prefix(mount_path) {
                Ok(p) => return if p.components().count() == 0 {
                    Ok(target.clone())
                } else {
                    Ok(target.join(p))
                },
                Err(_) => (),
            }
        }
        Err(PError::PathNotInVfs)
    }

    pub fn get_mount_points(&self) -> &HashMap<String, PathBuf> {
        return &self.mount_points;
    }
}

#[test]
fn test_virtual_to_real() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);

    let mut correct_path = PathBuf::new();
    correct_path.push("test_dir");
    correct_path.push("somewhere");
    correct_path.push("something.png");

    let mut virtual_path = PathBuf::new();
    virtual_path.push("root");
    virtual_path.push("somewhere");
    virtual_path.push("something.png");

    let found_path = vfs.virtual_to_real(virtual_path.as_path()).unwrap();
    assert!(found_path.to_str() == correct_path.to_str());
}

#[test]
fn test_virtual_to_real_no_trail() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);
    let correct_path = Path::new("test_dir");
    let found_path = vfs.virtual_to_real(Path::new("root")).unwrap();
    assert!(found_path.to_str() == correct_path.to_str());
}

#[test]
fn test_real_to_virtual() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);

    let mut correct_path = PathBuf::new();
    correct_path.push("root");
    correct_path.push("somewhere");
    correct_path.push("something.png");

    let mut real_path = PathBuf::new();
    real_path.push("test_dir");
    real_path.push("somewhere");
    real_path.push("something.png");

    let found_path = vfs.real_to_virtual(real_path.as_path()).unwrap();
    assert!(found_path == correct_path);
}
<|endoftext|>


<commit_before>#![feature(custom_attribute)]
#![allow(dead_code, unused_attributes)]

#[miri_run]
fn make_vec() -> Vec<i32> {
    let mut v = Vec::with_capacity(4);
    v.push(1);
    v.push(2);
    v
}

#[miri_run]
fn make_vec_macro() -> Vec<i32> {
    vec![1, 2]
}
<commit_msg>Add vec::IntoIter and fold test.<commit_after>#![feature(custom_attribute)]
#![allow(dead_code, unused_attributes)]

#[miri_run]
fn make_vec() -> Vec<i32> {
    let mut v = Vec::with_capacity(4);
    v.push(1);
    v.push(2);
    v
}

#[miri_run]
fn make_vec_macro() -> Vec<i32> {
    vec![1, 2]
}

#[miri_run]
fn vec_int_iter() -> i32 {
    vec![1, 2, 3, 4].into_iter().fold(0, |x, y| x + y)
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use dispatcher::request::{ExternalRequest, Request};

#[derive(Clone, Copy, Debug)]
pub struct TimerEvent(pub Duration);

pub struct Timer;

impl Timer {
    pub fn from_chan(duration: Duration, tx: mpsc::Sender<ExternalRequest>) {
        thread::spawn(move || {
            loop {
                thread::sleep(duration);
                if tx.send(Request::Timer(TimerEvent(duration))).is_err() {
                    break;
                }
            }
        });
    }
}
<commit_msg>TimerEvent: add from_millis() method<commit_after>use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use dispatcher::request::{ExternalRequest, Request};

#[derive(Clone, Copy, Debug)]
pub struct TimerEvent(pub Duration);

impl TimerEvent {
    pub fn from_millis(ms: u64) -> TimerEvent {
        TimerEvent(Duration::from_millis(ms))
    }
}

pub struct Timer;

impl Timer {
    pub fn from_chan(duration: Duration, tx: mpsc::Sender<ExternalRequest>) {
        thread::spawn(move || {
            loop {
                thread::sleep(duration);
                if tx.send(Request::Timer(TimerEvent(duration))).is_err() {
                    break;
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

extern crate libc;

use std::ffi;
use std::fmt;
use std::io::{self, Read};
use std::fs::File;
use std::os::raw::c_char;

#[cfg(target_os = "macos")]
use libc::sysctl;
use libc::timeval;
use std::mem::size_of_val;
use std::ptr::null_mut;

use std::collections::HashMap;

static MAC_CTL_KERN: libc::c_int = 1;
static MAC_KERN_BOOTTIME: libc::c_int = 21;

/// System load average value.
#[repr(C)]
#[derive(Debug)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64,
}

/// System memory information.
#[repr(C)]
#[derive(Debug)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free: u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached: u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free: u64,
}

/// Disk information.
#[repr(C)]
#[derive(Debug)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64,
}

/// Error types
#[derive(Debug)]
pub enum Error {
    UnsupportedSystem,
    ExecFailed(io::Error),
    IO(io::Error),
    Unknown,
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match *self {
            UnsupportedSystem => write!(fmt, "System is not supported"),
            ExecFailed(ref e) => write!(fmt, "Execution failed: {}", e),
            IO(ref e) => write!(fmt, "IO error: {}", e),
            Unknown => write!(fmt, "An unknown error occurred"),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            UnsupportedSystem => "unsupported system",
            ExecFailed(_) => "execution failed",
            IO(_) => "io error",
            Unknown => "unknown error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        use self::Error::*;
        match *self {
            UnsupportedSystem => None,
            ExecFailed(ref e) => Some(e),
            IO(ref e) => Some(e),
            Unknown => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::IO(e)
    }
}

extern "C" {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/sys/kernel/ostype")?.read_to_string(&mut s)?;
        s.pop(); // pop '\n'
        Ok(s)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        let typ = unsafe { ffi::CStr::from_ptr(get_os_type() as *const c_char).to_bytes() };
        Ok(String::from_utf8_lossy(typ).into_owned())
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/sys/kernel/osrelease")?.read_to_string(&mut s)?;
        s.pop(); // pop '\n'
        Ok(s)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        let typ = unsafe { ffi::CStr::from_ptr(get_os_release() as *const c_char).to_bytes() };
        Ok(String::from_utf8_lossy(typ).into_owned())
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, Error> {
    if cfg!(unix) || cfg!(windows) {
        unsafe { Ok(get_cpu_num()) }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, Error> {
    if cfg!(target_os = "linux") {
        // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
        let mut s = String::new();
        File::open("/proc/cpuinfo")?.read_to_string(&mut s)?;

        let mut find_cpu_mhz = s.split('\n').find(|line| line.starts_with("cpu MHz"));
        match find_cpu_mhz {
            None => find_cpu_mhz = s.split('\n').find(|line| line.starts_with("BogoMIPS")),
            _ => {}
        }

        find_cpu_mhz.and_then(|line| line.split(':').last())
            .and_then(|val| val.trim().parse::<f64>().ok())
            .map(|speed| speed as u64)
            .ok_or(Error::Unknown)

    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        unsafe { Ok(get_cpu_speed()) }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/loadavg")?.read_to_string(&mut s)?;
        let loads = s.trim().split(' ')
            .take(3)
            .map(|val| val.parse::<f64>().unwrap())
            .collect::<Vec<f64>>();
        Ok(LoadAvg {
            one: loads[0],
            five: loads[1],
            fifteen: loads[2],
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/loadavg")?.read_to_string(&mut s)?;
        s.split(' ')
            .nth(3)
            .and_then(|val| val.split('/').last())
            .and_then(|val| val.parse::<u64>().ok())
            .ok_or(Error::Unknown)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/meminfo")?.read_to_string(&mut s)?;
        let mut meminfo_hashmap = HashMap::new();
        for line in s.lines() {
            let mut split_line = line.split_whitespace();
            let label = split_line.next();
            let value = split_line.next();
            if value.is_some() && label.is_some() {
                let label = label.unwrap().split(':').nth(0).ok_or(Error::Unknown)?;
                let value = value.unwrap().parse::<u64>().ok().ok_or(Error::Unknown)?;
                meminfo_hashmap.insert(label, value);
            }
        }
        let total = *meminfo_hashmap.get("MemTotal").ok_or(Error::Unknown)?;
        let free = *meminfo_hashmap.get("MemFree").ok_or(Error::Unknown)?;
        let buffers = *meminfo_hashmap.get("Buffers").ok_or(Error::Unknown)?;
        let cached = *meminfo_hashmap.get("Cached").ok_or(Error::Unknown)?;
        let avail = meminfo_hashmap.get("MemAvailable").map(|v| v.clone()).or_else(|| {
            let sreclaimable = *meminfo_hashmap.get("SReclaimable")?;
            let shmem = *meminfo_hashmap.get("Shmem")?;
            Some(free + buffers + cached + sreclaimable - shmem)
        }).ok_or(Error::Unknown)?;
        let swap_total = *meminfo_hashmap.get("SwapTotal").ok_or(Error::Unknown)?;
        let swap_free = *meminfo_hashmap.get("SwapFree").ok_or(Error::Unknown)?;
        Ok(MemInfo {
            total,
            free,
            avail,
            buffers,
            cached,
            swap_total,
            swap_free,
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, Error> {
    if cfg!(target_os = "linux") || cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_disk_info() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, Error> {
    use std::process::Command;
    if cfg!(unix) {
        Command::new("hostname")
            .output()
            .map_err(Error::ExecFailed)
            .map(|output| String::from_utf8(output.stdout).unwrap().trim().to_string())
    } else if cfg!(windows) {
        Command::new("hostname")
            .output()
            .map_err(Error::ExecFailed)
            .map(|output| String::from_utf8(output.stdout).unwrap().trim().to_string())
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get system boottime
#[cfg(not(windows))]
pub fn boottime() -> Result<timeval, Error> {
    let mut bt = timeval {
        tv_sec: 0,
        tv_usec: 0
    };

    #[cfg(target_os = "linux")]
    {
        let mut s = String::new();
        File::open("/proc/uptime")?.read_to_string(&mut s)?;
        let secs = s.trim().split(' ')
            .take(2)
            .map(|val| val.parse::<f64>().unwrap())
            .collect::<Vec<f64>>();
        bt.tv_sec = secs[0] as libc::time_t;
        bt.tv_usec = secs[1] as libc::suseconds_t;
    }
    #[cfg(target_os = "macos")]
    {
        let mut mib = [MAC_CTL_KERN, MAC_KERN_BOOTTIME];
        let mut size: libc::size_t = size_of_val(&bt) as libc::size_t;
        unsafe {
            sysctl(&mut mib[0], 2,
                   &mut bt as *mut timeval as *mut libc::c_void,
                   &mut size, null_mut(), 0);
        }
    }

    Ok(bt)
}

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

    #[test]
    pub fn test_os_type() {
        let typ = os_type().unwrap();
        assert!(typ.len() > 0);
        println!("os_type(): {}", typ);
    }

    #[test]
    pub fn test_os_release() {
        let release = os_release().unwrap();
        assert!(release.len() > 0);
        println!("os_release(): {}", release);
    }

    #[test]
    pub fn test_cpu_num() {
        let num = cpu_num().unwrap();
        assert!(num > 0);
        println!("cpu_num(): {}", num);
    }

    #[test]
    pub fn test_cpu_speed() {
        let speed = cpu_speed().unwrap();
        assert!(speed > 0);
        println!("cpu_speed(): {}", speed);
    }

    #[test]
    pub fn test_loadavg() {
        let load = loadavg().unwrap();
        println!("loadavg(): {:?}", load);
    }

    #[test]
    pub fn test_proc_total() {
        let procs = proc_total().unwrap();
        assert!(procs > 0);
        println!("proc_total(): {}", procs);
    }

    #[test]
    pub fn test_mem_info() {
        let mem = mem_info().unwrap();
        assert!(mem.total > 0);
        println!("mem_info(): {:?}", mem);
    }

    #[test]
    pub fn test_disk_info() {
        let info = disk_info().unwrap();
        println!("disk_info(): {:?}", info);
    }

    #[test]
    pub fn test_hostname() {
        let host = hostname().unwrap();
        assert!(host.len() > 0);
        println!("hostname(): {}", host);
    }

    #[test]
    pub fn test_boottime() {
        let bt = boottime().unwrap();
        println!("boottime(): {} {}", bt.tv_sec, bt.tv_usec);
        assert!(bt.tv_sec > 0 || bt.tv_usec > 0);
    }
}
<commit_msg>Fix windows test. (#32)<commit_after>//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

extern crate libc;

use std::ffi;
use std::fmt;
use std::io::{self, Read};
use std::fs::File;
use std::os::raw::c_char;

#[cfg(target_os = "macos")]
use libc::sysctl;
use libc::timeval;
use std::mem::size_of_val;
use std::ptr::null_mut;

use std::collections::HashMap;

static MAC_CTL_KERN: libc::c_int = 1;
static MAC_KERN_BOOTTIME: libc::c_int = 21;

/// System load average value.
#[repr(C)]
#[derive(Debug)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64,
}

/// System memory information.
#[repr(C)]
#[derive(Debug)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free: u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached: u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free: u64,
}

/// Disk information.
#[repr(C)]
#[derive(Debug)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64,
}

/// Error types
#[derive(Debug)]
pub enum Error {
    UnsupportedSystem,
    ExecFailed(io::Error),
    IO(io::Error),
    Unknown,
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match *self {
            UnsupportedSystem => write!(fmt, "System is not supported"),
            ExecFailed(ref e) => write!(fmt, "Execution failed: {}", e),
            IO(ref e) => write!(fmt, "IO error: {}", e),
            Unknown => write!(fmt, "An unknown error occurred"),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            UnsupportedSystem => "unsupported system",
            ExecFailed(_) => "execution failed",
            IO(_) => "io error",
            Unknown => "unknown error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        use self::Error::*;
        match *self {
            UnsupportedSystem => None,
            ExecFailed(ref e) => Some(e),
            IO(ref e) => Some(e),
            Unknown => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::IO(e)
    }
}

extern "C" {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/sys/kernel/ostype")?.read_to_string(&mut s)?;
        s.pop(); // pop '\n'
        Ok(s)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        let typ = unsafe { ffi::CStr::from_ptr(get_os_type() as *const c_char).to_bytes() };
        Ok(String::from_utf8_lossy(typ).into_owned())
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/sys/kernel/osrelease")?.read_to_string(&mut s)?;
        s.pop(); // pop '\n'
        Ok(s)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        let typ = unsafe { ffi::CStr::from_ptr(get_os_release() as *const c_char).to_bytes() };
        Ok(String::from_utf8_lossy(typ).into_owned())
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, Error> {
    if cfg!(unix) || cfg!(windows) {
        unsafe { Ok(get_cpu_num()) }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, Error> {
    if cfg!(target_os = "linux") {
        // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
        let mut s = String::new();
        File::open("/proc/cpuinfo")?.read_to_string(&mut s)?;

        let mut find_cpu_mhz = s.split('\n').find(|line| line.starts_with("cpu MHz"));
        match find_cpu_mhz {
            None => find_cpu_mhz = s.split('\n').find(|line| line.starts_with("BogoMIPS")),
            _ => {}
        }

        find_cpu_mhz.and_then(|line| line.split(':').last())
            .and_then(|val| val.trim().parse::<f64>().ok())
            .map(|speed| speed as u64)
            .ok_or(Error::Unknown)

    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        unsafe { Ok(get_cpu_speed()) }
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/loadavg")?.read_to_string(&mut s)?;
        let loads = s.trim().split(' ')
            .take(3)
            .map(|val| val.parse::<f64>().unwrap())
            .collect::<Vec<f64>>();
        Ok(LoadAvg {
            one: loads[0],
            five: loads[1],
            fifteen: loads[2],
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/loadavg")?.read_to_string(&mut s)?;
        s.split(' ')
            .nth(3)
            .and_then(|val| val.split('/').last())
            .and_then(|val| val.parse::<u64>().ok())
            .ok_or(Error::Unknown)
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, Error> {
    if cfg!(target_os = "linux") {
        let mut s = String::new();
        File::open("/proc/meminfo")?.read_to_string(&mut s)?;
        let mut meminfo_hashmap = HashMap::new();
        for line in s.lines() {
            let mut split_line = line.split_whitespace();
            let label = split_line.next();
            let value = split_line.next();
            if value.is_some() && label.is_some() {
                let label = label.unwrap().split(':').nth(0).ok_or(Error::Unknown)?;
                let value = value.unwrap().parse::<u64>().ok().ok_or(Error::Unknown)?;
                meminfo_hashmap.insert(label, value);
            }
        }
        let total = *meminfo_hashmap.get("MemTotal").ok_or(Error::Unknown)?;
        let free = *meminfo_hashmap.get("MemFree").ok_or(Error::Unknown)?;
        let buffers = *meminfo_hashmap.get("Buffers").ok_or(Error::Unknown)?;
        let cached = *meminfo_hashmap.get("Cached").ok_or(Error::Unknown)?;
        let avail = meminfo_hashmap.get("MemAvailable").map(|v| v.clone()).or_else(|| {
            let sreclaimable = *meminfo_hashmap.get("SReclaimable")?;
            let shmem = *meminfo_hashmap.get("Shmem")?;
            Some(free + buffers + cached + sreclaimable - shmem)
        }).ok_or(Error::Unknown)?;
        let swap_total = *meminfo_hashmap.get("SwapTotal").ok_or(Error::Unknown)?;
        let swap_free = *meminfo_hashmap.get("SwapFree").ok_or(Error::Unknown)?;
        Ok(MemInfo {
            total,
            free,
            avail,
            buffers,
            cached,
            swap_total,
            swap_free,
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, Error> {
    if cfg!(target_os = "linux") || cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_disk_info() })
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, Error> {
    use std::process::Command;
    if cfg!(unix) {
        Command::new("hostname")
            .output()
            .map_err(Error::ExecFailed)
            .map(|output| String::from_utf8(output.stdout).unwrap().trim().to_string())
    } else if cfg!(windows) {
        Command::new("hostname")
            .output()
            .map_err(Error::ExecFailed)
            .map(|output| String::from_utf8(output.stdout).unwrap().trim().to_string())
    } else {
        Err(Error::UnsupportedSystem)
    }
}

/// Get system boottime
#[cfg(not(windows))]
pub fn boottime() -> Result<timeval, Error> {
    let mut bt = timeval {
        tv_sec: 0,
        tv_usec: 0
    };

    #[cfg(target_os = "linux")]
    {
        let mut s = String::new();
        File::open("/proc/uptime")?.read_to_string(&mut s)?;
        let secs = s.trim().split(' ')
            .take(2)
            .map(|val| val.parse::<f64>().unwrap())
            .collect::<Vec<f64>>();
        bt.tv_sec = secs[0] as libc::time_t;
        bt.tv_usec = secs[1] as libc::suseconds_t;
    }
    #[cfg(target_os = "macos")]
    {
        let mut mib = [MAC_CTL_KERN, MAC_KERN_BOOTTIME];
        let mut size: libc::size_t = size_of_val(&bt) as libc::size_t;
        unsafe {
            sysctl(&mut mib[0], 2,
                   &mut bt as *mut timeval as *mut libc::c_void,
                   &mut size, null_mut(), 0);
        }
    }

    Ok(bt)
}

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

    #[test]
    pub fn test_os_type() {
        let typ = os_type().unwrap();
        assert!(typ.len() > 0);
        println!("os_type(): {}", typ);
    }

    #[test]
    pub fn test_os_release() {
        let release = os_release().unwrap();
        assert!(release.len() > 0);
        println!("os_release(): {}", release);
    }

    #[test]
    pub fn test_cpu_num() {
        let num = cpu_num().unwrap();
        assert!(num > 0);
        println!("cpu_num(): {}", num);
    }

    #[test]
    pub fn test_cpu_speed() {
        let speed = cpu_speed().unwrap();
        assert!(speed > 0);
        println!("cpu_speed(): {}", speed);
    }

    #[test]
    pub fn test_loadavg() {
        let load = loadavg().unwrap();
        println!("loadavg(): {:?}", load);
    }

    #[test]
    pub fn test_proc_total() {
        let procs = proc_total().unwrap();
        assert!(procs > 0);
        println!("proc_total(): {}", procs);
    }

    #[test]
    pub fn test_mem_info() {
        let mem = mem_info().unwrap();
        assert!(mem.total > 0);
        println!("mem_info(): {:?}", mem);
    }

    #[test]
    pub fn test_disk_info() {
        let info = disk_info().unwrap();
        println!("disk_info(): {:?}", info);
    }

    #[test]
    pub fn test_hostname() {
        let host = hostname().unwrap();
        assert!(host.len() > 0);
        println!("hostname(): {}", host);
    }

    #[test]
    #[cfg(not(windows))]
    pub fn test_boottime() {
        let bt = boottime().unwrap();
        println!("boottime(): {} {}", bt.tv_sec, bt.tv_usec);
        assert!(bt.tv_sec > 0 || bt.tv_usec > 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#[feature(globs)];

extern mod std;

pub mod xlib;
<commit_msg>Set link name.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#[link(name = "xlib", vers = "0.1")];

#[feature(globs)];

extern mod std;

pub mod xlib;
<|endoftext|>


<commit_before>use std::fmt;
use std::mem::transmute;
use std::ops::Deref;

use llvm_sys::prelude::*;
use llvm_sys::core::*;
use llvm_sys::*;

use super::*;

/// Enumeration of all the base types of the LLVM type system.
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub enum Kind {
    Void = 0,
    Half,
    Float,
    Double,
    X86_FP80,
    FP128,
    PPC_FP128,
    Label,
    Integer,
    Function,
    Struct,
    Array,
    Pointer,
    Vector,
    Metadata,
    X86_MMX,
    Token,
}
}

/// Should always be used as `&Type`.
///
/// `Type`s are owned by `Context` instances such that only one instance of a
/// specific `Type` exists per `Context`, e.g. only 1 `Type` for `i64` exists
/// per context. `Type`s are also never mutated and never destroyed, living for
/// the lifetime of the `Context` that owns them.
// TODO: can this be made into an unsized type?
pub struct Type(LLVMType);

impl<'a> Into<&'a Type> for LLVMTypeRef {
    fn into(self) -> &'a Type {
        unsafe { transmute::<LLVMTypeRef, &Type>(self) }
    }
}

impl<'a> From<&'a Type> for LLVMTypeRef {
    fn from(ty: &'a Type) -> LLVMTypeRef {
        unsafe { transmute::<&Type, LLVMTypeRef>(ty) }
    }
}

impl Type {
    pub fn kind(&self) -> Kind {
        unsafe { transmute(LLVMGetTypeKind(self.into())) }
    }

    pub fn is_sized(&self) -> bool {
        unsafe { LLVMTypeIsSized(self.into()) == 1 }
    }
}

// This counts as the llvm::Type::print method from the C++ API, though the C++
// version has more options.
impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let s_ptr = LLVMPrintTypeToString(self.into());
            let r = write!(f, "{}", c_str_to_str!(s_ptr));
            LLVMDisposeMessage(s_ptr);
            r
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "llvm::Type({})", self)
    }
}

impl PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        LLVMTypeRef::from(self) == LLVMTypeRef::from(other)
    }
}

impl Eq for Type {}

macro_rules! impl_type {
    ($t:ty) => {
        impl<'a> Into<&'a $t> for LLVMTypeRef {
            fn into(self) -> &'a $t {
                unsafe { transmute::<LLVMTypeRef, &$t>(self) }
            }
        }

        impl<'a> From<&'a $t> for LLVMTypeRef {
            fn from(ty: &'a $t) -> LLVMTypeRef {
                unsafe { transmute::<&$t, LLVMTypeRef>(ty) }
            }
        }

        impl Deref for $t {
            type Target = Type;

            fn deref(&self) -> &Self::Target {
                unsafe { transmute::<&Self, &Self::Target>(self) }
            }
        }
    }
}

// Base types:

pub struct Void(Type);
impl_type!(Void);

pub struct Half(Type);
impl_type!(Half);

pub struct Float(Type);
impl_type!(Float);

pub struct Double(Type);
impl_type!(Double);

#[allow(non_camel_case_types)]
pub struct X86_FP80(Type);
impl_type!(X86_FP80);

#[allow(non_camel_case_types)]
pub struct FP128(Type);
impl_type!(FP128);

#[allow(non_camel_case_types)]
pub struct PPC_FP128(Type);
impl_type!(PPC_FP128);

pub struct Label(Type);
impl_type!(Label);

pub struct Metadata(Type);
impl_type!(Metadata);

#[allow(non_camel_case_types)]
pub struct X86_MMX(Type);
impl_type!(X86_MMX);

pub struct Token(Type);
impl_type!(Token);

/// Integer types are constructed with a size. Construct them with the methods
/// that `Context` provides.
pub struct Integer(Type);
impl_type!(Integer);

/// A function type is a tuple consisting of a return type and an array of
/// parameter types.
// TODO: check how varargs work

pub struct Function(Type);
impl_type!(Function);

impl Function {
    pub fn new<'a>(
        return_type: &'a Type,
        param_types: &[&'a Type],
        is_var_args: bool,
    ) -> &'a Function {
        unsafe {
            LLVMFunctionType(
                return_type.into(),
                transmute::<*const &Type, *mut LLVMTypeRef>(param_types.as_ptr()),
                param_types.len() as u32,
                is_var_args as LLVMBool,
            ).into()
        }
    }
}

// TODO: Struct, Array, Pointer, Vector

/// Represents a LLVM Context Type
pub trait ContextType {
    fn get_type_in_context<'a>(context: &'a Context) -> &'a Type;
}

macro_rules! impl_context_type {
    ($t: ty, $to_type_in_context: ident) => {
        impl ContextType for $t {
            fn get_type_in_context<'a>(context: &'a Context) -> &'a Type {
                unsafe {
                    $to_type_in_context(context.ptr).into()
                }
            }
        }
    }
}

impl_context_type!(bool, LLVMInt1TypeInContext);
// This might actually not be true, Not sure
impl_context_type!(char, LLVMInt8TypeInContext);
impl_context_type!(u8, LLVMInt8TypeInContext);
impl_context_type!(u16, LLVMInt16TypeInContext);
impl_context_type!(u32, LLVMInt32TypeInContext);
impl_context_type!(u64, LLVMInt64TypeInContext);
impl_context_type!(i8, LLVMInt8TypeInContext);
impl_context_type!(i16, LLVMInt16TypeInContext);
impl_context_type!(i32, LLVMInt32TypeInContext);
impl_context_type!(i64, LLVMInt64TypeInContext);
impl_context_type!(f32, LLVMFloatTypeInContext);
impl_context_type!(f64, LLVMDoubleTypeInContext);
//TODO: Function Types
//TODO: Structure Types
//TODO: Sequential Types
//TODO: Other Types
<commit_msg>wrap last few base types<commit_after>use std::fmt;
use std::mem::transmute;
use std::ops::Deref;

use llvm_sys::prelude::*;
use llvm_sys::core::*;
use llvm_sys::*;

use super::*;

/// Enumeration of all the base types of the LLVM type system.
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub enum Kind {
    Void = 0,
    Half,
    Float,
    Double,
    X86_FP80,
    FP128,
    PPC_FP128,
    Label,
    Integer,
    Function,
    Struct,
    Array,
    Pointer,
    Vector,
    Metadata,
    X86_MMX,
    Token,
}
}

/// Should always be used as `&Type`.
///
/// `Type`s are owned by `Context` instances such that only one instance of a
/// specific `Type` exists per `Context`, e.g. only 1 `Type` for `i64` exists
/// per context. `Type`s are also never mutated and never destroyed, living for
/// the lifetime of the `Context` that owns them.
// TODO: can this be made into an unsized type?
pub struct Type(LLVMType);

impl<'a> Into<&'a Type> for LLVMTypeRef {
    fn into(self) -> &'a Type {
        unsafe { transmute::<LLVMTypeRef, &Type>(self) }
    }
}

impl<'a> From<&'a Type> for LLVMTypeRef {
    fn from(ty: &'a Type) -> LLVMTypeRef {
        unsafe { transmute::<&Type, LLVMTypeRef>(ty) }
    }
}

impl Type {
    pub fn kind(&self) -> Kind {
        unsafe { transmute(LLVMGetTypeKind(self.into())) }
    }

    pub fn is_sized(&self) -> bool {
        unsafe { LLVMTypeIsSized(self.into()) == 1 }
    }
}

// This counts as the llvm::Type::print method from the C++ API, though the C++
// version has more options.
impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let s_ptr = LLVMPrintTypeToString(self.into());
            let r = write!(f, "{}", c_str_to_str!(s_ptr));
            LLVMDisposeMessage(s_ptr);
            r
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "llvm::Type({})", self)
    }
}

impl PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        LLVMTypeRef::from(self) == LLVMTypeRef::from(other)
    }
}

impl Eq for Type {}

macro_rules! impl_type {
    ($t:ty) => {
        impl<'a> Into<&'a $t> for LLVMTypeRef {
            fn into(self) -> &'a $t {
                unsafe { transmute::<LLVMTypeRef, &$t>(self) }
            }
        }

        impl<'a> From<&'a $t> for LLVMTypeRef {
            fn from(ty: &'a $t) -> LLVMTypeRef {
                unsafe { transmute::<&$t, LLVMTypeRef>(ty) }
            }
        }

        impl Deref for $t {
            type Target = Type;

            fn deref(&self) -> &Self::Target {
                unsafe { transmute::<&Self, &Self::Target>(self) }
            }
        }
    }
}

// Base types:

pub struct Void(Type);
impl_type!(Void);

pub struct Half(Type);
impl_type!(Half);

pub struct Float(Type);
impl_type!(Float);

pub struct Double(Type);
impl_type!(Double);

#[allow(non_camel_case_types)]
pub struct X86_FP80(Type);
impl_type!(X86_FP80);

#[allow(non_camel_case_types)]
pub struct FP128(Type);
impl_type!(FP128);

#[allow(non_camel_case_types)]
pub struct PPC_FP128(Type);
impl_type!(PPC_FP128);

pub struct Label(Type);
impl_type!(Label);

pub struct Metadata(Type);
impl_type!(Metadata);

#[allow(non_camel_case_types)]
pub struct X86_MMX(Type);
impl_type!(X86_MMX);

pub struct Token(Type);
impl_type!(Token);

/// Integer types are constructed with a size. Construct them with the methods
/// that `Context` provides.
pub struct Integer(Type);
impl_type!(Integer);

/// A function type is a tuple consisting of a return type and an array of
/// parameter types.
pub struct Function(Type);
impl_type!(Function);

impl Function {
    pub fn new<'a>(
        return_type: &'a Type,
        param_types: &[&'a Type],
        is_var_args: bool,
    ) -> &'a Function {
        unsafe {
            LLVMFunctionType(
                return_type.into(),
                transmute::<*const &Type, *mut LLVMTypeRef>(param_types.as_ptr()),
                param_types.len() as u32,
                is_var_args as LLVMBool,
            ).into()
        }
    }
}

pub struct Struct(Type);
impl_type!(Struct);

pub struct Array(Type);
impl_type!(Array);

pub struct Pointer(Type);
impl_type!(Pointer);

pub struct Vector(Type);
impl_type!(Vector);

/// Represents a LLVM Context Type
pub trait ContextType {
    fn get_type_in_context<'a>(context: &'a Context) -> &'a Type;
}

macro_rules! impl_context_type {
    ($t: ty, $to_type_in_context: ident) => {
        impl ContextType for $t {
            fn get_type_in_context<'a>(context: &'a Context) -> &'a Type {
                unsafe {
                    $to_type_in_context(context.ptr).into()
                }
            }
        }
    }
}

impl_context_type!(bool, LLVMInt1TypeInContext);
// This might actually not be true, Not sure
impl_context_type!(char, LLVMInt8TypeInContext);
impl_context_type!(u8, LLVMInt8TypeInContext);
impl_context_type!(u16, LLVMInt16TypeInContext);
impl_context_type!(u32, LLVMInt32TypeInContext);
impl_context_type!(u64, LLVMInt64TypeInContext);
impl_context_type!(i8, LLVMInt8TypeInContext);
impl_context_type!(i16, LLVMInt16TypeInContext);
impl_context_type!(i32, LLVMInt32TypeInContext);
impl_context_type!(i64, LLVMInt64TypeInContext);
impl_context_type!(f32, LLVMFloatTypeInContext);
impl_context_type!(f64, LLVMDoubleTypeInContext);
//TODO: Function Types
//TODO: Structure Types
//TODO: Sequential Types
//TODO: Other Types
<|endoftext|>


<commit_before>//! Traits dealing with SQLite data types.
//!
//! SQLite uses a [dynamic type system](https://www.sqlite.org/datatype3.html). Implementations of
//! the `ToSql` and `FromSql` traits are provided for the basic types that SQLite provides methods
//! for:
//!
//! * C integers and doubles (`c_int` and `c_double`)
//! * Strings (`String` and `&str`)
//! * Blobs (`Vec<u8>` and `&[u8]`)
//!
//! Additionally, because it is such a common data type, implementations are provided for
//! `time::Timespec` that use a string for storage (using the same format string,
//! `"%Y-%m-%d %H:%M:%S"`, as SQLite's builtin
//! [datetime](https://www.sqlite.org/lang_datefunc.html) function.  Note that this storage
//! truncates timespecs to the nearest second. If you want different storage for timespecs, you can
//! use a newtype. For example, to store timespecs as doubles:
//!
//! `ToSql` and `FromSql` are also implemented for `Option<T>` where `T` implements `ToSql` or
//! `FromSql` for the cases where you want to know if a value was NULL (which gets translated to
//! `None`). If you get a value that was NULL in SQLite but you store it into a non-`Option` value
//! in Rust, you will get a "sensible" zero value - 0 for numeric types (including timespecs), an
//! empty string, or an empty vector of bytes.
//!
//! ```rust,ignore
//! extern crate rusqlite;
//! extern crate libc;
//!
//! use rusqlite::types::{FromSql, ToSql};
//! use rusqlite::{ffi, SqliteResult};
//! use libc::c_int;
//! use time;
//!
//! pub struct TimespecSql(pub time::Timespec);
//!
//! impl FromSql for TimespecSql {
//!     unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int)
//!             -> SqliteResult<TimespecSql> {
//!         let as_f64_result = FromSql::column_result(stmt, col);
//!         as_f64_result.map(|as_f64: f64| {
//!             TimespecSql(time::Timespec{ sec: as_f64.trunc() as i64,
//!                                         nsec: (as_f64.fract() * 1.0e9) as i32 })
//!         })
//!     }
//! }
//!
//! impl ToSql for TimespecSql {
//!     unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
//!         let TimespecSql(ts) = *self;
//!         let as_f64 = ts.sec as f64 + (ts.nsec as f64) / 1.0e9;
//!         as_f64.bind_parameter(stmt, col)
//!     }
//! }
//! ```

extern crate time;

use libc::{c_int, c_double};
use std::c_str::{CString};
use std::mem;
use std::vec;
use super::ffi;
use super::{SqliteResult, SqliteError};

const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S";

/// A trait for types that can be converted into SQLite values.
pub trait ToSql {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int;
}

/// A trait for types that can be created from a SQLite value.
pub trait FromSql {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<Self>;
}

macro_rules! raw_to_impl(
    ($t:ty, $f:ident) => (
        impl ToSql for $t {
            unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
                ffi::$f(stmt, col, *self)
            }
        }
    )
)

raw_to_impl!(c_int, sqlite3_bind_int)
raw_to_impl!(i64, sqlite3_bind_int64)
raw_to_impl!(c_double, sqlite3_bind_double)

impl<'a> ToSql for &'a str {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        self.with_c_str(|c_str| {
            ffi::sqlite3_bind_text(stmt, col, c_str, -1, Some(ffi::SQLITE_TRANSIENT()))
        })
    }
}

impl ToSql for String {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        self.as_slice().bind_parameter(stmt, col)
    }
}

impl<'a> ToSql for &'a [u8] {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        ffi::sqlite3_bind_blob(
            stmt, col, mem::transmute(self.as_ptr()), self.len() as c_int,
            Some(ffi::SQLITE_TRANSIENT()))
    }
}

impl ToSql for Vec<u8> {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        self.as_slice().bind_parameter(stmt, col)
    }
}

impl ToSql for time::Timespec {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        let time_str = time::at_utc(*self).strftime(SQLITE_DATETIME_FMT).unwrap().to_string();
        time_str.bind_parameter(stmt, col)
    }
}

impl<T: ToSql> ToSql for Option<T> {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        match *self {
            None => ffi::sqlite3_bind_null(stmt, col),
            Some(ref t) => t.bind_parameter(stmt, col),
        }
    }
}

/// Empty struct that can be used to fill in a query parameter as `NULL`.
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{SqliteConnection, SqliteResult};
/// # use rusqlite::types::{Null};
/// fn insert_null(conn: &SqliteConnection) -> SqliteResult<uint> {
///     conn.execute("INSERT INTO people (name) VALUES (?)", &[&Null])
/// }
/// ```
pub struct Null;

impl ToSql for Null {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        ffi::sqlite3_bind_null(stmt, col)
    }
}

macro_rules! raw_from_impl(
    ($t:ty, $f:ident) => (
        impl FromSql for $t {
            unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<$t> {
                Ok(ffi::$f(stmt, col))
            }
        }
    )
)

raw_from_impl!(c_int, sqlite3_column_int)
raw_from_impl!(i64, sqlite3_column_int64)
raw_from_impl!(c_double, sqlite3_column_double)

impl FromSql for String {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<String> {
        let c_text = ffi::sqlite3_column_text(stmt, col);
        if c_text.is_null() {
            Ok("".to_string())
        } else {
            match CString::new(mem::transmute(c_text), false).as_str() {
                Some(s) => Ok(s.to_string()),
                None => Err(SqliteError{ code: ffi::SQLITE_MISMATCH,
                    message: "Could not convert text to UTF-8".to_string() })
            }
        }
    }
}

impl FromSql for Vec<u8> {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<Vec<u8>> {
        let c_blob = ffi::sqlite3_column_blob(stmt, col);
        let len = ffi::sqlite3_column_bytes(stmt, col);

        assert!(len >= 0); let len = len as uint;

        Ok(vec::raw::from_buf(mem::transmute(c_blob), len))
    }
}

impl FromSql for time::Timespec {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt,
                            col: c_int) -> SqliteResult<time::Timespec> {
        let col_str = FromSql::column_result(stmt, col);
        col_str.and_then(|txt: String| {
            time::strptime(txt.as_slice(), SQLITE_DATETIME_FMT).map(|tm| {
                tm.to_timespec()
            }).map_err(|parse_error| {
                SqliteError{ code: ffi::SQLITE_MISMATCH, message: format!("{}", parse_error) }
            })
        })
    }
}

impl<T: FromSql> FromSql for Option<T> {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<Option<T>> {
        if ffi::sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL {
            Ok(None)
        } else {
            FromSql::column_result(stmt, col).map(|t| Some(t))
        }
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;
    use super::time;

    fn checked_memory_handle() -> SqliteConnection {
        let db = SqliteConnection::open(":memory:").unwrap();
        db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT)").unwrap();
        db
    }

    #[test]
    fn test_blob() {
        let db = checked_memory_handle();

        let v1234 = vec![1u8,2,3,4];
        db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234]).unwrap();

        let v: Vec<u8> = db.query_row("SELECT b FROM foo", &[], |r| r.get(0));
        assert_eq!(v, v1234);
    }

    #[test]
    fn test_str() {
        let db = checked_memory_handle();

        let s = "hello, world!";
        db.execute("INSERT INTO foo(t) VALUES (?)", &[&s.to_string()]).unwrap();

        let from: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0));
        assert_eq!(from.as_slice(), s);
    }

    #[test]
    fn test_timespec() {
        let db = checked_memory_handle();

        let ts = time::Timespec{sec: 10_000, nsec: 0 };
        db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts]).unwrap();

        let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0));
        assert_eq!(from, ts);
    }

    #[test]
    fn test_option() {
        let db = checked_memory_handle();

        let s = Some("hello, world!");
        let b = Some(vec![1u8,2,3,4]);

        db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap();
        db.execute("INSERT INTO foo(b) VALUES (?)", &[&b]).unwrap();

        let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC").unwrap();
        let mut rows = stmt.query(&[]).unwrap();

        let row1 = rows.next().unwrap().unwrap();
        let s1: Option<String> = row1.get(0);
        let b1: Option<Vec<u8>> = row1.get(1);
        assert_eq!(s.unwrap(), s1.unwrap().as_slice());
        assert!(b1.is_none());

        let row2 = rows.next().unwrap().unwrap();
        let s2: Option<String> = row2.get(0);
        let b2: Option<Vec<u8>> = row2.get(1);
        assert!(s2.is_none());
        assert_eq!(b, b2);
    }
}
<commit_msg>Use `Vec::from_raw_buf` instead of `vec::raw::from_buf`<commit_after>//! Traits dealing with SQLite data types.
//!
//! SQLite uses a [dynamic type system](https://www.sqlite.org/datatype3.html). Implementations of
//! the `ToSql` and `FromSql` traits are provided for the basic types that SQLite provides methods
//! for:
//!
//! * C integers and doubles (`c_int` and `c_double`)
//! * Strings (`String` and `&str`)
//! * Blobs (`Vec<u8>` and `&[u8]`)
//!
//! Additionally, because it is such a common data type, implementations are provided for
//! `time::Timespec` that use a string for storage (using the same format string,
//! `"%Y-%m-%d %H:%M:%S"`, as SQLite's builtin
//! [datetime](https://www.sqlite.org/lang_datefunc.html) function.  Note that this storage
//! truncates timespecs to the nearest second. If you want different storage for timespecs, you can
//! use a newtype. For example, to store timespecs as doubles:
//!
//! `ToSql` and `FromSql` are also implemented for `Option<T>` where `T` implements `ToSql` or
//! `FromSql` for the cases where you want to know if a value was NULL (which gets translated to
//! `None`). If you get a value that was NULL in SQLite but you store it into a non-`Option` value
//! in Rust, you will get a "sensible" zero value - 0 for numeric types (including timespecs), an
//! empty string, or an empty vector of bytes.
//!
//! ```rust,ignore
//! extern crate rusqlite;
//! extern crate libc;
//!
//! use rusqlite::types::{FromSql, ToSql};
//! use rusqlite::{ffi, SqliteResult};
//! use libc::c_int;
//! use time;
//!
//! pub struct TimespecSql(pub time::Timespec);
//!
//! impl FromSql for TimespecSql {
//!     unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int)
//!             -> SqliteResult<TimespecSql> {
//!         let as_f64_result = FromSql::column_result(stmt, col);
//!         as_f64_result.map(|as_f64: f64| {
//!             TimespecSql(time::Timespec{ sec: as_f64.trunc() as i64,
//!                                         nsec: (as_f64.fract() * 1.0e9) as i32 })
//!         })
//!     }
//! }
//!
//! impl ToSql for TimespecSql {
//!     unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
//!         let TimespecSql(ts) = *self;
//!         let as_f64 = ts.sec as f64 + (ts.nsec as f64) / 1.0e9;
//!         as_f64.bind_parameter(stmt, col)
//!     }
//! }
//! ```

extern crate time;

use libc::{c_int, c_double};
use std::c_str::{CString};
use std::mem;
use super::ffi;
use super::{SqliteResult, SqliteError};

const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S";

/// A trait for types that can be converted into SQLite values.
pub trait ToSql {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int;
}

/// A trait for types that can be created from a SQLite value.
pub trait FromSql {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<Self>;
}

macro_rules! raw_to_impl(
    ($t:ty, $f:ident) => (
        impl ToSql for $t {
            unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
                ffi::$f(stmt, col, *self)
            }
        }
    )
)

raw_to_impl!(c_int, sqlite3_bind_int)
raw_to_impl!(i64, sqlite3_bind_int64)
raw_to_impl!(c_double, sqlite3_bind_double)

impl<'a> ToSql for &'a str {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        self.with_c_str(|c_str| {
            ffi::sqlite3_bind_text(stmt, col, c_str, -1, Some(ffi::SQLITE_TRANSIENT()))
        })
    }
}

impl ToSql for String {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        self.as_slice().bind_parameter(stmt, col)
    }
}

impl<'a> ToSql for &'a [u8] {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        ffi::sqlite3_bind_blob(
            stmt, col, mem::transmute(self.as_ptr()), self.len() as c_int,
            Some(ffi::SQLITE_TRANSIENT()))
    }
}

impl ToSql for Vec<u8> {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        self.as_slice().bind_parameter(stmt, col)
    }
}

impl ToSql for time::Timespec {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        let time_str = time::at_utc(*self).strftime(SQLITE_DATETIME_FMT).unwrap().to_string();
        time_str.bind_parameter(stmt, col)
    }
}

impl<T: ToSql> ToSql for Option<T> {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        match *self {
            None => ffi::sqlite3_bind_null(stmt, col),
            Some(ref t) => t.bind_parameter(stmt, col),
        }
    }
}

/// Empty struct that can be used to fill in a query parameter as `NULL`.
///
/// ## Example
///
/// ```rust,no_run
/// # use rusqlite::{SqliteConnection, SqliteResult};
/// # use rusqlite::types::{Null};
/// fn insert_null(conn: &SqliteConnection) -> SqliteResult<uint> {
///     conn.execute("INSERT INTO people (name) VALUES (?)", &[&Null])
/// }
/// ```
pub struct Null;

impl ToSql for Null {
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
        ffi::sqlite3_bind_null(stmt, col)
    }
}

macro_rules! raw_from_impl(
    ($t:ty, $f:ident) => (
        impl FromSql for $t {
            unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<$t> {
                Ok(ffi::$f(stmt, col))
            }
        }
    )
)

raw_from_impl!(c_int, sqlite3_column_int)
raw_from_impl!(i64, sqlite3_column_int64)
raw_from_impl!(c_double, sqlite3_column_double)

impl FromSql for String {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<String> {
        let c_text = ffi::sqlite3_column_text(stmt, col);
        if c_text.is_null() {
            Ok("".to_string())
        } else {
            match CString::new(mem::transmute(c_text), false).as_str() {
                Some(s) => Ok(s.to_string()),
                None => Err(SqliteError{ code: ffi::SQLITE_MISMATCH,
                    message: "Could not convert text to UTF-8".to_string() })
            }
        }
    }
}

impl FromSql for Vec<u8> {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<Vec<u8>> {
        let c_blob = ffi::sqlite3_column_blob(stmt, col);
        let len = ffi::sqlite3_column_bytes(stmt, col);

        assert!(len >= 0); let len = len as uint;

        Ok(Vec::from_raw_buf(mem::transmute(c_blob), len))
    }
}

impl FromSql for time::Timespec {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt,
                            col: c_int) -> SqliteResult<time::Timespec> {
        let col_str = FromSql::column_result(stmt, col);
        col_str.and_then(|txt: String| {
            time::strptime(txt.as_slice(), SQLITE_DATETIME_FMT).map(|tm| {
                tm.to_timespec()
            }).map_err(|parse_error| {
                SqliteError{ code: ffi::SQLITE_MISMATCH, message: format!("{}", parse_error) }
            })
        })
    }
}

impl<T: FromSql> FromSql for Option<T> {
    unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<Option<T>> {
        if ffi::sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL {
            Ok(None)
        } else {
            FromSql::column_result(stmt, col).map(|t| Some(t))
        }
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;
    use super::time;

    fn checked_memory_handle() -> SqliteConnection {
        let db = SqliteConnection::open(":memory:").unwrap();
        db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT)").unwrap();
        db
    }

    #[test]
    fn test_blob() {
        let db = checked_memory_handle();

        let v1234 = vec![1u8,2,3,4];
        db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234]).unwrap();

        let v: Vec<u8> = db.query_row("SELECT b FROM foo", &[], |r| r.get(0));
        assert_eq!(v, v1234);
    }

    #[test]
    fn test_str() {
        let db = checked_memory_handle();

        let s = "hello, world!";
        db.execute("INSERT INTO foo(t) VALUES (?)", &[&s.to_string()]).unwrap();

        let from: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0));
        assert_eq!(from.as_slice(), s);
    }

    #[test]
    fn test_timespec() {
        let db = checked_memory_handle();

        let ts = time::Timespec{sec: 10_000, nsec: 0 };
        db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts]).unwrap();

        let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0));
        assert_eq!(from, ts);
    }

    #[test]
    fn test_option() {
        let db = checked_memory_handle();

        let s = Some("hello, world!");
        let b = Some(vec![1u8,2,3,4]);

        db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap();
        db.execute("INSERT INTO foo(b) VALUES (?)", &[&b]).unwrap();

        let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC").unwrap();
        let mut rows = stmt.query(&[]).unwrap();

        let row1 = rows.next().unwrap().unwrap();
        let s1: Option<String> = row1.get(0);
        let b1: Option<Vec<u8>> = row1.get(1);
        assert_eq!(s.unwrap(), s1.unwrap().as_slice());
        assert!(b1.is_none());

        let row2 = rows.next().unwrap().unwrap();
        let s2: Option<String> = row2.get(0);
        let b2: Option<Vec<u8>> = row2.get(1);
        assert!(s2.is_none());
        assert_eq!(b, b2);
    }
}
<|endoftext|>