<commit_before>// Copyright 2016 The android_logger Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

//! A logger which writes to android output.
//!
//! ## Example
//!
//! ```ignore
//! #[macro_use] extern crate log;
//! extern crate android_logger;
//!
//! use log::LogLevel;
//!
//! fn native_activity_create() {
//!     android_logger::init_once(LogLevel::Trace);
//!
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//!
//!     if log_enabled!(LogLevel::Info) {
//!         let x = 3 * 4; // expensive computation
//!         info!("the answer was: {}", x);
//!     }
//! }
//! ```

extern crate android_log_sys as log_ffi;
#[macro_use] extern crate log;

use log_ffi::LogPriority;
use log::{Log,LogLevel,LogMetadata,LogRecord};
use std::ffi::{ CStr, CString };

/// Output log to android system.
fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
    unsafe { log_ffi::__android_log_write(prio as log_ffi::c_int, tag.as_ptr(), msg.as_ptr()) };
}

struct PlatformLogger;

impl Log for PlatformLogger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, record: &LogRecord) {
        let tag = CString::new(record.location().module_path()).unwrap();
        let msg = CString::new(format!("{}", record.args())).unwrap();
        match record.level() {
            LogLevel::Warn => android_log(LogPriority::WARN, &tag, &msg),
            LogLevel::Info => android_log(LogPriority::INFO, &tag, &msg),
            LogLevel::Debug => android_log(LogPriority::DEBUG, &tag, &msg),
            LogLevel::Error => android_log(LogPriority::ERROR, &tag, &msg),
            LogLevel::Trace => android_log(LogPriority::VERBOSE, &tag, &msg),
        }
    }
}

/// Initializes the global logger with an android logger.
///
/// This can be called many times, but will only initialize logging once,
/// and will not replace any other previously initialized logger.
///
/// It is ok to call this at the activity creation, and it will be
/// repeatedly called on every lifecycle restart (i.e. screen rotation).
pub fn init_once(log_level: LogLevel) {
    match log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        return Box::new(PlatformLogger);
    }) {
        Err(e) => debug!("{}", e),
        _ => (),
    }
}
<commit_msg>Efficiently split log message into several parts if it exceeds allowed length.<commit_after>// Copyright 2016 The android_logger Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

//! A logger which writes to android output.
//!
//! ## Example
//!
//! ```ignore
//! #[macro_use] extern crate log;
//! extern crate android_logger;
//!
//! use log::LogLevel;
//!
//! fn native_activity_create() {
//!     android_logger::init_once(LogLevel::Trace);
//!
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//!
//!     if log_enabled!(LogLevel::Info) {
//!         let x = 3 * 4; // expensive computation
//!         info!("the answer was: {}", x);
//!     }
//! }
//! ```

extern crate android_log_sys as log_ffi;
#[macro_use] extern crate log;

use log_ffi::LogPriority;
use log::{Log,LogLevel,LogMetadata,LogRecord};
use std::ffi::CStr;
use std::mem;
use std::fmt;

/// Output log to android system.
fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
    unsafe { log_ffi::__android_log_write(prio as log_ffi::c_int, tag.as_ptr(), msg.as_ptr()) };
}

struct PlatformLogger;

const LOGGING_TAG_MAX_LEN: usize = 23;
const LOGGING_MSG_MAX_LEN: usize = 4000;

impl Log for PlatformLogger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, record: &LogRecord) {
        // tag must not exceed LOGGING_TAG_MAX_LEN
        let mut tag_bytes: [u8; LOGGING_TAG_MAX_LEN + 1] = unsafe { mem::uninitialized() };
        // truncate the tag here to fit into LOGGING_TAG_MAX_LEN
        self.fill_tag_bytes(&mut tag_bytes, record);
        // use stack array as C string
        let tag: &CStr = unsafe { CStr::from_ptr(mem::transmute(tag_bytes.as_ptr())) };

        // message must not exceed LOGGING_MSG_MAX_LEN
        // therefore split log message into multiple log calls
        let mut writer = PlatformLogWriter::new(
            record.level(),
            tag
        );

        // use PlatformLogWriter to output chunks if they exceed max size
        let _ = fmt::write(&mut writer, *record.args());

        // output the remaining message (this would usually be the most common case)
        writer.flush();
    }
}

impl PlatformLogger {
    fn fill_tag_bytes(&self, array: &mut [u8], record: &LogRecord) {
        let tag_bytes_iter = record.location().module_path().bytes();
        if tag_bytes_iter.len() > LOGGING_TAG_MAX_LEN {
            for (input, output) in tag_bytes_iter
                .take(LOGGING_TAG_MAX_LEN - 2)
                .chain(b"..\0".iter().cloned())
                .zip(array.iter_mut())
            {
                *output = input;
            }
        } else {
            for (input, output) in tag_bytes_iter
                .chain(b"\0".iter().cloned())
                .zip(array.iter_mut())
            {
                *output = input;
            }
        }
    }
}

struct PlatformLogWriter<'a> {
    priority: LogPriority,
    len: usize,
    last_newline_index: usize,
    tag: &'a CStr,
    buffer: [u8; LOGGING_MSG_MAX_LEN + 1],
}

impl<'a> PlatformLogWriter<'a> {
    pub fn new<'r>(level: LogLevel, tag: &'r CStr) -> PlatformLogWriter<'r> {
        PlatformLogWriter {
            priority: match level {
                LogLevel::Warn => LogPriority::WARN,
                LogLevel::Info => LogPriority::INFO,
                LogLevel::Debug => LogPriority::DEBUG,
                LogLevel::Error => LogPriority::ERROR,
                LogLevel::Trace => LogPriority::VERBOSE,
            },
            len: 0,
            last_newline_index: 0,
            tag: tag,
            buffer: unsafe { mem::uninitialized() },
        }
    }

    /// Flush some bytes to android logger.
    ///
    /// If there is a newline, flush up to it.
    /// If ther was no newline, flush all.
    ///
    /// Not guaranteed to flush everything.
    fn temporal_flush(&mut self) {
        let total_len = self.len;

        if total_len == 0 {
            return;
        }

        if self.last_newline_index > 0 {
            let copy_from_index = self.last_newline_index;
            let remaining_chunk_len = total_len - copy_from_index;

            self.output_specified_len(copy_from_index);
            self.copy_bytes_to_start(copy_from_index, remaining_chunk_len);
            self.len = remaining_chunk_len;
        } else {
            self.output_specified_len(total_len);
            self.len = 0;
        }
        self.last_newline_index = 0;
    }

    /// Flush everything remaining to android logger.
    fn flush(&mut self) {
        let total_len = self.len;

        if total_len == 0 {
            return;
        }

        self.output_specified_len(total_len);
        self.len = 0;
        self.last_newline_index = 0;
    }

    /// Output buffer up until the \0 which will be placed at `len` position.
    fn output_specified_len(&mut self, len: usize) {
        let last_byte: u8 = self.buffer[len];
        self.buffer[len] = b'\0';
        let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) };
        android_log(self.priority, self.tag, msg);
        self.buffer[len] = last_byte;
    }

    /// Copy `len` bytes from `index` position to starting position.
    fn copy_bytes_to_start(&mut self, index: usize, len: usize) {
        for i in 0..len {
            *unsafe { self.buffer.get_unchecked_mut(i) } =
                *unsafe { self.buffer.get_unchecked_mut(i + index) };
        }
    }
}

impl<'a> fmt::Write for PlatformLogWriter<'a> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let mut incomming_bytes = s.as_bytes();

        while incomming_bytes.len() > 0 {
            let len = self.len;

            // write everything possible to buffer and mark last \n
            let new_len = len + incomming_bytes.len();
            let last_newline = self.buffer[len..LOGGING_MSG_MAX_LEN].iter_mut()
                .zip(incomming_bytes)
                .enumerate()
                .fold(None, |acc, (i, (output, input))| {
                    *output = *input;
                    if *input == b'\n' { Some(i) } else { acc }
                });

            // update last \n index
            if let Some(newline) = last_newline {
                self.last_newline_index = len + newline;
            }

            // calculate how many bytes were written
            let written_len = if new_len <= LOGGING_MSG_MAX_LEN {
                // if the len was not exceeded
                self.len = new_len;
                new_len - len // written len
            } else {
                // if new length was exceeded
                self.len = LOGGING_MSG_MAX_LEN;
                self.temporal_flush();

                LOGGING_MSG_MAX_LEN - len // written len
            };

            incomming_bytes = &incomming_bytes[written_len..];
        }

        Ok(())
    }
}

/// Initializes the global logger with an android logger.
///
/// This can be called many times, but will only initialize logging once,
/// and will not replace any other previously initialized logger.
///
/// It is ok to call this at the activity creation, and it will be
/// repeatedly called on every lifecycle restart (i.e. screen rotation).
pub fn init_once(log_level: LogLevel) {
    match log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        return Box::new(PlatformLogger);
    }) {
        Err(e) => debug!("{}", e),
        _ => (),
    }
}
<|endoftext|>


<commit_before>mod error;
pub use self::error::Error;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Clone, Copy)]
pub struct ViewHandle(u64);

#[derive(Default, Clone)]
pub struct Rect {
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
}

impl Rect {
    pub fn new(x: f32, y: f32, width: f32, height: f32) -> Rect {
        Rect {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

#[derive(Clone)]
pub struct View {
    pub handle: ViewHandle,
    pub rect: Rect
}

impl View {
    fn new(view_handle: ViewHandle) -> View {
        View {
            handle: view_handle,
            rect: Rect::default(),
        }
    }
}

pub enum Direction {
    Vertical,
    Horizontal,
    Full,
}

#[derive(Clone)]
pub struct Container {
    pub views: Vec<View>,
}

pub struct Split {
    /// left/top slipit
    pub left: Option<Box<Split>>,
    /// right/bottom split
    pub right: Option<Box<Split>>,
    /// left/top views
    pub left_views: Container,
    /// right/top views
    pub right_views: Container,
    /// ratioage value of how much of each side that is visible. 1.0 = right/bottom fully visible
    pub ratio: f32,
    /// Direction of the split
    pub direction: Direction,
}

impl Split {
    pub fn new(direction: Direction) -> Split {
        Split {
            left: None,
            right: None,
            left_views: Container { views: Vec::new() },
            right_views: Container { views: Vec::new() },
            ratio: 0.0,
            direction: direction,
        }
    }

    pub fn no_split(&mut self, view_handle: ViewHandle) -> bool {
        if self.left_views.views.len() == 0 {
            self.left_views.views.push(View::new(view_handle));
            self.ratio = 0.5;
            return true;
        }

        if self.right_views.views.len() == 0 {
            self.right_views.views.push(View::new(view_handle));
            self.ratio = 0.5;
            return true;
        }

        false
    }

    pub fn split_left(&mut self, view_handle: ViewHandle, direction: Direction) {
        if Self::no_split(self, view_handle) {
            return;
        } else {
            let mut split = Box::new(Split::new(direction));
            split.right_views = self.left_views.clone();
            split.left_views.views.push(View::new(view_handle));
            self.left = Some(split);
            self.right_views.views.clear();
        }

        /*
        // this case only happens when a view happen to be fullscreen
        if self.left_top.len() == 1 && self.right_bottom.len() == 0 {
            self.direction = direction;
            self.ratio = 0.5;
            self.right_bottom.push(View::new(view_handle));
        } else {

        }
        */
    }

    pub fn split_right(&mut self, view_handle: ViewHandle, direction: Direction) {
        if Self::no_split(self, view_handle) {
            return;
        } else {
            let mut split = Box::new(Split::new(direction));
            split.left_views = self.right_views.clone();
            split.right_views.views.push(View::new(view_handle));
            self.right = Some(split);
            self.left_views.views.clear();
        }
    }
}

pub struct Workspace {
    pub split: Option<Box<Split>>,
    pub rect: Rect,
    /// border size of the windows (in pixels)
    pub window_border: f32,
}

impl Workspace {
    /// Construct a new workspace. The rect has to be y >= 0, x >= 0, width > 0 and height > 0
    pub fn new(rect: Rect) -> Result<Workspace> {
        if rect.x < 0.0 {
            return Err(Error::IllegalSize("x has to be non-negative".to_owned()));
        }

        if rect.y < 0.0 {
            return Err(Error::IllegalSize("y has to be non-negative".to_owned()));
        }

        if rect.width <= 0.0 {
            return Err(Error::IllegalSize("width has to be larger than 0.0".to_owned()));
        }

        if rect.height <= 0.0 {
            return Err(Error::IllegalSize("height has to be larger than 0.0".to_owned()));
        }

        Ok(Workspace {
            split: None,
            rect: rect,
            window_border: 4.0,
        })
    }

    /// This code gets called when the top split is None. This mean that the view will be
    /// set to fullscreen as there are no other splits to be done
    fn split_new(&mut self, view_handle: ViewHandle) {
        let mut split = Box::new(Split::new(Direction::Full));
        split.ratio = 1.0;
        split.left_views.views.push(View::new(view_handle));
        self.split = Some(split);
    }

    pub fn split_top(&mut self, view_handle: ViewHandle, direction: Direction) {
        if let Some(ref mut split) = self.split {
            split.split_left(view_handle, direction);
        } else {
            Self::split_new(self, view_handle);
        }
    }

    pub fn calc_horizontal_sizing(rect: Rect, ratio: f32) -> (Rect, Rect) {
        let h = rect.height * ratio;

        let rect_top = Rect {
            x: rect.x,
            y: rect.y,
            width: rect.width,
            height: h,
        };

        let rect_bottom = Rect {
            x: rect.x,
            y: rect.y + h,
            width: rect.width,
            height: rect.height - h,
        };

        (rect_top, rect_bottom)
    }

    pub fn calc_vertical_sizing(rect: Rect, ratio: f32) -> (Rect, Rect) {
        let w = rect.width * ratio;

        let rect_left = Rect {
            x: rect.x,
            y: rect.y,
            width: w,
            height: rect.height,
        };

        let rect_right = Rect {
            x: rect.x + w,
            y: rect.y,
            width: rect.width - w,
            height: rect.height,
        };

        (rect_left, rect_right)
    }

    fn recursive_update(&mut self, _rect: Rect, _level: usize) {
        // update the size on this level

        /*
        match self.direction {
            Direction::Vertical => {

            }

            Direction::Horizontal => {

            }
        }
        */
    }

    pub fn update(&mut self) {
        let rect = self.rect.clone();
        Self::recursive_update(self, rect, 0);
    }
}

#[cfg(test)]
mod test {
    use {Workspace, Rect, ViewHandle, Direction};

    fn check_range(inv: f32, value: f32, delta: f32) -> bool {
        (inv - value).abs() < delta
    }

    #[test]
    fn test_validate_x_less_than_zero() {
        assert_eq!(Workspace::new(Rect::new(-0.1, 0.0, 1.0, 1.0)).is_err(), true);
    }

    #[test]
    fn test_validate_y_less_than_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, -0.1, 1.0, 1.0)).is_err(), true);
    }

    #[test]
    fn test_validate_width_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, 0.0, 1.0)).is_err(), true);
    }

    #[test]
    fn test_validate_height_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, 1.0, 0.0)).is_err(), true);
    }

    #[test]
    fn test_validate_width_less_than_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, -1.0, 0.0)).is_err(), true);
    }

    #[test]
    fn test_validate_height_less_than_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, 0.0, -1.0)).is_err(), true);
    }

    #[test]
    fn test_validate_workspace_ok() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, 1024.0, 1024.0)).is_ok(), true);
    }

    #[test]
    fn test_split_top() {
        let mut ws = Workspace::new(Rect::new(0.0, 0.0, 1024.0, 1024.0)).unwrap();
        ws.split_top(ViewHandle(1), Direction::Vertical);

        assert_eq!(ws.split.is_some(), true);
        let split = ws.split.unwrap();

        assert_eq!(split.left_views.views.len(), 1);
    }

    #[test]
    fn test_split_top_2() {
        let mut ws = Workspace::new(Rect::new(0.0, 0.0, 1024.0, 1024.0)).unwrap();
        ws.split_top(ViewHandle(1), Direction::Vertical);
        ws.split_top(ViewHandle(2), Direction::Vertical);

        assert_eq!(ws.split.is_some(), true);
        let split = ws.split.unwrap();

        assert_eq!(split.right_views.views.len(), 1);
        assert_eq!(split.left_views.views.len(), 1);
        assert_eq!(check_range(split.ratio, 0.5, 0.01), true);
    }

    #[test]
    fn test_calc_rect_horz_half() {
        let rects = Workspace::calc_horizontal_sizing(Rect::new(0.0, 0.0, 1024.0, 1024.0), 0.5);

        assert_eq!(check_range(rects.0.x, 0.0, 0.001), true);
        assert_eq!(check_range(rects.0.y, 0.0, 0.001), true);
        assert_eq!(check_range(rects.0.width, 1024.0, 0.001), true);
        assert_eq!(check_range(rects.0.height, 512.0, 0.001), true);

        assert_eq!(check_range(rects.1.x, 0.0, 0.001), true);
        assert_eq!(check_range(rects.1.y, 512.0, 0.001), true);
        assert_eq!(check_range(rects.1.width, 1024.0, 0.001), true);
        assert_eq!(check_range(rects.1.height, 512.0, 0.001), true);
    }

    #[test]
    fn test_calc_rect_horz_25_per() {
        let rects = Workspace::calc_horizontal_sizing(Rect::new(0.0, 0.0, 1024.0, 1024.0), 0.25);

        assert_eq!(check_range(rects.0.x, 0.0, 0.001), true);
        assert_eq!(check_range(rects.0.y, 0.0, 0.001), true);
        assert_eq!(check_range(rects.0.width, 1024.0, 0.001), true);
        assert_eq!(check_range(rects.0.height, 256.0, 0.001), true);

        assert_eq!(check_range(rects.1.x, 0.0, 0.001), true);
        assert_eq!(check_range(rects.1.y, 256.0, 0.001), true);
        assert_eq!(check_range(rects.1.width, 1024.0, 0.001), true);
        assert_eq!(check_range(rects.1.height, 768.0, 0.001), true);
    }

    #[test]
    fn test_calc_rect_horz_25_per_2() {
        let rects = Workspace::calc_horizontal_sizing(Rect::new(16.0, 32.0, 512.0, 1024.0), 0.25);

        assert_eq!(check_range(rects.0.x, 16.0, 0.001), true);
        assert_eq!(check_range(rects.0.y, 32.0, 0.001), true);
        assert_eq!(check_range(rects.0.width, 512.0, 0.001), true);
        assert_eq!(check_range(rects.0.height, 256.0, 0.001), true);

        assert_eq!(check_range(rects.1.x, 32.0, 0.001), true);
        assert_eq!(check_range(rects.1.y, 288.0, 0.001), true);
        assert_eq!(check_range(rects.1.width, 512.0, 0.001), true);
        assert_eq!(check_range(rects.1.height, 768.0, 0.001), true);
    }
}
<commit_msg>Fixed broken test<commit_after>mod error;
pub use self::error::Error;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Clone, Copy)]
pub struct ViewHandle(u64);

#[derive(Default, Clone)]
pub struct Rect {
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
}

impl Rect {
    pub fn new(x: f32, y: f32, width: f32, height: f32) -> Rect {
        Rect {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

#[derive(Clone)]
pub struct View {
    pub handle: ViewHandle,
    pub rect: Rect
}

impl View {
    fn new(view_handle: ViewHandle) -> View {
        View {
            handle: view_handle,
            rect: Rect::default(),
        }
    }
}

pub enum Direction {
    Vertical,
    Horizontal,
    Full,
}

#[derive(Clone)]
pub struct Container {
    pub views: Vec<View>,
}

pub struct Split {
    /// left/top slipit
    pub left: Option<Box<Split>>,
    /// right/bottom split
    pub right: Option<Box<Split>>,
    /// left/top views
    pub left_views: Container,
    /// right/top views
    pub right_views: Container,
    /// ratioage value of how much of each side that is visible. 1.0 = right/bottom fully visible
    pub ratio: f32,
    /// Direction of the split
    pub direction: Direction,
}

impl Split {
    pub fn new(direction: Direction) -> Split {
        Split {
            left: None,
            right: None,
            left_views: Container { views: Vec::new() },
            right_views: Container { views: Vec::new() },
            ratio: 0.0,
            direction: direction,
        }
    }

    pub fn no_split(&mut self, view_handle: ViewHandle) -> bool {
        if self.left_views.views.len() == 0 {
            self.left_views.views.push(View::new(view_handle));
            self.ratio = 0.5;
            return true;
        }

        if self.right_views.views.len() == 0 {
            self.right_views.views.push(View::new(view_handle));
            self.ratio = 0.5;
            return true;
        }

        false
    }

    pub fn split_left(&mut self, view_handle: ViewHandle, direction: Direction) {
        if Self::no_split(self, view_handle) {
            return;
        } else {
            let mut split = Box::new(Split::new(direction));
            split.right_views = self.left_views.clone();
            split.left_views.views.push(View::new(view_handle));
            self.left = Some(split);
            self.right_views.views.clear();
        }

        /*
        // this case only happens when a view happen to be fullscreen
        if self.left_top.len() == 1 && self.right_bottom.len() == 0 {
            self.direction = direction;
            self.ratio = 0.5;
            self.right_bottom.push(View::new(view_handle));
        } else {

        }
        */
    }

    pub fn split_right(&mut self, view_handle: ViewHandle, direction: Direction) {
        if Self::no_split(self, view_handle) {
            return;
        } else {
            let mut split = Box::new(Split::new(direction));
            split.left_views = self.right_views.clone();
            split.right_views.views.push(View::new(view_handle));
            self.right = Some(split);
            self.left_views.views.clear();
        }
    }
}

pub struct Workspace {
    pub split: Option<Box<Split>>,
    pub rect: Rect,
    /// border size of the windows (in pixels)
    pub window_border: f32,
}

impl Workspace {
    /// Construct a new workspace. The rect has to be y >= 0, x >= 0, width > 0 and height > 0
    pub fn new(rect: Rect) -> Result<Workspace> {
        if rect.x < 0.0 {
            return Err(Error::IllegalSize("x has to be non-negative".to_owned()));
        }

        if rect.y < 0.0 {
            return Err(Error::IllegalSize("y has to be non-negative".to_owned()));
        }

        if rect.width <= 0.0 {
            return Err(Error::IllegalSize("width has to be larger than 0.0".to_owned()));
        }

        if rect.height <= 0.0 {
            return Err(Error::IllegalSize("height has to be larger than 0.0".to_owned()));
        }

        Ok(Workspace {
            split: None,
            rect: rect,
            window_border: 4.0,
        })
    }

    /// This code gets called when the top split is None. This mean that the view will be
    /// set to fullscreen as there are no other splits to be done
    fn split_new(&mut self, view_handle: ViewHandle) {
        let mut split = Box::new(Split::new(Direction::Full));
        split.ratio = 1.0;
        split.left_views.views.push(View::new(view_handle));
        self.split = Some(split);
    }

    pub fn split_top(&mut self, view_handle: ViewHandle, direction: Direction) {
        if let Some(ref mut split) = self.split {
            split.split_left(view_handle, direction);
        } else {
            Self::split_new(self, view_handle);
        }
    }

    pub fn calc_horizontal_sizing(rect: Rect, ratio: f32) -> (Rect, Rect) {
        let h = rect.height * ratio;

        let rect_top = Rect {
            x: rect.x,
            y: rect.y,
            width: rect.width,
            height: h,
        };

        let rect_bottom = Rect {
            x: rect.x,
            y: rect.y + h,
            width: rect.width,
            height: rect.height - h,
        };

        (rect_top, rect_bottom)
    }

    pub fn calc_vertical_sizing(rect: Rect, ratio: f32) -> (Rect, Rect) {
        let w = rect.width * ratio;

        let rect_left = Rect {
            x: rect.x,
            y: rect.y,
            width: w,
            height: rect.height,
        };

        let rect_right = Rect {
            x: rect.x + w,
            y: rect.y,
            width: rect.width - w,
            height: rect.height,
        };

        (rect_left, rect_right)
    }

    fn recursive_update(&mut self, _rect: Rect, _level: usize) {
        // update the size on this level

        /*
        match self.direction {
            Direction::Vertical => {

            }

            Direction::Horizontal => {

            }
        }
        */
    }

    pub fn update(&mut self) {
        let rect = self.rect.clone();
        Self::recursive_update(self, rect, 0);
    }
}

#[cfg(test)]
mod test {
    use {Workspace, Rect, ViewHandle, Direction};

    fn check_range(inv: f32, value: f32, delta: f32) -> bool {
        (inv - value).abs() < delta
    }

    #[test]
    fn test_validate_x_less_than_zero() {
        assert_eq!(Workspace::new(Rect::new(-0.1, 0.0, 1.0, 1.0)).is_err(), true);
    }

    #[test]
    fn test_validate_y_less_than_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, -0.1, 1.0, 1.0)).is_err(), true);
    }

    #[test]
    fn test_validate_width_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, 0.0, 1.0)).is_err(), true);
    }

    #[test]
    fn test_validate_height_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, 1.0, 0.0)).is_err(), true);
    }

    #[test]
    fn test_validate_width_less_than_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, -1.0, 0.0)).is_err(), true);
    }

    #[test]
    fn test_validate_height_less_than_zero() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, 0.0, -1.0)).is_err(), true);
    }

    #[test]
    fn test_validate_workspace_ok() {
        assert_eq!(Workspace::new(Rect::new(0.0, 0.0, 1024.0, 1024.0)).is_ok(), true);
    }

    #[test]
    fn test_split_top() {
        let mut ws = Workspace::new(Rect::new(0.0, 0.0, 1024.0, 1024.0)).unwrap();
        ws.split_top(ViewHandle(1), Direction::Vertical);

        assert_eq!(ws.split.is_some(), true);
        let split = ws.split.unwrap();

        assert_eq!(split.left_views.views.len(), 1);
    }

    #[test]
    fn test_split_top_2() {
        let mut ws = Workspace::new(Rect::new(0.0, 0.0, 1024.0, 1024.0)).unwrap();
        ws.split_top(ViewHandle(1), Direction::Vertical);
        ws.split_top(ViewHandle(2), Direction::Vertical);

        assert_eq!(ws.split.is_some(), true);
        let split = ws.split.unwrap();

        assert_eq!(split.right_views.views.len(), 1);
        assert_eq!(split.left_views.views.len(), 1);
        assert_eq!(check_range(split.ratio, 0.5, 0.01), true);
    }

    #[test]
    fn test_calc_rect_horz_half() {
        let rects = Workspace::calc_horizontal_sizing(Rect::new(0.0, 0.0, 1024.0, 1024.0), 0.5);

        assert_eq!(check_range(rects.0.x, 0.0, 0.001), true);
        assert_eq!(check_range(rects.0.y, 0.0, 0.001), true);
        assert_eq!(check_range(rects.0.width, 1024.0, 0.001), true);
        assert_eq!(check_range(rects.0.height, 512.0, 0.001), true);

        assert_eq!(check_range(rects.1.x, 0.0, 0.001), true);
        assert_eq!(check_range(rects.1.y, 512.0, 0.001), true);
        assert_eq!(check_range(rects.1.width, 1024.0, 0.001), true);
        assert_eq!(check_range(rects.1.height, 512.0, 0.001), true);
    }

    #[test]
    fn test_calc_rect_horz_25_per() {
        let rects = Workspace::calc_horizontal_sizing(Rect::new(0.0, 0.0, 1024.0, 1024.0), 0.25);

        assert_eq!(check_range(rects.0.x, 0.0, 0.001), true);
        assert_eq!(check_range(rects.0.y, 0.0, 0.001), true);
        assert_eq!(check_range(rects.0.width, 1024.0, 0.001), true);
        assert_eq!(check_range(rects.0.height, 256.0, 0.001), true);

        assert_eq!(check_range(rects.1.x, 0.0, 0.001), true);
        assert_eq!(check_range(rects.1.y, 256.0, 0.001), true);
        assert_eq!(check_range(rects.1.width, 1024.0, 0.001), true);
        assert_eq!(check_range(rects.1.height, 768.0, 0.001), true);
    }

    #[test]
    fn test_calc_rect_horz_25_per_2() {
        let rects = Workspace::calc_horizontal_sizing(Rect::new(16.0, 32.0, 512.0, 1024.0), 0.25);

        assert_eq!(check_range(rects.0.x, 16.0, 0.001), true);
        assert_eq!(check_range(rects.0.y, 32.0, 0.001), true);
        assert_eq!(check_range(rects.0.width, 512.0, 0.001), true);
        assert_eq!(check_range(rects.0.height, 256.0, 0.001), true);

        assert_eq!(check_range(rects.1.x, 16.0, 0.001), true);
        assert_eq!(check_range(rects.1.y, 288.0, 0.001), true);
        assert_eq!(check_range(rects.1.width, 512.0, 0.001), true);
        assert_eq!(check_range(rects.1.height, 768.0, 0.001), true);
    }
}
<|endoftext|>


<commit_before>//! TypeDef is used to identify and compare types, as well as print their names.
//!
//! If you do not need readable type name, you should use `TypeId`. This
//! wrapper re-implements `TypeId`.
//!
//! Since Rust 1.0, this library can only work on nightly Rust. To activate the nice names instead
//! of gobbledygook, include this library with `features = ["nightly"]` configuration parameter.
//! On stable rust, it falls back to gobbledygook (type identifier) instead of a nice name.
//!
//! To get a name of a type:
//!
//! ``` ignore
//! use typedef::{ TypeDef };
//!
//! assert_eq!(TypeDef::name_of::<i64>(), "i64");
//! ```
//!
//! Type can also serve as type identifier and name container:
//!
//! ``` ignore
//! use typedef::{ TypeDef };
//!
//! let typedef = TypeDef::of::<i64>();
//!
//! assert!(typedef.is::<i64>());
//! assert_eq!(typedef.get_str(), "i64");
//! ```
//!
//! More common usage would be in a generic method:
//!
//! ``` ignore
//! use std::any::Any;
//! use std::fmt;
//! use typedef::TypeDef;
//!
//! fn foo<T: Any + fmt::Debug>(value: T) -> String {
//!     format!(
//!         "the value of {} type is {:?}",
//!         TypeDef::of::<T>(),
//!         value
//!     )
//! }
//!
//! fn main() {
//!     assert_eq!(foo(15), "the value of i32 type is 15");
//! }
//! ```

#![cfg_attr(nightly, feature(core_intrinsics))]

use std::any::{Any, TypeId};
use std::fmt;
use std::borrow::Cow;

/// Create a TypeDef structure to identify a type and to print its name.
///
/// ``` ignore
/// use typedef::{ TypeDef };
///
/// let typedef = TypeDef::of::<i64>();
///
/// assert!(typedef.is::<i64>());
/// assert!(typedef.get_str() == "i64");
/// ```
#[derive(Debug, Clone, Copy)]
#[cfg(feature = "nightly")]
pub struct TypeDef {
    id: TypeId,
    name: &'static str,
}

#[derive(Debug, Clone, Copy)]
#[cfg(not(feature = "nightly"))]
pub struct TypeDef {
    id: TypeId,
}

impl TypeDef {
    /// Create a TypeDef structure from a type parameter.
    ///
    /// ```
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    /// ```
    #[cfg(feature = "nightly")]
    pub fn of<T: Any>() -> TypeDef {
        use std::intrinsics::type_name;
        TypeDef {
            id: TypeId::of::<T>(),
            name: unsafe { type_name::<T>() },
        }
    }

    /// Create a TypeDef structure from a type parameter.
    ///
    /// ```
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    /// ```
    #[cfg(not(feature = "nightly"))]
    pub fn of<T: Any>() -> TypeDef {
        TypeDef {
            id: TypeId::of::<T>(),
        }
    }

    /// Get `TypeId` for specified type directly.
    ///
    /// ```
    /// use std::any::{ TypeId };
    /// use typedef::{ TypeDef };
    ///
    /// assert!(TypeDef::id_of::<i64>() == TypeId::of::<i64>());
    /// ```
    pub fn id_of<T: Any>() -> TypeId {
        TypeId::of::<T>()
    }

    /// Get type name for specified type directly.
    ///
    /// This only works if this crate is compiled with `features = ["nightly"]`
    ///
    /// ``` ignore
    /// use typedef::{ TypeDef };
    ///
    /// assert_eq!(TypeDef::name_of::<i64>(), "i64");
    /// ```
    #[cfg(feature = "nightly")]
    pub fn name_of<T: Any>() -> Cow<'static, str> {
        use std::intrinsics::type_name;
        Cow::Borrowed(unsafe { type_name::<T>() })
    }

    /// Get type name for specified type directly.
    ///
    /// This only works if this crate is compiled with `features = ["nightly"]`
    ///
    /// ``` ignore
    /// use typedef::{ TypeDef };
    ///
    /// assert_eq!(TypeDef::name_of::<i64>(), "i64");
    /// ```
    #[cfg(not(feature = "nightly"))]
    pub fn name_of<T: Any>() -> Cow<'static, str> {
        Cow::Owned(format!("{}", unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&TypeId::of::<T>()) }))
    }

    /// Check if typedef instance matches type.
    ///
    /// ```
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    ///
    /// assert!(typedef.is::<i64>());
    /// ```
    pub fn is<T: Any>(&self) -> bool {
        self.id == TypeId::of::<T>()
    }

    /// Get the static `&str` for typedef instance.
    ///
    /// ``` ignore
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    ///
    /// assert!(typedef.get_str() == "i64");
    /// ```
    #[cfg(feature = "nightly")]
    pub fn get_str(&self) -> Cow<'static, str> {
        Cow::Borrowed(self.name)
    }

    /// Get the static `&str` for typedef instance.
    ///
    /// This only works if this crate is compiled with `features = ["nightly"]`
    ///
    /// ``` ignore
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    ///
    /// assert!(typedef.get_str() == "i64");
    /// ```
    #[cfg(not(feature = "nightly"))]
    pub fn get_str(&self) -> Cow<'static, str> {
        Cow::Owned(format!("{}", unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&self.id) }))
    }
}

impl PartialEq for TypeDef {
    fn eq(&self, other: &TypeDef) -> bool {
        self.id == other.id
    }
}

impl fmt::Display for TypeDef {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", &self.get_str())
    }
}

#[cfg(test)]
mod test {
    use super::TypeDef;
    use std::any::TypeId;

    #[test]
    fn should_match_type() {
        assert!(TypeDef::of::<i16>().is::<i16>());
    }

    #[test]
    fn should_not_match_incorrect_type() {
        assert!(!TypeDef::of::<i16>().is::<i32>());
    }

    #[test]
    #[cfg(not(feature = "nightly"))]
    fn should_return_type_name() {
        assert_eq!(TypeDef::of::<i16>().get_str().into_owned(), format!("{:?}", type_id_fallback::<i16>()));
        assert_eq!(TypeDef::of::<i64>().get_str().into_owned(), format!("{:?}", type_id_fallback::<i64>()));
    }

    #[test]
    #[cfg(feature = "nightly")]
    fn should_return_type_name() {
        assert_eq!(&TypeDef::of::<i16>().get_str(), "i16");
        assert_eq!(&TypeDef::of::<i64>().get_str(), "i64");
    }

    #[test]
    fn should_be_equal_to_another_typedef_of_the_same_type() {
        assert_eq!(TypeDef::of::<i16>(), TypeDef::of::<i16>());
    }

    #[test]
    fn should_not_be_equal_to_another_typedef_of_different_type() {
        assert!(TypeDef::of::<i16>() != TypeDef::of::<i32>());
    }

    #[cfg(not(feature = "nightly"))]
    fn type_id_fallback<T: 'static>() -> u64 {
        unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&TypeId::of::<T>()) }
    }
}
<commit_msg>Fix intrinsics feature configuration.<commit_after>//! TypeDef is used to identify and compare types, as well as print their names.
//!
//! If you do not need readable type name, you should use `TypeId`. This
//! wrapper re-implements `TypeId`.
//!
//! Since Rust 1.0, this library can only work on nightly Rust. To activate the nice names instead
//! of gobbledygook, include this library with `features = ["nightly"]` configuration parameter.
//! On stable rust, it falls back to gobbledygook (type identifier) instead of a nice name.
//!
//! To get a name of a type:
//!
//! ``` ignore
//! use typedef::{ TypeDef };
//!
//! assert_eq!(TypeDef::name_of::<i64>(), "i64");
//! ```
//!
//! Type can also serve as type identifier and name container:
//!
//! ``` ignore
//! use typedef::{ TypeDef };
//!
//! let typedef = TypeDef::of::<i64>();
//!
//! assert!(typedef.is::<i64>());
//! assert_eq!(typedef.get_str(), "i64");
//! ```
//!
//! More common usage would be in a generic method:
//!
//! ``` ignore
//! use std::any::Any;
//! use std::fmt;
//! use typedef::TypeDef;
//!
//! fn foo<T: Any + fmt::Debug>(value: T) -> String {
//!     format!(
//!         "the value of {} type is {:?}",
//!         TypeDef::of::<T>(),
//!         value
//!     )
//! }
//!
//! fn main() {
//!     assert_eq!(foo(15), "the value of i32 type is 15");
//! }
//! ```

#![cfg_attr(feature = "nightly", feature(core_intrinsics))]

use std::any::{Any, TypeId};
use std::fmt;
use std::borrow::Cow;

/// Create a TypeDef structure to identify a type and to print its name.
///
/// ``` ignore
/// use typedef::{ TypeDef };
///
/// let typedef = TypeDef::of::<i64>();
///
/// assert!(typedef.is::<i64>());
/// assert!(typedef.get_str() == "i64");
/// ```
#[derive(Debug, Clone, Copy)]
#[cfg(feature = "nightly")]
pub struct TypeDef {
    id: TypeId,
    name: &'static str,
}

#[derive(Debug, Clone, Copy)]
#[cfg(not(feature = "nightly"))]
pub struct TypeDef {
    id: TypeId,
}

impl TypeDef {
    /// Create a TypeDef structure from a type parameter.
    ///
    /// ```
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    /// ```
    #[cfg(feature = "nightly")]
    pub fn of<T: Any>() -> TypeDef {
        use std::intrinsics::type_name;
        TypeDef {
            id: TypeId::of::<T>(),
            name: unsafe { type_name::<T>() },
        }
    }

    /// Create a TypeDef structure from a type parameter.
    ///
    /// ```
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    /// ```
    #[cfg(not(feature = "nightly"))]
    pub fn of<T: Any>() -> TypeDef {
        TypeDef {
            id: TypeId::of::<T>(),
        }
    }

    /// Get `TypeId` for specified type directly.
    ///
    /// ```
    /// use std::any::{ TypeId };
    /// use typedef::{ TypeDef };
    ///
    /// assert!(TypeDef::id_of::<i64>() == TypeId::of::<i64>());
    /// ```
    pub fn id_of<T: Any>() -> TypeId {
        TypeId::of::<T>()
    }

    /// Get type name for specified type directly.
    ///
    /// This only works if this crate is compiled with `features = ["nightly"]`
    ///
    /// ``` ignore
    /// use typedef::{ TypeDef };
    ///
    /// assert_eq!(TypeDef::name_of::<i64>(), "i64");
    /// ```
    #[cfg(feature = "nightly")]
    pub fn name_of<T: Any>() -> Cow<'static, str> {
        use std::intrinsics::type_name;
        Cow::Borrowed(unsafe { type_name::<T>() })
    }

    /// Get type name for specified type directly.
    ///
    /// This only works if this crate is compiled with `features = ["nightly"]`
    ///
    /// ``` ignore
    /// use typedef::{ TypeDef };
    ///
    /// assert_eq!(TypeDef::name_of::<i64>(), "i64");
    /// ```
    #[cfg(not(feature = "nightly"))]
    pub fn name_of<T: Any>() -> Cow<'static, str> {
        Cow::Owned(format!("{}", unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&TypeId::of::<T>()) }))
    }

    /// Check if typedef instance matches type.
    ///
    /// ```
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    ///
    /// assert!(typedef.is::<i64>());
    /// ```
    pub fn is<T: Any>(&self) -> bool {
        self.id == TypeId::of::<T>()
    }

    /// Get the static `&str` for typedef instance.
    ///
    /// ``` ignore
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    ///
    /// assert!(typedef.get_str() == "i64");
    /// ```
    #[cfg(feature = "nightly")]
    pub fn get_str(&self) -> Cow<'static, str> {
        Cow::Borrowed(self.name)
    }

    /// Get the static `&str` for typedef instance.
    ///
    /// This only works if this crate is compiled with `features = ["nightly"]`
    ///
    /// ``` ignore
    /// use typedef::{ TypeDef };
    ///
    /// let typedef = TypeDef::of::<i64>();
    ///
    /// assert!(typedef.get_str() == "i64");
    /// ```
    #[cfg(not(feature = "nightly"))]
    pub fn get_str(&self) -> Cow<'static, str> {
        Cow::Owned(format!("{}", unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&self.id) }))
    }
}

impl PartialEq for TypeDef {
    fn eq(&self, other: &TypeDef) -> bool {
        self.id == other.id
    }
}

impl fmt::Display for TypeDef {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", &self.get_str())
    }
}

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

    #[test]
    fn should_match_type() {
        assert!(TypeDef::of::<i16>().is::<i16>());
    }

    #[test]
    fn should_not_match_incorrect_type() {
        assert!(!TypeDef::of::<i16>().is::<i32>());
    }

    #[test]
    #[cfg(not(feature = "nightly"))]
    fn should_return_type_name() {
        assert_eq!(TypeDef::of::<i16>().get_str().into_owned(), format!("{:?}", type_id_fallback::<i16>()));
        assert_eq!(TypeDef::of::<i64>().get_str().into_owned(), format!("{:?}", type_id_fallback::<i64>()));
    }

    #[test]
    #[cfg(feature = "nightly")]
    fn should_return_type_name() {
        assert_eq!(&TypeDef::of::<i16>().get_str(), "i16");
        assert_eq!(&TypeDef::of::<i64>().get_str(), "i64");
    }

    #[test]
    fn should_be_equal_to_another_typedef_of_the_same_type() {
        assert_eq!(TypeDef::of::<i16>(), TypeDef::of::<i16>());
    }

    #[test]
    fn should_not_be_equal_to_another_typedef_of_different_type() {
        assert!(TypeDef::of::<i16>() != TypeDef::of::<i32>());
    }

    #[cfg(not(feature = "nightly"))]
    fn type_id_fallback<T: 'static>() -> u64 {
        use std::any::TypeId;
        unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&TypeId::of::<T>()) }
    }
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://pwoolcoc.github.io/collection_macros/")]
#![cfg_attr(feature = "nightly", feature(collections))]

/// Create a `HashMap` containing the arguments
///
/// `hashmap!` allows `HashMap`s to be constructed using minimal syntax:
///
/// ```
/// # #[cfg_attr(feature = "nightly", feature(collections))]
/// # #[macro_use] extern crate collection_macros;
/// use std::collections::HashMap;
/// # fn main() {
/// let m = hashmap!{
///     "a" => "foo",
///     "b" => "bar",
///     "c" => "baz",
/// };
/// assert_eq!(m.get("a"), Some(&"foo"));
/// assert_eq!(m.get("b"), Some(&"bar"));
/// assert_eq!(m.get("c"), Some(&"baz"));
/// # }
/// ```
///
#[macro_export]
macro_rules! hashmap {
    ( $($x:expr => $y:expr),* ) => ({
        let mut temp_map = HashMap::new();
        $(
            temp_map.insert($x, $y);
        )*
        temp_map
    });
    ( $($x:expr => $y:expr,)* ) => (
        hashmap!{$($x => $y),*}
    );
}

/// Create a `BTreeMap` containing the arguments
///
/// `btreemap!` allows `BTreeMap`s to be constructed using minimal syntax:
///
/// - Create a `BTreeMap` using a list of `key => value` pairs:
///
/// ```
/// # #[macro_use] extern crate collection_macros;
/// use std::collections::BTreeMap;
/// # fn main() {
/// let m = btreemap!{
///     1 => "foo",
///     2 => "bar",
///     3 => "baz",
///     5 => "quux",
/// };
/// assert_eq!(m.get(&1), Some(&"foo"));
/// assert_eq!(m.get(&2), Some(&"bar"));
/// assert_eq!(m.get(&3), Some(&"baz"));
/// assert_eq!(m.get(&5), Some(&"quux"));
/// # }
/// ```
///
#[cfg_attr(feature = "nightly", doc = r#"If you are using nightly, there is a second form to this macro:"#)]
#[cfg_attr(feature = "nightly", doc = r#""#)]
#[cfg_attr(feature = "nightly", doc = r#"- Create a `BTreeMap` using the `BTreeMap::with_b` constructor, and a list"#)]
#[cfg_attr(feature = "nightly", doc = r#"  of `key => value` pairs. This is currently only available on nightly"#)]
#[cfg_attr(feature = "nightly", doc = r#""#)]
#[cfg_attr(feature = "nightly", doc = r#"```"#)]
#[cfg_attr(feature = "nightly", doc = r#"# #![feature(collections)]"#)]
#[cfg_attr(feature = "nightly", doc = r#"# #[macro_use] extern crate collection_macros;"#)]
#[cfg_attr(feature = "nightly", doc = r#"use std::collections::BTreeMap;"#)]
#[cfg_attr(feature = "nightly", doc = r#"# fn main() {"#)]
#[cfg_attr(feature = "nightly", doc = r#"let m = btreemap!{"#)]
#[cfg_attr(feature = "nightly", doc = r#"    6;"#)]
#[cfg_attr(feature = "nightly", doc = r#"    1 => "foo","#)]
#[cfg_attr(feature = "nightly", doc = r#"    2 => "bar","#)]
#[cfg_attr(feature = "nightly", doc = r#"    3 => "baz","#)]
#[cfg_attr(feature = "nightly", doc = r#"    5 => "quux","#)]
#[cfg_attr(feature = "nightly", doc = r#"};"#)]
#[cfg_attr(feature = "nightly", doc = r#"assert_eq!(m.get(&1), Some(&"foo"));"#)]
#[cfg_attr(feature = "nightly", doc = r#"assert_eq!(m.get(&2), Some(&"bar"));"#)]
#[cfg_attr(feature = "nightly", doc = r#"assert_eq!(m.get(&3), Some(&"baz"));"#)]
#[cfg_attr(feature = "nightly", doc = r#"assert_eq!(m.get(&5), Some(&"quux"));"#)]
#[cfg_attr(feature = "nightly", doc = r#"# }"#)]
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(feature = "nightly", doc = "")]
#[macro_export]
macro_rules! btreemap {
    ( $b:expr; $($x:expr => $y:expr),* ) => ({
        let mut temp_map = BTreeMap::with_b($b);
        $(
            temp_map.insert($x, $y);
        )*
        temp_map
    });
    ( $($x:expr => $y:expr),* ) => ({
        let mut temp_map = BTreeMap::new();
        $(
            temp_map.insert($x, $y);
        )*
        temp_map
    });
    ( $b:expr; $($x:expr => $y:expr,)* ) => (
        btreemap!{$b; $($x => $y),*}
    );
    ( $($x:expr => $y:expr,)* ) => (
        btreemap!{$($x => $y),*}
    );
}

#[cfg(test)] mod tests {
    use std::collections::{BTreeMap, HashMap};

    #[cfg(feature = "nightly")]
    #[test]
    fn test_btreemap_with_b() {
        let bmap = btreemap! {
            6;
            1 => "hello",
            3 => "blah",
        };

        let mut should_be = BTreeMap::new();
        should_be.insert(1, "hello");
        should_be.insert(3, "blah");

        assert_eq!(bmap, should_be);
    }

    #[test]
    fn test_btreemap() {
        let map = btreemap! {
            1 => "hello",
            3 => "blah",
        };

        let mut should_be = BTreeMap::new();
        should_be.insert(1, "hello");
        should_be.insert(3, "blah");

        assert_eq!(map, should_be);

    }

    #[test]
    fn test_hashmap() {
        let map = hashmap!{
            "one" => "two",
            "three" => "four",
        };

        let mut should_be = HashMap::new();
        should_be.insert("one", "two");
        should_be.insert("three", "four");

        assert_eq!(map, should_be);
    }
}

<commit_msg>moar docs<commit_after>#![doc(html_root_url = "https://pwoolcoc.github.io/collection_macros/")]
#![cfg_attr(feature = "nightly", feature(collections))]

//! Collection Macros
//!
//! A collection of macros to construct collections with minimal syntax

/// Create a `HashMap` containing the arguments
///
/// `hashmap!` allows `HashMap`s to be constructed using minimal syntax:
///
/// ```
/// # #[cfg_attr(feature = "nightly", feature(collections))]
/// # #[macro_use] extern crate collection_macros;
/// use std::collections::HashMap;
/// # fn main() {
/// let m = hashmap!{
///     "a" => "foo",
///     "b" => "bar",
///     "c" => "baz",
/// };
/// assert_eq!(m.get("a"), Some(&"foo"));
/// assert_eq!(m.get("b"), Some(&"bar"));
/// assert_eq!(m.get("c"), Some(&"baz"));
/// # }
/// ```
///
#[macro_export]
macro_rules! hashmap {
    ( $($x:expr => $y:expr),* ) => ({
        let mut temp_map = HashMap::new();
        $(
            temp_map.insert($x, $y);
        )*
        temp_map
    });
    ( $($x:expr => $y:expr,)* ) => (
        hashmap!{$($x => $y),*}
    );
}

/// Create a `BTreeMap` containing the arguments
///
/// `btreemap!` allows `BTreeMap`s to be constructed using minimal syntax:
///
/// - Create a `BTreeMap` using a list of `key => value` pairs:
///
/// ```
/// # #[macro_use] extern crate collection_macros;
/// use std::collections::BTreeMap;
/// # fn main() {
/// let m = btreemap!{
///     1 => "foo",
///     2 => "bar",
///     3 => "baz",
///     5 => "quux",
/// };
/// assert_eq!(m.get(&1), Some(&"foo"));
/// assert_eq!(m.get(&2), Some(&"bar"));
/// assert_eq!(m.get(&3), Some(&"baz"));
/// assert_eq!(m.get(&5), Some(&"quux"));
/// # }
/// ```
///
#[cfg_attr(feature = "nightly", doc = r#"If you are using nightly, there is a second form to this macro:"#)]
#[cfg_attr(feature = "nightly", doc = r#""#)]
#[cfg_attr(feature = "nightly", doc = r#"- Create a `BTreeMap` using the `BTreeMap::with_b` constructor, and a list"#)]
#[cfg_attr(feature = "nightly", doc = r#"  of `key => value` pairs. This is currently only available on nightly"#)]
#[cfg_attr(feature = "nightly", doc = r#""#)]
#[cfg_attr(feature = "nightly", doc = r#"```"#)]
#[cfg_attr(feature = "nightly", doc = r#"# #![feature(collections)]"#)]
#[cfg_attr(feature = "nightly", doc = r#"# #[macro_use] extern crate collection_macros;"#)]
#[cfg_attr(feature = "nightly", doc = r#"use std::collections::BTreeMap;"#)]
#[cfg_attr(feature = "nightly", doc = r#"# fn main() {"#)]
#[cfg_attr(feature = "nightly", doc = r#"let m = btreemap!{"#)]
#[cfg_attr(feature = "nightly", doc = r#"    6;"#)]
#[cfg_attr(feature = "nightly", doc = r#"    1 => "foo","#)]
#[cfg_attr(feature = "nightly", doc = r#"    2 => "bar","#)]
#[cfg_attr(feature = "nightly", doc = r#"    3 => "baz","#)]
#[cfg_attr(feature = "nightly", doc = r#"    5 => "quux","#)]
#[cfg_attr(feature = "nightly", doc = r#"};"#)]
#[cfg_attr(feature = "nightly", doc = r#"assert_eq!(m.get(&1), Some(&"foo"));"#)]
#[cfg_attr(feature = "nightly", doc = r#"assert_eq!(m.get(&2), Some(&"bar"));"#)]
#[cfg_attr(feature = "nightly", doc = r#"assert_eq!(m.get(&3), Some(&"baz"));"#)]
#[cfg_attr(feature = "nightly", doc = r#"assert_eq!(m.get(&5), Some(&"quux"));"#)]
#[cfg_attr(feature = "nightly", doc = r#"# }"#)]
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(feature = "nightly", doc = "")]
#[macro_export]
macro_rules! btreemap {
    ( $b:expr; $($x:expr => $y:expr),* ) => ({
        let mut temp_map = BTreeMap::with_b($b);
        $(
            temp_map.insert($x, $y);
        )*
        temp_map
    });
    ( $($x:expr => $y:expr),* ) => ({
        let mut temp_map = BTreeMap::new();
        $(
            temp_map.insert($x, $y);
        )*
        temp_map
    });
    ( $b:expr; $($x:expr => $y:expr,)* ) => (
        btreemap!{$b; $($x => $y),*}
    );
    ( $($x:expr => $y:expr,)* ) => (
        btreemap!{$($x => $y),*}
    );
}

#[cfg(test)] mod tests {
    use std::collections::{BTreeMap, HashMap};

    #[cfg(feature = "nightly")]
    #[test]
    fn test_btreemap_with_b() {
        let bmap = btreemap! {
            6;
            1 => "hello",
            3 => "blah",
        };

        let mut should_be = BTreeMap::new();
        should_be.insert(1, "hello");
        should_be.insert(3, "blah");

        assert_eq!(bmap, should_be);
    }

    #[test]
    fn test_btreemap() {
        let map = btreemap! {
            1 => "hello",
            3 => "blah",
        };

        let mut should_be = BTreeMap::new();
        should_be.insert(1, "hello");
        should_be.insert(3, "blah");

        assert_eq!(map, should_be);

    }

    #[test]
    fn test_hashmap() {
        let map = hashmap!{
            "one" => "two",
            "three" => "four",
        };

        let mut should_be = HashMap::new();
        should_be.insert("one", "two");
        should_be.insert("three", "four");

        assert_eq!(map, should_be);
    }
}

<|endoftext|>


<commit_before>#![feature(plugin_registrar, quote, rustc_private)]

extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::registry::Registry;
use syntax::ast::{Attribute, Block, Ident, Item, Mac, MetaItem, MetaItemKind, ItemKind};
use syntax::fold::{self, Folder};
use syntax::ptr::P;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::ext::build::AstBuilder;
use syntax::ext::expand::expand_item;
use syntax::feature_gate::AttributeType;
use syntax::parse::token;
use syntax::util::small_vector::SmallVector;

pub fn insert_flame_guard(cx: &mut ExtCtxt, _span: Span, _mi: &MetaItem,
                          a: Annotatable) -> Annotatable {
    match a {
        Annotatable::Item(i) => Annotatable::Item(
            Flamer { cx: cx, ident: i.ident }.fold_item(i).expect_one("expected exactly one item")),
        Annotatable::TraitItem(i) => Annotatable::TraitItem(
            i.map(|i| Flamer { cx: cx, ident: i.ident }.fold_trait_item(i).expect_one("expected exactly one item"))),
        Annotatable::ImplItem(i) => Annotatable::ImplItem(
            i.map(|i| Flamer { cx: cx, ident: i.ident }.fold_impl_item(i).expect_one("expected exactly one item"))),
    }
}

struct Flamer<'a, 'cx: 'a> {
    ident: Ident,
    cx: &'a mut ExtCtxt<'cx>,
}

impl<'a, 'cx> Folder for Flamer<'a, 'cx> {
    fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> {
        if let ItemKind::Mac(_) = item.node {
            let expanded = expand_item(item, &mut self.cx.expander());
            expanded.into_iter()
                    .flat_map(|i| fold::noop_fold_item(i, self).into_iter())
                    .collect()
        } else {
            fold::noop_fold_item(item, self)
        }
    }

    fn fold_item_simple(&mut self, i: Item) -> Item {
        fn is_flame_annotation(attr: &Attribute) -> bool {
            if let MetaItemKind::Word(ref name) = attr.node.value.node {
                name == "flame" || name == "noflame"
            } else {
                false
            }
        }
        // don't double-flame nested annotations
        if i.attrs.iter().any(is_flame_annotation) { return i; }
        if let ItemKind::Mac(_) = i.node {
            return i;
        }else {
            self.ident = i.ident; // update in case of nested items
            fold::noop_fold_item_simple(i, self)
        }
    }

    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
        block.map(|block| {
            let name = self.cx.expr_str(DUMMY_SP, self.ident.name.as_str());
            quote_block!(self.cx, {
                let g = ::flame::start_guard($name);
                let r = $block;
                g.end();
                r
            }).unwrap()
        })
    }

    fn fold_mac(&mut self, mac: Mac) -> Mac {
        mac
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(token::intern("flame"),
        SyntaxExtension::MultiModifier(Box::new(insert_flame_guard)));
    reg.register_attribute(String::from("noflame"), AttributeType::Whitelisted);
}
<commit_msg>expand macros in expressions<commit_after>#![feature(plugin_registrar, quote, rustc_private)]

extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::registry::Registry;
use syntax::ast::{Attribute, Block, Expr, ExprKind, Ident, Item, ItemKind, Mac,
                  MetaItem, MetaItemKind};
use syntax::fold::{self, Folder};
use syntax::ptr::P;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::ext::build::AstBuilder;
use syntax::ext::expand::{expand_expr, expand_item};
use syntax::feature_gate::AttributeType;
use syntax::parse::token;
use syntax::util::small_vector::SmallVector;

pub fn insert_flame_guard(cx: &mut ExtCtxt, _span: Span, _mi: &MetaItem,
                          a: Annotatable) -> Annotatable {
    match a {
        Annotatable::Item(i) => Annotatable::Item(
            Flamer { cx: cx, ident: i.ident }.fold_item(i).expect_one("expected exactly one item")),
        Annotatable::TraitItem(i) => Annotatable::TraitItem(
            i.map(|i| Flamer { cx: cx, ident: i.ident }.fold_trait_item(i).expect_one("expected exactly one item"))),
        Annotatable::ImplItem(i) => Annotatable::ImplItem(
            i.map(|i| Flamer { cx: cx, ident: i.ident }.fold_impl_item(i).expect_one("expected exactly one item"))),
    }
}

struct Flamer<'a, 'cx: 'a> {
    ident: Ident,
    cx: &'a mut ExtCtxt<'cx>,
}

impl<'a, 'cx> Folder for Flamer<'a, 'cx> {
    fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> {
        if let ItemKind::Mac(_) = item.node {
            let expanded = expand_item(item, &mut self.cx.expander());
            expanded.into_iter()
                    .flat_map(|i| fold::noop_fold_item(i, self).into_iter())
                    .collect()
        } else {
            fold::noop_fold_item(item, self)
        }
    }

    fn fold_item_simple(&mut self, i: Item) -> Item {
        fn is_flame_annotation(attr: &Attribute) -> bool {
            if let MetaItemKind::Word(ref name) = attr.node.value.node {
                name == "flame" || name == "noflame"
            } else {
                false
            }
        }
        // don't double-flame nested annotations
        if i.attrs.iter().any(is_flame_annotation) { return i; }
        if let ItemKind::Mac(_) = i.node {
            return i;
        }else {
            self.ident = i.ident; // update in case of nested items
            fold::noop_fold_item_simple(i, self)
        }
    }

    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
        block.map(|block| {
            let name = self.cx.expr_str(DUMMY_SP, self.ident.name.as_str());
            quote_block!(self.cx, {
                let g = ::flame::start_guard($name);
                let r = $block;
                g.end();
                r
            }).unwrap()
        })
    }

    fn fold_expr(&mut self, expr: P<Expr>) -> P<Expr> {
        if let ExprKind::Mac(_) = expr.node {
            expand_expr(expr.unwrap(), &mut self.cx.expander()).map(|e|
                fold::noop_fold_expr(e, self))
        } else {
            expr
        }
    }

    fn fold_mac(&mut self, mac: Mac) -> Mac {
        mac
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(token::intern("flame"),
        SyntaxExtension::MultiModifier(Box::new(insert_flame_guard)));
    reg.register_attribute(String::from("noflame"), AttributeType::Whitelisted);
}
<|endoftext|>


<commit_before>//! Crate `retry` provides utilities for retrying operations that can fail.
//!
//! # Usage
//!
//! Retry an operation using the `retry` function. `retry` accepts an iterator over `Duration`s and
//! a closure that returns a `Result` (or `OperationResult`; see below). The iterator is used to
//! determine how long to wait after each unsuccessful try and how many times to try before giving
//! up and returning `Result::Err`. The closure determines either the final successful value, or
//! an error value, which can either be returned immediately or used to indicate that the
//! operation should be retried.
//!
//! Any type that implements `Iterator<Item = Duration>` can be used to determine retry behavior,
//! though a few useful implementations are provided in the `delay` module, including a fixed delay
//! and exponential back-off.
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_ok());
//! ```
//!
//! The `Iterator` API can be used to limit or modify the delay strategy. For example, to limit the
//! number of retries to 1:
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100).take(1), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_err());
//! ```
//!
#![cfg_attr(
    feature = "random",
    doc = r##"
To apply random jitter to any delay strategy, the `jitter` function can be used in combination
with the `Iterator` API:

```
# use retry::retry;
# use retry::delay::{Exponential, jitter};
let mut collection = vec![1, 2, 3].into_iter();

let result = retry(Exponential::from_millis(10).map(jitter).take(3), || {
    match collection.next() {
        Some(n) if n == 3 => Ok("n is 3!"),
        Some(_) => Err("n must be 3!"),
        None => Err("n was never 3!"),
    }
});

assert!(result.is_ok());
```
"##
)]
//!
//! To deal with fatal errors, return `retry::OperationResult`, which is like std's `Result`, but
//! with a third case to distinguish between errors that should cause a retry and errors that
//! should immediately return, halting retry behavior. (Internally, `OperationResult` is always
//! used, and closures passed to `retry` that return plain `Result` are converted into
//! `OperationResult`.)
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! use retry::OperationResult;
//! let mut collection = vec![1, 2].into_iter();
//! let value = retry(Fixed::from_millis(1), || {
//!     match collection.next() {
//!         Some(n) if n == 2 => OperationResult::Ok(n),
//!         Some(_) => OperationResult::Retry("not 2"),
//!         None => OperationResult::Err("not found"),
//!     }
//! }).unwrap();
//!
//! assert_eq!(value, 2);
//! ```
//!
//! If your operation needs to know how many times it's been tried, use the `retry_with_index`
//! function. This works the same as `retry`, but passes the number of the current try to the
//! closure as an argument.
//!
//! ```
//! # use retry::retry_with_index;
//! # use retry::delay::Fixed;
//! # use retry::OperationResult;
//! let mut collection = vec![1, 2, 3, 4, 5].into_iter();
//!
//! let result = retry_with_index(Fixed::from_millis(100), |current_try| {
//!     if current_try > 3 {
//!         return OperationResult::Err("did not succeed within 3 tries");
//!     }
//!
//!     match collection.next() {
//!         Some(n) if n == 5 => OperationResult::Ok("n is 5!"),
//!         Some(_) => OperationResult::Retry("n must be 5!"),
//!         None => OperationResult::Retry("n was never 5!"),
//!     }
//! });
//!
//! assert!(result.is_err());
//! ```
//!
//! # Features
//!
//! - `random`: offer some random delay utilities (on by default)

#![deny(missing_debug_implementations, missing_docs, warnings)]

use std::{
    error::Error as StdError,
    fmt::{Display, Error as FmtError, Formatter},
    thread::sleep,
    time::Duration,
};

pub mod delay;
mod opresult;

#[doc(inline)]
pub use opresult::OperationResult;

/// Retry the given operation synchronously until it succeeds, or until the given `Duration`
/// iterator ends.
pub fn retry<I, O, R, E, OR>(iterable: I, mut operation: O) -> Result<R, Error<E>>
where
    I: IntoIterator<Item = Duration>,
    O: FnMut() -> OR,
    OR: Into<OperationResult<R, E>>,
{
    retry_with_index(iterable, |_| operation())
}

/// Retry the given operation synchronously until it succeeds, or until the given `Duration`
/// iterator ends, with each iteration of the operation receiving the number of the attempt as an
/// argument.
pub fn retry_with_index<I, O, R, E, OR>(iterable: I, mut operation: O) -> Result<R, Error<E>>
where
    I: IntoIterator<Item = Duration>,
    O: FnMut(u64) -> OR,
    OR: Into<OperationResult<R, E>>,
{
    let mut iterator = iterable.into_iter();
    let mut current_try = 1;
    let mut total_delay = Duration::default();

    loop {
        match operation(current_try).into() {
            OperationResult::Ok(value) => return Ok(value),
            OperationResult::Retry(error) => {
                if let Some(delay) = iterator.next() {
                    sleep(delay);
                    current_try += 1;
                    total_delay += delay;
                } else {
                    return Err(Error::Operation {
                        error,
                        total_delay,
                        tries: current_try,
                    });
                }
            }
            OperationResult::Err(error) => {
                return Err(Error::Operation {
                    error,
                    total_delay,
                    tries: current_try,
                });
            }
        }
    }
}

/// An error with a retryable operation.
#[derive(Debug, PartialEq, Eq)]
pub enum Error<E> {
    /// The operation's last error, plus the number of times the operation was tried and the
    /// duration spent waiting between tries.
    Operation {
        /// The error returned by the operation on the last try.
        error: E,
        /// The duration spent waiting between retries of the operation.
        ///
        /// Note that this does not include the time spent running the operation itself.
        total_delay: Duration,
        /// The total number of times the operation was tried.
        tries: u64,
    },
    /// Something went wrong in the internal logic.
    Internal(String),
}

impl<E> Display for Error<E>
where
    E: StdError,
{
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        match self {
            Error::Operation { error, .. } => Display::fmt(error, formatter),
            Error::Internal(description) => formatter.write_str(description),
        }
    }
}

impl<E> StdError for Error<E>
where
    E: StdError,
{
    #[allow(deprecated)]
    fn description(&self) -> &str {
        match *self {
            Error::Operation { ref error, .. } => error.description(),
            Error::Internal(ref description) => description,
        }
    }

    fn cause(&self) -> Option<&dyn StdError> {
        match *self {
            Error::Operation { ref error, .. } => Some(error),
            Error::Internal(_) => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use super::delay::{Exponential, Fixed, NoDelay};
    use super::opresult::OperationResult;
    use super::{retry, retry_with_index, Error};

    #[test]
    fn succeeds_with_infinite_retries() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = retry(NoDelay, || match collection.next() {
            Some(n) if n == 5 => Ok(n),
            Some(_) => Err("not 5"),
            None => Err("not 5"),
        })
        .unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_with_maximum_retries() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(NoDelay.take(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let res = retry(NoDelay.take(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        });

        assert_eq!(
            res,
            Err(Error::Operation {
                error: "not 2",
                tries: 2,
                total_delay: Duration::from_millis(0)
            })
        );
    }

    #[test]
    fn fatal_errors() {
        let mut collection = vec![1].into_iter();

        let res = retry(NoDelay.take(2), || match collection.next() {
            Some(n) if n == 2 => OperationResult::Ok(n),
            Some(_) => OperationResult::Err("no retry"),
            None => OperationResult::Err("not 2"),
        });

        assert_eq!(
            res,
            Err(Error::Operation {
                error: "no retry",
                tries: 1,
                total_delay: Duration::from_millis(0)
            })
        );
    }

    #[test]
    fn succeeds_with_fixed_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Fixed::from_millis(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fixed_delay_from_duration() {
        assert_eq!(
            Fixed::from_millis(1_000).next(),
            Fixed::from(Duration::from_secs(1)).next(),
        );
    }

    #[test]
    fn succeeds_with_exponential_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Exponential::from_millis(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_exponential_delay_with_factor() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(
            Exponential::from_millis_with_factor(1000, 2.0),
            || match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            },
        )
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    #[cfg(feature = "random")]
    fn succeeds_with_ranged_delay() {
        use super::delay::Range;

        let mut collection = vec![1, 2].into_iter();

        let value = retry(Range::from_millis_exclusive(1, 10), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_index() {
        let mut collection = vec![1, 2, 3].into_iter();

        let value = retry_with_index(NoDelay, |current_try| match collection.next() {
            Some(n) if n == current_try => Ok(n),
            Some(_) => Err("not current_try"),
            None => Err("not current_try"),
        })
        .unwrap();

        assert_eq!(value, 1);
    }
}
<commit_msg>Provide Display impl for more error types<commit_after>//! Crate `retry` provides utilities for retrying operations that can fail.
//!
//! # Usage
//!
//! Retry an operation using the `retry` function. `retry` accepts an iterator over `Duration`s and
//! a closure that returns a `Result` (or `OperationResult`; see below). The iterator is used to
//! determine how long to wait after each unsuccessful try and how many times to try before giving
//! up and returning `Result::Err`. The closure determines either the final successful value, or
//! an error value, which can either be returned immediately or used to indicate that the
//! operation should be retried.
//!
//! Any type that implements `Iterator<Item = Duration>` can be used to determine retry behavior,
//! though a few useful implementations are provided in the `delay` module, including a fixed delay
//! and exponential back-off.
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_ok());
//! ```
//!
//! The `Iterator` API can be used to limit or modify the delay strategy. For example, to limit the
//! number of retries to 1:
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100).take(1), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_err());
//! ```
//!
#![cfg_attr(
    feature = "random",
    doc = r##"
To apply random jitter to any delay strategy, the `jitter` function can be used in combination
with the `Iterator` API:

```
# use retry::retry;
# use retry::delay::{Exponential, jitter};
let mut collection = vec![1, 2, 3].into_iter();

let result = retry(Exponential::from_millis(10).map(jitter).take(3), || {
    match collection.next() {
        Some(n) if n == 3 => Ok("n is 3!"),
        Some(_) => Err("n must be 3!"),
        None => Err("n was never 3!"),
    }
});

assert!(result.is_ok());
```
"##
)]
//!
//! To deal with fatal errors, return `retry::OperationResult`, which is like std's `Result`, but
//! with a third case to distinguish between errors that should cause a retry and errors that
//! should immediately return, halting retry behavior. (Internally, `OperationResult` is always
//! used, and closures passed to `retry` that return plain `Result` are converted into
//! `OperationResult`.)
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! use retry::OperationResult;
//! let mut collection = vec![1, 2].into_iter();
//! let value = retry(Fixed::from_millis(1), || {
//!     match collection.next() {
//!         Some(n) if n == 2 => OperationResult::Ok(n),
//!         Some(_) => OperationResult::Retry("not 2"),
//!         None => OperationResult::Err("not found"),
//!     }
//! }).unwrap();
//!
//! assert_eq!(value, 2);
//! ```
//!
//! If your operation needs to know how many times it's been tried, use the `retry_with_index`
//! function. This works the same as `retry`, but passes the number of the current try to the
//! closure as an argument.
//!
//! ```
//! # use retry::retry_with_index;
//! # use retry::delay::Fixed;
//! # use retry::OperationResult;
//! let mut collection = vec![1, 2, 3, 4, 5].into_iter();
//!
//! let result = retry_with_index(Fixed::from_millis(100), |current_try| {
//!     if current_try > 3 {
//!         return OperationResult::Err("did not succeed within 3 tries");
//!     }
//!
//!     match collection.next() {
//!         Some(n) if n == 5 => OperationResult::Ok("n is 5!"),
//!         Some(_) => OperationResult::Retry("n must be 5!"),
//!         None => OperationResult::Retry("n was never 5!"),
//!     }
//! });
//!
//! assert!(result.is_err());
//! ```
//!
//! # Features
//!
//! - `random`: offer some random delay utilities (on by default)

#![deny(missing_debug_implementations, missing_docs, warnings)]

use std::{
    error::Error as StdError,
    fmt::{Display, Error as FmtError, Formatter},
    thread::sleep,
    time::Duration,
};

pub mod delay;
mod opresult;

#[doc(inline)]
pub use opresult::OperationResult;

/// Retry the given operation synchronously until it succeeds, or until the given `Duration`
/// iterator ends.
pub fn retry<I, O, R, E, OR>(iterable: I, mut operation: O) -> Result<R, Error<E>>
where
    I: IntoIterator<Item = Duration>,
    O: FnMut() -> OR,
    OR: Into<OperationResult<R, E>>,
{
    retry_with_index(iterable, |_| operation())
}

/// Retry the given operation synchronously until it succeeds, or until the given `Duration`
/// iterator ends, with each iteration of the operation receiving the number of the attempt as an
/// argument.
pub fn retry_with_index<I, O, R, E, OR>(iterable: I, mut operation: O) -> Result<R, Error<E>>
where
    I: IntoIterator<Item = Duration>,
    O: FnMut(u64) -> OR,
    OR: Into<OperationResult<R, E>>,
{
    let mut iterator = iterable.into_iter();
    let mut current_try = 1;
    let mut total_delay = Duration::default();

    loop {
        match operation(current_try).into() {
            OperationResult::Ok(value) => return Ok(value),
            OperationResult::Retry(error) => {
                if let Some(delay) = iterator.next() {
                    sleep(delay);
                    current_try += 1;
                    total_delay += delay;
                } else {
                    return Err(Error::Operation {
                        error,
                        total_delay,
                        tries: current_try,
                    });
                }
            }
            OperationResult::Err(error) => {
                return Err(Error::Operation {
                    error,
                    total_delay,
                    tries: current_try,
                });
            }
        }
    }
}

/// An error with a retryable operation.
#[derive(Debug, PartialEq, Eq)]
pub enum Error<E> {
    /// The operation's last error, plus the number of times the operation was tried and the
    /// duration spent waiting between tries.
    Operation {
        /// The error returned by the operation on the last try.
        error: E,
        /// The duration spent waiting between retries of the operation.
        ///
        /// Note that this does not include the time spent running the operation itself.
        total_delay: Duration,
        /// The total number of times the operation was tried.
        tries: u64,
    },
    /// Something went wrong in the internal logic.
    Internal(String),
}

impl<E> Display for Error<E>
where
    E: Display,
{
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        match self {
            Error::Operation { error, .. } => Display::fmt(error, formatter),
            Error::Internal(description) => formatter.write_str(description),
        }
    }
}

impl<E> StdError for Error<E>
where
    E: StdError,
{
    #[allow(deprecated)]
    fn description(&self) -> &str {
        match *self {
            Error::Operation { ref error, .. } => error.description(),
            Error::Internal(ref description) => description,
        }
    }

    fn cause(&self) -> Option<&dyn StdError> {
        match *self {
            Error::Operation { ref error, .. } => Some(error),
            Error::Internal(_) => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use super::delay::{Exponential, Fixed, NoDelay};
    use super::opresult::OperationResult;
    use super::{retry, retry_with_index, Error};

    #[test]
    fn succeeds_with_infinite_retries() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = retry(NoDelay, || match collection.next() {
            Some(n) if n == 5 => Ok(n),
            Some(_) => Err("not 5"),
            None => Err("not 5"),
        })
        .unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_with_maximum_retries() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(NoDelay.take(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let res = retry(NoDelay.take(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        });

        assert_eq!(
            res,
            Err(Error::Operation {
                error: "not 2",
                tries: 2,
                total_delay: Duration::from_millis(0)
            })
        );
    }

    #[test]
    fn fatal_errors() {
        let mut collection = vec![1].into_iter();

        let res = retry(NoDelay.take(2), || match collection.next() {
            Some(n) if n == 2 => OperationResult::Ok(n),
            Some(_) => OperationResult::Err("no retry"),
            None => OperationResult::Err("not 2"),
        });

        assert_eq!(
            res,
            Err(Error::Operation {
                error: "no retry",
                tries: 1,
                total_delay: Duration::from_millis(0)
            })
        );
    }

    #[test]
    fn succeeds_with_fixed_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Fixed::from_millis(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fixed_delay_from_duration() {
        assert_eq!(
            Fixed::from_millis(1_000).next(),
            Fixed::from(Duration::from_secs(1)).next(),
        );
    }

    #[test]
    fn succeeds_with_exponential_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Exponential::from_millis(1), || match collection.next() {
            Some(n) if n == 2 => Ok(n),
            Some(_) => Err("not 2"),
            None => Err("not 2"),
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_exponential_delay_with_factor() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(
            Exponential::from_millis_with_factor(1000, 2.0),
            || match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            },
        )
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    #[cfg(feature = "random")]
    fn succeeds_with_ranged_delay() {
        use super::delay::Range;

        let mut collection = vec![1, 2].into_iter();

        let value = retry(Range::from_millis_exclusive(1, 10), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        })
        .unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_index() {
        let mut collection = vec![1, 2, 3].into_iter();

        let value = retry_with_index(NoDelay, |current_try| match collection.next() {
            Some(n) if n == current_try => Ok(n),
            Some(_) => Err("not current_try"),
            None => Err("not current_try"),
        })
        .unwrap();

        assert_eq!(value, 1);
    }
}
<|endoftext|>


<commit_before>//! Sqlite support for the `r2d2` connection pool.
extern crate r2d2;
extern crate rusqlite;

use std::error;
use std::error::Error as _StdError;
use std::fmt;

use rusqlite::SqliteError;
use rusqlite::SqliteConnection;

use std::path::Path;

#[derive(Debug)]
pub enum Error {
    Connect(SqliteError),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}: {}", self.description(), self.cause().unwrap())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Connect(_) => "Error opening a connection",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Connect(ref err) => Some(err as &error::Error),
        }
    }
}

pub struct SqliteConnectionManager {
    in_memory: bool,
    path: Option<String>,
}

impl SqliteConnectionManager {

    pub fn new(database: &str)-> Result<SqliteConnectionManager, SqliteError>{
        match database{
            ":memory:" => {
                Ok(SqliteConnectionManager {in_memory: true, path: None})
            },
            _ => {
                Ok(SqliteConnectionManager {in_memory: false, path: Some(database.to_string())})
           }
        }
    }
}

impl r2d2::ManageConnection for SqliteConnectionManager {
    type Connection = SqliteConnection;
    type Error = Error;

    fn connect(&self) -> Result<SqliteConnection, Error> {
        if self.in_memory{
            Ok(SqliteConnection::open_in_memory().unwrap())
        }
        else if self.path.is_some(){
            println!("path: {:?}", self.path);
            Ok(SqliteConnection::open(&Path::new(self.path.as_ref().unwrap())).unwrap())
        }
        else{
            unreachable!()
        }
    }

    fn is_valid(&self, conn: &mut SqliteConnection) -> Result<(), Error> {
        conn.execute_batch("").map_err(Error::Connect)
    }

    fn has_broken(&self, conn: &mut SqliteConnection) -> bool {
        false
    }
}
<commit_msg>Remove debug print<commit_after>//! Sqlite support for the `r2d2` connection pool.
extern crate r2d2;
extern crate rusqlite;

use std::error;
use std::error::Error as _StdError;
use std::fmt;

use rusqlite::SqliteError;
use rusqlite::SqliteConnection;

use std::path::Path;

#[derive(Debug)]
pub enum Error {
    Connect(SqliteError),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}: {}", self.description(), self.cause().unwrap())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Connect(_) => "Error opening a connection",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Connect(ref err) => Some(err as &error::Error),
        }
    }
}

pub struct SqliteConnectionManager {
    in_memory: bool,
    path: Option<String>,
}

impl SqliteConnectionManager {

    pub fn new(database: &str)-> Result<SqliteConnectionManager, SqliteError>{
        match database{
            ":memory:" => {
                Ok(SqliteConnectionManager {in_memory: true, path: None})
            },
            _ => {
                Ok(SqliteConnectionManager {in_memory: false, path: Some(database.to_string())})
           }
        }
    }
}

impl r2d2::ManageConnection for SqliteConnectionManager {
    type Connection = SqliteConnection;
    type Error = Error;

    fn connect(&self) -> Result<SqliteConnection, Error> {
        if self.in_memory{
            Ok(SqliteConnection::open_in_memory().unwrap())
        }
        else if self.path.is_some(){
            Ok(SqliteConnection::open(&Path::new(self.path.as_ref().unwrap())).unwrap())
        }
        else{
            unreachable!()
        }
    }

    fn is_valid(&self, conn: &mut SqliteConnection) -> Result<(), Error> {
        conn.execute_batch("").map_err(Error::Connect)
    }

    fn has_broken(&self, conn: &mut SqliteConnection) -> bool {
        false
    }
}
<|endoftext|>