<commit_before>use std::path::PathBuf;
use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use toml::Value;
use git2::{Reference as GitReference, Repository, Error as Git2Error};

use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::error::HookError as HE;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::error::CustomData as HECD;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;
use libimagerror::trace::trace_error;
use libimagerror::into::IntoError;

use vcs::git::result::Result;
use vcs::git::error::MapErrInto;
use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::GitHookError as GHE;
use vcs::git::config::ensure_branch;

pub struct CreateHook<'a> {
    storepath: &'a PathBuf,

    repository: Option<Repository>,

    position: HookPosition,
}

impl<'a> CreateHook<'a> {

    pub fn new(storepath: &'a PathBuf, p: HookPosition) -> CreateHook<'a> {
        let r = match Repository::open(storepath) {
            Ok(r) => Some(r),
            Err(e) => {
                trace_error(&e);
                None
            },
        };
        CreateHook {
            storepath: storepath,
            repository: r,
            position: p,
        }
    }

    fn repository(&self) -> HookResult<&Repository> {
        use vcs::git::config::abort_on_repo_init_err;

        match self.repository.as_ref() {
            Some(r) => Ok(r),
            None    => {
                debug!("Repository isn't initialized... creating error object now");
                let he = GHEK::MkRepo.into_error();
                let he = HE::new(HEK::HookExecutionError, Some(Box::new(he)));
                let custom = HECD::default().aborting(abort_on_repo_init_err(self.config.as_ref()));
                return Err(he.with_custom_data(custom));
            }
        }
    }

}

impl<'a> Debug for CreateHook<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "CreateHook(storepath={:?}, repository={}, pos={:?}, cfg={:?}",
               self.storepath,
               (if self.repository.is_some() { "Some(_)" } else { "None" }),
               self.position,
               self.runtime.has_config())
    }
}

impl<'a> Hook for CreateHook<'a> {

    fn name(&self) -> &'static str {
        "stdhook_git_create"
    }

    fn set_config(&mut self, config: &Value) {
        if let Err(e) = self.runtime.set_config(config) {
            trace_error(&e);
        }
    }

}

impl<'a> HookDataAccessorProvider for CreateHook<'a> {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl<'a> StoreIdAccessor for CreateHook<'a> {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        debug!("[GIT CREATE HOOK]: {:?}", id);
        let repository = try!(self.repository());
        let head       = try!(repository.head().map_err_into(GHEK::HeadFetchError)
             .map_err(|e| HEK::HookExecutionError.into_error_with_cause(Box::new(e))));

        if head.is_branch() {
            return GHEK::NotOnBranch.into_error().inside_of(HEK::HookExecutionError)
        }

        try!(checkout_branch(self.config.as_ref(), &head)
             .map_err(|e| HEK::HookExecutionError.into_error_with_cause(Box::new(e))));

        // Now to the create() hook action

        unimplemented!()

        Ok(())
    }

}

fn checkout_branch(config: Option<&Value>, head: &GitReference) -> Result<()> {
    // Check out appropriate branch ... or fail
    match ensure_branch(config) {
        Ok(Some(s)) => {
            match head.name().map(|name| name == s) {
                Some(b) => {
                    if b {
                        debug!("Branch already checked out.");
                        Ok(())
                    } else {
                        debug!("Branch not checked out.");
                        unimplemented!()
                    }
                },

                None => Err(GHEK::RepositoryBranchNameFetchingError.into_error())
                    .map_err_into(GHEK::RepositoryBranchError)
                    .map_err_into(GHEK::RepositoryError),
            }
        },
        Ok(None) => {
            debug!("No branch to checkout");
            Ok(())
        },

        Err(e) => Err(e).map_err_into(GHEK::RepositoryError),
    }
}

<commit_msg>Use Runtime object rather than own Repository object<commit_after>use std::path::PathBuf;
use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use toml::Value;
use git2::{Reference as GitReference, Repository, Error as Git2Error};

use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::error::HookError as HE;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::error::CustomData as HECD;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;
use libimagerror::trace::trace_error;
use libimagerror::into::IntoError;

use vcs::git::result::Result;
use vcs::git::error::MapErrInto;
use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::GitHookError as GHE;
use vcs::git::runtime::Runtime;

pub struct CreateHook<'a> {
    storepath: &'a PathBuf,

    runtime: Runtime<'a>,

    position: HookPosition,
}

impl<'a> CreateHook<'a> {

    pub fn new(storepath: &'a PathBuf, p: HookPosition) -> CreateHook<'a> {
        CreateHook {
            storepath: storepath,
            runtime: Runtime::new(storepath),
            position: p,
        }
    }

}

impl<'a> Debug for CreateHook<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "CreateHook(storepath={:?}, repository={}, pos={:?}, cfg={:?}",
               self.storepath,
               (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
               self.position,
               self.runtime.has_config())
    }
}

impl<'a> Hook for CreateHook<'a> {

    fn name(&self) -> &'static str {
        "stdhook_git_create"
    }

    fn set_config(&mut self, config: &Value) {
        if let Err(e) = self.runtime.set_config(config) {
            trace_error(&e);
        }
    }

}

impl<'a> HookDataAccessorProvider for CreateHook<'a> {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl<'a> StoreIdAccessor for CreateHook<'a> {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        debug!("[GIT CREATE HOOK]: {:?}", id);
        try!(self
             .runtime
             .ensure_cfg_branch_is_checked_out()
             .map_err(Box::new)
             .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e)));
        let repository = try!(self.runtime.repository());

        // Now to the create() hook action

        unimplemented!()

        Ok(())
    }

}

<|endoftext|>


<commit_before>use alloc::collections::VecDeque;
use alloc::prelude::v1::*;

use d7time::Instant;

use crate::multitasking::ProcessId;

/// Instructions for scheduling a process
#[derive(Debug, Clone)]
pub enum Schedule {
    /// Run again on the next free slot
    Running,
    /// Run after specified moment
    Sleeping(Instant),
}

#[derive(Debug)]
pub struct Queues {
    /// Processes currently in the running queue
    pub running: VecDeque<ProcessId>,
    /// Processes which are sleeping until specified time
    /// Must be kept sorted by the wake-up time
    /// TODO: Switch to a proper priority queue for faster insert time
    pub sleeping: VecDeque<(Instant, ProcessId)>,
}
impl Queues {
    pub fn new() -> Self {
        Self {
            running: VecDeque::new(),
            sleeping: VecDeque::new(),
        }
    }

    pub fn all_completed(&self) -> bool {
        self.running.is_empty() && self.sleeping.is_empty()
    }

    pub fn give(&mut self, pid: ProcessId, s: Schedule) {
        match s {
            Schedule::Running => {
                self.running.push_back(pid);
            },
            Schedule::Sleeping(instant) => {
                let i = p_index_vecdeque(&self.sleeping, &instant);
                self.sleeping.insert(i, (instant, pid));
            },
        }
    }

    pub fn take(&mut self) -> Option<ProcessId> {
        self.running.pop_front()
    }

    /// Update by when clock ticks
    pub fn tick(&mut self, now: &Instant) {
        if self.sleeping.len() >= 2 {
            assert!(self.sleeping[0].0 < self.sleeping[1].0, "SLORD1");
            if self.sleeping.len() >= 3 {
                assert!(self.sleeping[1].0 < self.sleeping[2].0, "SLORD2");
            }
        }

        while let Some((wakeup, _)) = self.sleeping.front() {
            if now >= wakeup {
                let (_, pid) = self.sleeping.pop_front().unwrap();
                // FIXME: push_front to schedule immediately?
                self.running.push_back(pid);
            } else {
                break;
            }
        }
    }
}

/// Priority queue like index in the vecdeque of pairs
/// The first item of the pair is used as the priority key
fn p_index_vecdeque<K: Ord, V>(v: &VecDeque<(K, V)>, t: &K) -> usize {
    // TODO: use binary search?
    let mut i = 0;
    while i < v.len() {
        if &v[i].0 > t {
            return i;
        }
        i += 1;
    }
    return v.len();
}
<commit_msg>Clean up some clippy warnings<commit_after>use alloc::collections::VecDeque;
use alloc::prelude::v1::*;

use d7time::Instant;

use crate::multitasking::ProcessId;

/// Instructions for scheduling a process
#[derive(Debug, Clone)]
pub enum Schedule {
    /// Run again on the next free slot
    Running,
    /// Run after specified moment
    Sleeping(Instant),
}

#[derive(Debug)]
pub struct Queues {
    /// Processes currently in the running queue
    pub running: VecDeque<ProcessId>,
    /// Processes which are sleeping until specified time
    /// Must be kept sorted by the wake-up time
    /// TODO: Switch to a proper priority queue for faster insert time
    pub sleeping: VecDeque<(Instant, ProcessId)>,
}
impl Queues {
    pub fn new() -> Self {
        Self {
            running: VecDeque::new(),
            sleeping: VecDeque::new(),
        }
    }

    pub fn all_completed(&self) -> bool {
        self.running.is_empty() && self.sleeping.is_empty()
    }

    pub fn give(&mut self, pid: ProcessId, s: Schedule) {
        match s {
            Schedule::Running => {
                self.running.push_back(pid);
            },
            Schedule::Sleeping(instant) => {
                let i = p_index_vecdeque(&self.sleeping, &instant);
                self.sleeping.insert(i, (instant, pid));
            },
        }
    }

    pub fn take(&mut self) -> Option<ProcessId> {
        self.running.pop_front()
    }

    /// Update by when clock ticks
    pub fn tick(&mut self, now: &Instant) {
        if self.sleeping.len() >= 2 {
            assert!(self.sleeping[0].0 < self.sleeping[1].0, "SLORD1");
            if self.sleeping.len() >= 3 {
                assert!(self.sleeping[1].0 < self.sleeping[2].0, "SLORD2");
            }
        }

        while let Some((wakeup, _)) = self.sleeping.front() {
            if now >= wakeup {
                let (_, pid) = self.sleeping.pop_front().unwrap();
                // FIXME: push_front to schedule immediately?
                self.running.push_back(pid);
            } else {
                break;
            }
        }
    }
}

/// Priority queue like index in the vecdeque of pairs
/// The first item of the pair is used as the priority key
fn p_index_vecdeque<K: Ord, V>(v: &VecDeque<(K, V)>, t: &K) -> usize {
    // TODO: use binary search?
    let mut i = 0;
    while i < v.len() {
        if v[i].0 > *t {
            return i;
        }
        i += 1;
    }
    v.len()
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for interacting with the system's VGA buffer.
#![crate_name = "sos_vga"]

#![feature( const_fn
          , slice_patterns
          , unique )]
#![cfg_attr( feature = "system_term"
           , feature(lang_items) )]
#![no_std]

#[cfg(feature = "system_term")]
extern crate spin;

use core::mem;
use core::fmt::{Write, Result};
use core::ptr::Unique;

#[cfg(feature = "system_term")]
use spin::Mutex;

/// The system's global VGA terminal
#[cfg(feature = "system_term")]
pub static CONSOLE: Mutex<Terminal>
    = Mutex::new(unsafe { Terminal::new(
         Palette::new(Color::LightGrey, Color::Black )
       , 0xB8000
    )});

// TODO: support varying VGA screen sizes?
pub const X_MAX: usize = 80;
pub const Y_MAX: usize = 25;

/// The type signature fot the actual VGA buffer
pub type Buffer = [[Char; X_MAX]; Y_MAX];

const ANSI_ESCAPE: &'static str = "\x1b";
const FG_MASK: u8 = 0b0000_1111;
const BG_MASK: u8 = 0b1111_0000;

/// VGA color codes
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
#[repr(u8)]
pub enum Color { Black = 0
               , Blue = 1
               , Green = 2
               , Cyan = 3
               , Red = 4
               , Magenta = 5
               , Brown = 6
               , LightGrey = 7
               , DarkGrey = 8
               , LightBlue = 9
               , LightGreen = 10
               , LightCyan = 11
               , LightRed = 12
               , LightMagenta = 13
               , Yellow = 14
               , White = 15
               }

#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
pub struct Palette(u8);

impl Palette {
    /// Returns a `Palette` with the given foreground and background color.
    pub const fn new(fg: Color, bg: Color) -> Self {
        Palette( (bg as u8) << 4 | (fg as u8) )
    }

    /// Returns a new `Palette` with this palette's background color, and
    /// the specified foreground color.
    pub fn set_foreground(&self, fg: Color) -> Self {
        Palette( ( self.0 & BG_MASK) | (fg as u8 & FG_MASK) )
    }

    /// Returns a new `Palette` with this palette's foreground color, and
    /// the specified background color.
    pub fn set_background(&self, bg: Color) -> Self {
        Palette( ( (bg as u8) << 4 & BG_MASK) | (self.0 & FG_MASK) )
    }

    /// Returns this `Palette`'s foreground color.
    pub fn foreground(&self) -> Color {
        unsafe { mem::transmute(self.0 & FG_MASK) }
    }

    /// Returns this `Palette`'s background color.
    pub fn background(&self) -> Color {
        unsafe { mem::transmute((self.0 & BG_MASK) >> 4) }
    }

}
/// A colored VGA character.
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Char { pub ascii: u8
                , pub colors: Palette
                }

pub struct Terminal { buffer: Unique<Buffer>
                    , x: usize
                    , y: usize
                    , colors: Palette
                    }
impl Terminal {

    /// Constructs a new `Terminal` for abuffer starting at the given address.
    ///
    /// # Arguments:
    ///   - `colors`: the default color palette for the terminal
    ///   - `buffer_start`: the address of the to the memory location where
    ///      the terminal's VGA buffer begins
    ///
    /// # Unsafe due to:
    ///   - Casting a raw address to an array
    pub const unsafe fn new( colors: Palette
                           , buffer_start: usize)
                           -> Terminal {
        Terminal { x: 0, y: 0
                 , colors: colors
                 , buffer: Unique::new(buffer_start as *mut _)
                 }
    }

    #[inline]
    fn buffer(&mut self) -> &mut  Buffer {
        unsafe { self.buffer.get_mut() }
    }

    /// Set the color palette used for writing subsequent characters.
    pub fn set_colors(&mut self, bg: Color, fg: Color) -> &mut Self {
        self.colors = Palette::new(bg,fg);
        self
    }

    /// Scrolls the terminal one row.
    fn scroll(&mut self) {
        // // construct an iterator over the whole buffer
        // let mut rows = self.buffer()
        //                    .iter_mut();
        //
        // // the current row in the buffer
        // let mut current = rows.next()
        //                    .unwrap();
        //
        // while let Some(next) = rows.next() {
        //     // while there are rows remaining in the iterator, swap the
        //     // next row with the current one (moving it back by one)
        //     mem::swap(current, next);
        //     // and advance our pointer to the current row.
        //     current = next;
        // }
        let buffer: &mut _ = self.buffer();
        for row in 1..Y_MAX {
            buffer[row - 1] = buffer[row];
        }
        // empty the last line in the buffer
        unsafe { buffer[Y_MAX - 1] = mem::zeroed() }
    }

    /// Clear the terminal
    pub fn clear(&mut self) -> &mut Self {
        // to clear the terminal, we just zero out the whole buffer.
        unsafe { *(self.buffer()) = mem::zeroed(); }
        self.x = 0;
        self.y = 0;
        self
    }

    /// Write the given byte to the terminal, and advance the cursor position.
    pub fn write_byte(&mut self, byte: u8) -> &mut Self {
        if byte == b'\n' {
            // if the byte is a newline, we just advance to the next line
            // and reset the column position.
            self.x = 0;
            self.y += 1;
        } else {
            // otherwise, it's a regular character, so we just set the
            // byte at the current position in the buffer to that
            // character (with the current color palette)
            self.buffer()[self.y][self.x]
                = Char { ascii: byte
                       , colors: self.colors };
            // and advance our column position by one
            self.x += 1;

            if self.x >= X_MAX {
                // if we've reached the end of the line, advance to the next
                self.x = 0;
                self.y += 1;
            }
        }
        if self.y >= Y_MAX {
            // if we've reached the bottom of the terminal, scroll.
            self.scroll();
            self.y -= 1;
        }
        self
    }

    fn handle_ansi_escape(&self, escape_code: &str) -> Result {
        match escape_code.as_bytes() {
            // `\x1b[3Nm` sets the foreground color to N.
            [0x1b, b'[', b'3', n, b'm'] => {
                unsafe { self.colors
                             .set_foreground(mem::transmute(n - 48)); }
                Ok(())
            }
            // `\x1b[4Nm` sets the background color to N
          , [0x1b, b'[', b'4', n, b'm'] => {
                unsafe { self.colors
                             .set_background(mem::transmute(n - 48)); }
                Ok(())
            }
          , _ => unimplemented!()
        }
        // let escape_seq: &str = bytes.take_while(|b| b != b'm')
        //                       .collect::<&str>();
        // match escape_seq {
        //     [b'3', n] => unsafe {
        //         self.colors.set_foreground(mem::transmute(n - 48))
        //     }
        // }
        // while let Some(byte) = bytes.next() {
        //     match *byte {
        //         // we've recieved an ANSI escape sequence.
        //         // this basically enters a mediocre FSM for matching ANSI
        //         // control codes.
        //         0x1b => match *next_ansi_byte!(bytes) {
        //             // handle multi-char ANSI escapes
        //             b'[' => match *next_ansi_byte!(bytes) {
        //                 // foreground color code
        //                 fg @ 30 ... 37 => {
        //                     if !(*next_ansi_byte!(bytes) == b'm') {
        //                         unsafe {
        //                             let color: vga::Color
        //                                 = mem::transmute(fg - 30);
        //                             self.colors
        //                                 .set_foreground(color);
        //                         }
        //
        //                     }
        //                 }
        //                 // background color code
        //               , 40 ... 47 => {
        //
        //                 }
        //               , _ => unimplemented!()
        //             }
        //           , _    => unimplemented!()
        //         }
        //         // otherwise, treat the byte as a normal ASCII char
        //       , b => { self.write_byte(b); }
        //     }
        // }

    }

}

struct AnsiEscapeIter<'a> { curr_slice: &'a str
                          , in_escape: bool
                          }

impl<'a> AnsiEscapeIter<'a> {

    pub fn new(s: &'a str) -> Self {
        AnsiEscapeIter { curr_slice: s
                       , in_escape: false
                       }
    }
}

impl<'a> Iterator for AnsiEscapeIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.curr_slice.len() == 0 {
            // if the remaining string is empty, we just return `None`
            None
        } else {
            // otherwise, find the next index to chunk on.
            let maybe_idx
                = if self.in_escape {
                     // if we're in an escape code, we split the chunk at the
                     // index of the next 'm' character, adding 1 so that the
                     // 'm' is in the escape code chunk.
                    self.curr_slice.find('m')
                        .map(|idx| idx + 1)
                } else {
                    // otherwise, split at the next ANSI escape sequence
                    self.curr_slice.find(ANSI_ESCAPE)
                };

            // if we found another index to chunk on, map over that index;
            // otherwise, we just yield the rest of the string
            maybe_idx.map_or(
                Some(self.curr_slice) // remainder (if no index to chunk on)
              , |idx| { // otherwise, chunk along that index...
                    let (chunk, next_slice) = self.curr_slice
                                                  .split_at(idx);
                    self.curr_slice = next_slice; // update current chunk
                    Some(chunk)                   // return the chunk
                })
        }

    }
}

impl Write for Terminal {

    fn write_str(&mut self, s: &str) -> Result {

        if s.contains(ANSI_ESCAPE) {
            // if the segment contains an ANSI escape, construct an iterator
            // over each chunk containing either an escape sequence or text
            for segment in AnsiEscapeIter::new(s) {
                if segment.starts_with(ANSI_ESCAPE) {
                    // if the current segment is an ANSI escape code,
                    // try to handle the escape and fail if it is malformed
                    try!(self.handle_ansi_escape(segment))
                } else {
                    // otherwise, just write each chunk in the string.
                    for byte in segment.as_bytes() {
                        self.write_byte(*byte);
                    }
                }
            }
        } else {
            // otherwise, if there are no ANSI escape codes,
            // we can just write each byte in the string.
            for byte in s.as_bytes() {
                self.write_byte(*byte);
            }
        }
        Ok(())
    }

}

#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
            use core::fmt::Write;
            $crate::CONSOLE.lock()
                           .write_fmt(format_args!($($arg)*))
                           .unwrap();
    });
}

#[cfg(feature = "log")]
#[macro_export]
macro_rules! log {
    (level: $level:expr, $fmt:expr, $($arg:tt)*) => ({
        println!( "[{} {}:{}] {}", $level, file!(), line!()
                , format_args!($fmt, $($arg)*));
    });
    (level: $level:expr, $fmt:expr) => ({
        println!("[{} {}:{}] {}", $level, file!(), line!(), $fmt);
    });
}

/// Required for Rust stack unwinding
#[cfg(feature = "system_term")]
#[lang = "eh_personality"]
#[no_mangle] #[inline(never)] #[cold]
pub extern "C" fn rust_eh_personality() {
    // TODO: add support for stack unwinding
    println!("eh")
}
<commit_msg>[vga] Refactor to use new question mark operator<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for interacting with the system's VGA buffer.
#![crate_name = "sos_vga"]

#![feature( const_fn
          , slice_patterns
          , unique
          , question_mark )]
#![cfg_attr( feature = "system_term"
           , feature(lang_items) )]
#![no_std]

#[cfg(feature = "system_term")]
extern crate spin;

use core::mem;
use core::fmt::{Write, Result};
use core::ptr::Unique;

#[cfg(feature = "system_term")]
use spin::Mutex;

/// The system's global VGA terminal
#[cfg(feature = "system_term")]
pub static CONSOLE: Mutex<Terminal>
    = Mutex::new(unsafe { Terminal::new(
         Palette::new(Color::LightGrey, Color::Black )
       , 0xB8000
    )});

// TODO: support varying VGA screen sizes?
pub const X_MAX: usize = 80;
pub const Y_MAX: usize = 25;

/// The type signature fot the actual VGA buffer
pub type Buffer = [[Char; X_MAX]; Y_MAX];

const ANSI_ESCAPE: &'static str = "\x1b";
const FG_MASK: u8 = 0b0000_1111;
const BG_MASK: u8 = 0b1111_0000;

/// VGA color codes
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
#[repr(u8)]
pub enum Color { Black = 0
               , Blue = 1
               , Green = 2
               , Cyan = 3
               , Red = 4
               , Magenta = 5
               , Brown = 6
               , LightGrey = 7
               , DarkGrey = 8
               , LightBlue = 9
               , LightGreen = 10
               , LightCyan = 11
               , LightRed = 12
               , LightMagenta = 13
               , Yellow = 14
               , White = 15
               }

#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
pub struct Palette(u8);

impl Palette {
    /// Returns a `Palette` with the given foreground and background color.
    pub const fn new(fg: Color, bg: Color) -> Self {
        Palette( (bg as u8) << 4 | (fg as u8) )
    }

    /// Returns a new `Palette` with this palette's background color, and
    /// the specified foreground color.
    pub fn set_foreground(&self, fg: Color) -> Self {
        Palette( ( self.0 & BG_MASK) | (fg as u8 & FG_MASK) )
    }

    /// Returns a new `Palette` with this palette's foreground color, and
    /// the specified background color.
    pub fn set_background(&self, bg: Color) -> Self {
        Palette( ( (bg as u8) << 4 & BG_MASK) | (self.0 & FG_MASK) )
    }

    /// Returns this `Palette`'s foreground color.
    pub fn foreground(&self) -> Color {
        unsafe { mem::transmute(self.0 & FG_MASK) }
    }

    /// Returns this `Palette`'s background color.
    pub fn background(&self) -> Color {
        unsafe { mem::transmute((self.0 & BG_MASK) >> 4) }
    }

}
/// A colored VGA character.
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Char { pub ascii: u8
                , pub colors: Palette
                }

pub struct Terminal { buffer: Unique<Buffer>
                    , x: usize
                    , y: usize
                    , colors: Palette
                    }
impl Terminal {

    /// Constructs a new `Terminal` for abuffer starting at the given address.
    ///
    /// # Arguments:
    ///   - `colors`: the default color palette for the terminal
    ///   - `buffer_start`: the address of the to the memory location where
    ///      the terminal's VGA buffer begins
    ///
    /// # Unsafe due to:
    ///   - Casting a raw address to an array
    pub const unsafe fn new( colors: Palette
                           , buffer_start: usize)
                           -> Terminal {
        Terminal { x: 0, y: 0
                 , colors: colors
                 , buffer: Unique::new(buffer_start as *mut _)
                 }
    }

    #[inline]
    fn buffer(&mut self) -> &mut  Buffer {
        unsafe { self.buffer.get_mut() }
    }

    /// Set the color palette used for writing subsequent characters.
    pub fn set_colors(&mut self, bg: Color, fg: Color) -> &mut Self {
        self.colors = Palette::new(bg,fg);
        self
    }

    /// Scrolls the terminal one row.
    fn scroll(&mut self) {
        // // construct an iterator over the whole buffer
        // let mut rows = self.buffer()
        //                    .iter_mut();
        //
        // // the current row in the buffer
        // let mut current = rows.next()
        //                    .unwrap();
        //
        // while let Some(next) = rows.next() {
        //     // while there are rows remaining in the iterator, swap the
        //     // next row with the current one (moving it back by one)
        //     mem::swap(current, next);
        //     // and advance our pointer to the current row.
        //     current = next;
        // }
        let buffer: &mut _ = self.buffer();
        for row in 1..Y_MAX {
            buffer[row - 1] = buffer[row];
        }
        // empty the last line in the buffer
        unsafe { buffer[Y_MAX - 1] = mem::zeroed() }
    }

    /// Clear the terminal
    pub fn clear(&mut self) -> &mut Self {
        // to clear the terminal, we just zero out the whole buffer.
        unsafe { *(self.buffer()) = mem::zeroed(); }
        self.x = 0;
        self.y = 0;
        self
    }

    /// Write the given byte to the terminal, and advance the cursor position.
    pub fn write_byte(&mut self, byte: u8) -> &mut Self {
        if byte == b'\n' {
            // if the byte is a newline, we just advance to the next line
            // and reset the column position.
            self.x = 0;
            self.y += 1;
        } else {
            // otherwise, it's a regular character, so we just set the
            // byte at the current position in the buffer to that
            // character (with the current color palette)
            self.buffer()[self.y][self.x]
                = Char { ascii: byte
                       , colors: self.colors };
            // and advance our column position by one
            self.x += 1;

            if self.x >= X_MAX {
                // if we've reached the end of the line, advance to the next
                self.x = 0;
                self.y += 1;
            }
        }
        if self.y >= Y_MAX {
            // if we've reached the bottom of the terminal, scroll.
            self.scroll();
            self.y -= 1;
        }
        self
    }

    fn handle_ansi_escape(&self, escape_code: &str) -> Result {
        match escape_code.as_bytes() {
            // `\x1b[3Nm` sets the foreground color to N.
            [0x1b, b'[', b'3', n, b'm'] => {
                unsafe { self.colors
                             .set_foreground(mem::transmute(n - 48)); }
                Ok(())
            }
            // `\x1b[4Nm` sets the background color to N
          , [0x1b, b'[', b'4', n, b'm'] => {
                unsafe { self.colors
                             .set_background(mem::transmute(n - 48)); }
                Ok(())
            }
          , _ => unimplemented!()
        }
        // let escape_seq: &str = bytes.take_while(|b| b != b'm')
        //                       .collect::<&str>();
        // match escape_seq {
        //     [b'3', n] => unsafe {
        //         self.colors.set_foreground(mem::transmute(n - 48))
        //     }
        // }
        // while let Some(byte) = bytes.next() {
        //     match *byte {
        //         // we've recieved an ANSI escape sequence.
        //         // this basically enters a mediocre FSM for matching ANSI
        //         // control codes.
        //         0x1b => match *next_ansi_byte!(bytes) {
        //             // handle multi-char ANSI escapes
        //             b'[' => match *next_ansi_byte!(bytes) {
        //                 // foreground color code
        //                 fg @ 30 ... 37 => {
        //                     if !(*next_ansi_byte!(bytes) == b'm') {
        //                         unsafe {
        //                             let color: vga::Color
        //                                 = mem::transmute(fg - 30);
        //                             self.colors
        //                                 .set_foreground(color);
        //                         }
        //
        //                     }
        //                 }
        //                 // background color code
        //               , 40 ... 47 => {
        //
        //                 }
        //               , _ => unimplemented!()
        //             }
        //           , _    => unimplemented!()
        //         }
        //         // otherwise, treat the byte as a normal ASCII char
        //       , b => { self.write_byte(b); }
        //     }
        // }

    }

}

struct AnsiEscapeIter<'a> { curr_slice: &'a str
                          , in_escape: bool
                          }

impl<'a> AnsiEscapeIter<'a> {

    pub fn new(s: &'a str) -> Self {
        AnsiEscapeIter { curr_slice: s
                       , in_escape: false
                       }
    }
}

impl<'a> Iterator for AnsiEscapeIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.curr_slice.len() == 0 {
            // if the remaining string is empty, we just return `None`
            None
        } else {
            // otherwise, find the next index to chunk on.
            let maybe_idx
                = if self.in_escape {
                     // if we're in an escape code, we split the chunk at the
                     // index of the next 'm' character, adding 1 so that the
                     // 'm' is in the escape code chunk.
                    self.curr_slice.find('m')
                        .map(|idx| idx + 1)
                } else {
                    // otherwise, split at the next ANSI escape sequence
                    self.curr_slice.find(ANSI_ESCAPE)
                };

            // if we found another index to chunk on, map over that index;
            // otherwise, we just yield the rest of the string
            maybe_idx.map_or(
                Some(self.curr_slice) // remainder (if no index to chunk on)
              , |idx| { // otherwise, chunk along that index...
                    let (chunk, next_slice) = self.curr_slice
                                                  .split_at(idx);
                    self.curr_slice = next_slice; // update current chunk
                    Some(chunk)                   // return the chunk
                })
        }

    }
}

impl Write for Terminal {

    fn write_str(&mut self, s: &str) -> Result {

        if s.contains(ANSI_ESCAPE) {
            // if the segment contains an ANSI escape, construct an iterator
            // over each chunk containing either an escape sequence or text
            for segment in AnsiEscapeIter::new(s) {
                if segment.starts_with(ANSI_ESCAPE) {
                    // if the current segment is an ANSI escape code,
                    // try to handle the escape and fail if it is malformed
                    self.handle_ansi_escape(segment)?
                } else {
                    // otherwise, just write each chunk in the string.
                    for byte in segment.as_bytes() {
                        self.write_byte(*byte);
                    }
                }
            }
        } else {
            // otherwise, if there are no ANSI escape codes,
            // we can just write each byte in the string.
            for byte in s.as_bytes() {
                self.write_byte(*byte);
            }
        }
        Ok(())
    }

}

#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
            use core::fmt::Write;
            $crate::CONSOLE.lock()
                           .write_fmt(format_args!($($arg)*))
                           .unwrap();
    });
}

#[cfg(feature = "log")]
#[macro_export]
macro_rules! log {
    (level: $level:expr, $fmt:expr, $($arg:tt)*) => ({
        println!( "[{} {}:{}] {}", $level, file!(), line!()
                , format_args!($fmt, $($arg)*));
    });
    (level: $level:expr, $fmt:expr) => ({
        println!("[{} {}:{}] {}", $level, file!(), line!(), $fmt);
    });
}

/// Required for Rust stack unwinding
#[cfg(feature = "system_term")]
#[lang = "eh_personality"]
#[no_mangle] #[inline(never)] #[cold]
pub extern "C" fn rust_eh_personality() {
    // TODO: add support for stack unwinding
    println!("eh")
}
<|endoftext|>


<commit_before>#![feature (test)]

extern crate test;
#[macro_use]
extern crate time_steward;

#[macro_use]
extern crate glium;

extern crate nalgebra;
extern crate rand;
extern crate docopt;

extern crate serde;
#[macro_use]
extern crate serde_derive;

use test::Bencher;

use time_steward::{DeterministicRandomId};
use time_steward::rowless::api::{PersistentTypeId, ListedType, PersistentlyIdentifiedType, StewardData, QueryOffset, DataTimelineCellTrait, Basics as BasicsTrait};
use time_steward::rowless::stewards::{simple_full as steward_module};
use steward_module::{TimeSteward, ConstructibleTimeSteward, Event, DataTimelineCell, EventAccessor, FutureCleanupAccessor, SnapshotAccessor, simple_timeline};
use simple_timeline::{SimpleTimeline, GetVarying};

#[path = "../dev-shared/bouncy_circles_rowless.rs"] mod bouncy_circles;
use bouncy_circles::*;

#[bench]
fn bouncy_circles_straightforward(bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: Steward = Steward::from_global_timeline (make_globals());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize {}).unwrap();
    // make sure to check for inefficiencies in the forgetting code
    steward.forget_before(& 0);
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
  })
}

#[bench]
fn bouncy_circles_disturbed (bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: Steward = Steward::from_global_timeline (make_globals());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize {}).unwrap();
    for index in 1..10 {
      steward.insert_fiat_event (index*SECOND/10, DeterministicRandomId::new (& index), Disturb{ coordinates: [ARENA_SIZE/3,ARENA_SIZE/3]}).unwrap();
    }
    steward.forget_before(& 0);
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
  })
}
/*
#[bench]
fn bouncy_circles_disturbed_retroactive (bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
    for index in 1..10 {
      steward.insert_fiat_event (index*SECOND/10, DeterministicRandomId::new (& index), Disturb::new ([ARENA_SIZE/3,ARENA_SIZE/3])).unwrap();
      steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
    }
  })
}
*/
<commit_msg>fixed bouncy_circles_rowless benchmarks<commit_after>#![feature (test)]

extern crate test;
#[macro_use]
extern crate time_steward;

#[macro_use]
extern crate glium;

extern crate nalgebra;
extern crate rand;
extern crate docopt;

extern crate serde;
#[macro_use]
extern crate serde_derive;

use test::Bencher;

use time_steward::{DeterministicRandomId};
use time_steward::rowless::api::{PersistentTypeId, ListedType, PersistentlyIdentifiedType, DataTimelineCellTrait, Basics as BasicsTrait};
use time_steward::rowless::stewards::{simple_full as steward_module};
use steward_module::{TimeSteward, ConstructibleTimeSteward, Event, DataTimelineCell, EventAccessor, FutureCleanupAccessor, SnapshotAccessor, simple_timeline};
use simple_timeline::{SimpleTimeline, GetVarying};

#[path = "../dev-shared/bouncy_circles_rowless.rs"] mod bouncy_circles;
use bouncy_circles::*;

#[bench]
fn bouncy_circles_straightforward(bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: Steward = Steward::from_globals (make_globals());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize {}).unwrap();
    // make sure to check for inefficiencies in the forgetting code
    steward.forget_before(& 0);
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
  })
}

#[bench]
fn bouncy_circles_disturbed (bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: Steward = Steward::from_globals (make_globals());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize {}).unwrap();
    for index in 1..10 {
      steward.insert_fiat_event (index*SECOND/10, DeterministicRandomId::new (& index), Disturb{ coordinates: [ARENA_SIZE/3,ARENA_SIZE/3]}).unwrap();
    }
    steward.forget_before(& 0);
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
  })
}
/*
#[bench]
fn bouncy_circles_disturbed_retroactive (bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
    for index in 1..10 {
      steward.insert_fiat_event (index*SECOND/10, DeterministicRandomId::new (& index), Disturb::new ([ARENA_SIZE/3,ARENA_SIZE/3])).unwrap();
      steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
    }
  })
}
*/
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};

use codec::{
    common::{async_trait::async_trait, eyre::Result},
    stencila_schema::Node,
    utils::vec_string,
    Codec, CodecTrait, DecodeOptions, EncodeOptions,
};
use codec_pandoc::{decode, encode, PandocCodec};

/// A codec for Microsoft Word (.docx) files
pub struct DocxCodec {}

#[async_trait]
impl CodecTrait for DocxCodec {
    fn spec() -> Codec {
        let pandoc_codec = PandocCodec::spec();
        Codec {
            status: "alpha".to_string(),
            formats: vec_string!["docx"],
            root_types: vec_string!["Article"],
            from_string: false,
            to_string: false,
            unsupported_types: [
                pandoc_codec.unsupported_types,
                // TODO: Fix decoding of quotes from DOCX
                vec_string!["Quote"],
            ]
            .concat(),
            ..Default::default()
        }
    }

    async fn from_path(path: &Path, _options: Option<DecodeOptions>) -> Result<Node> {
        let path = PathBuf::from(path);
        let media = [&path.to_string_lossy(), ".media"].concat();
        decode("", Some(path), "docx", &["--extract-media", &media]).await
    }

    async fn to_path(node: &Node, path: &Path, options: Option<EncodeOptions>) -> Result<()> {
        encode(
            node,
            Some(path),
            "docx",
            &[],
            Some(EncodeOptions {
                rpng_text: true,
                ..options.unwrap_or_default()
            }),
        )
        .await?;
        Ok(())
    }
}
<commit_msg>chore(DOCX codec): Do not default to `rpng_text: true`<commit_after>use std::path::{Path, PathBuf};

use codec::{
    common::{async_trait::async_trait, eyre::Result},
    stencila_schema::Node,
    utils::vec_string,
    Codec, CodecTrait, DecodeOptions, EncodeOptions,
};
use codec_pandoc::{decode, encode, PandocCodec};

/// A codec for Microsoft Word (.docx) files
pub struct DocxCodec {}

#[async_trait]
impl CodecTrait for DocxCodec {
    fn spec() -> Codec {
        let pandoc_codec = PandocCodec::spec();
        Codec {
            status: "alpha".to_string(),
            formats: vec_string!["docx"],
            root_types: vec_string!["Article"],
            from_string: false,
            to_string: false,
            unsupported_types: [
                pandoc_codec.unsupported_types,
                // TODO: Fix decoding of quotes from DOCX
                vec_string!["Quote"],
            ]
            .concat(),
            ..Default::default()
        }
    }

    async fn from_path(path: &Path, _options: Option<DecodeOptions>) -> Result<Node> {
        let path = PathBuf::from(path);
        let media = [&path.to_string_lossy(), ".media"].concat();
        decode("", Some(path), "docx", &["--extract-media", &media]).await
    }

    async fn to_path(node: &Node, path: &Path, options: Option<EncodeOptions>) -> Result<()> {
        encode(node, Some(path), "docx", &[], options).await?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>// differences between variables:
// const can be declared in any scope; must annotate type;
// RHS should computed AOT
// todo low level different?
const MAX_POINTS: u32 = 100_000;
// let y = 0;
fn main() {
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;  // this is reassign, can only contain same type
    println!("The value of x is: {}", x);
    let x = "haha"; // this is shadowing, just a new variable
    println!("The value of x is: {}", x);
}
<commit_msg>On types.<commit_after>// differences between variables:
// const can be declared in any scope; must annotate type;
// RHS should computed AOT
// todo low level different?
const MAX_POINTS: u32 = 100_000;
// let y = 0;
fn main() {
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;  // this is reassign, can only contain same type
    println!("The value of x is: {}", x);
    let x = "haha"; // this is shadowing, just a new variable
    println!("The value of x is: {}", x);

    // tuple
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    let (a, _, b) = tup;
    println!("The value of b is: {}", b);
    // let c = tup.3;

    // array: fixed length! on the stack!
    // vector: can grow/shrink size
    let months = ["January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"];
    let fst = months[0];
    println!("The value of fst is: {}", fst);
    // a warning at build time, a panic at run time!
    // let non = months[12];
}
<|endoftext|>


<commit_before>//! Search for projects by name
//!
//! https://docs.gitlab.com/ce/api/projects.html#search-for-projects-by-name
//!
//! # Search for projects by name
//!
//! Search for projects by name which are accessible to the authenticated user.
//!
//! ```text
//! GET /projects/search/QUERY
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `query` | string | yes | A string contained in the project name |
//! | `order_by` | string | no | Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields |
//! | `sort` | string | no | Return requests sorted in `asc` or `desc` order |

use serde_json;
use serde_urlencoded;

use BuildQuery;
use Projects;
use projects::{SearchProjectListerInternal, ListingOrderBy};

#[derive(Debug, Clone)]
pub struct ProjectsLister<'a> {
    gl: &'a ::GitLab,
    /// A string contained in the project name.
    query: String,
    internal: SearchProjectListerInternal,
}

impl<'a> ProjectsLister<'a> {
    pub fn new(gl: &'a ::GitLab, query: String) -> ProjectsLister {
        ProjectsLister {
            gl: gl,
            query: query,
            internal: SearchProjectListerInternal {
                order_by: None,
                sort: None,
            },
        }
    }

    pub fn order_by(&'a mut self, order_by: ListingOrderBy) -> &'a mut ProjectsLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut ProjectsLister {
        self.internal.sort = Some(sort);
        self
    }

    /// Commit the lister: Query GitLab and return a list of projects.
    pub fn list(&self) -> Projects {
        // let query = serde_urlencoded::to_string(&self);
        let query = self.build_query();
        debug!("query: {:?}", query);

        let projects: Result<Projects, serde_json::Error> = self.gl.get(&query);

        projects.unwrap()
    }
}

impl<'a> BuildQuery for ProjectsLister<'a> {
    fn build_query(&self) -> String {

        let encoded = serde_urlencoded::to_string(&self.internal).unwrap();
        let mut query = format!("projects/search/{}", self.query);
        if !encoded.is_empty() {
            query.push_str("?");
            query.push_str(&encoded);
        }
        debug!("query: {}", query);

        query
    }
}

#[cfg(test)]
mod tests {
    use BuildQuery;
    use projects::ListingOrderBy;

    const TEST_SEARCH_QUERY: &'static str = "SearchPattern";

    #[test]
    fn build_query_default() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX");
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/search/{}", TEST_SEARCH_QUERY);

        let lister = gl.projects().search(TEST_SEARCH_QUERY.to_string());
        let query = lister.build_query();
        assert_eq!(query, expected_string);
    }

//     #[test]
//     fn build_query_order_by() {
//         let expected_string = format!("projects/search/{}?order_by=id", TEST_SEARCH_QUERY);
//         let query =
//             ProjectsLister::new(TEST_SEARCH_QUERY.to_string()).order_by(ListingOrderBy::Id).build_query();
//         assert_eq!(query, expected_string);
//
//         let expected_string = format!("projects/search/{}?order_by=name", TEST_SEARCH_QUERY);
//         let query = ProjectsLister::new(TEST_SEARCH_QUERY.to_string())
//             .order_by(ListingOrderBy::Name)
//             .build_query();
//         assert_eq!(query, expected_string);
//
//         let expected_string = format!("projects/search/{}?order_by=created_at", TEST_SEARCH_QUERY);
//         let query = ProjectsLister::new(TEST_SEARCH_QUERY.to_string())
//             .order_by(ListingOrderBy::CreatedAt)
//             .build_query();
//         assert_eq!(query, expected_string);
//
//         let expected_string = format!("projects/search/{}?order_by=last_activity_at",
//                                       TEST_SEARCH_QUERY);
//         let query = ProjectsLister::new(TEST_SEARCH_QUERY.to_string())
//             .order_by(ListingOrderBy::LastActivityAt)
//             .build_query();
//         assert_eq!(query, expected_string);
//     }
//
//
//     #[test]
//     fn build_query_sort() {
//         let expected_string = format!("projects/search/{}?sort=asc", TEST_SEARCH_QUERY);
//         let query =
//             ProjectsLister::new(TEST_SEARCH_QUERY.to_string()).sort(::ListingSort::Asc).build_query();
//         assert_eq!(query, expected_string);
//
//         let expected_string = format!("projects/search/{}?sort=desc", TEST_SEARCH_QUERY);
//         let query =
//             ProjectsLister::new(TEST_SEARCH_QUERY.to_string()).sort(::ListingSort::Desc).build_query();
//         assert_eq!(query, expected_string);
//     }
//
//
//     #[test]
//     fn groups_build_query_multiple() {
//         let expected_string = format!("projects/search/{}?order_by=created_at&sort=desc",
//                                       TEST_SEARCH_QUERY);
//         let query = ProjectsLister::new(TEST_SEARCH_QUERY.to_string())
//             .order_by(ListingOrderBy::CreatedAt)
//             .sort(::ListingSort::Desc)
//             .build_query();
//         assert_eq!(query, expected_string);
//     }
}
<commit_msg>Add back unit tests for `projects::search()`<commit_after>//! Search for projects by name
//!
//! https://docs.gitlab.com/ce/api/projects.html#search-for-projects-by-name
//!
//! # Search for projects by name
//!
//! Search for projects by name which are accessible to the authenticated user.
//!
//! ```text
//! GET /projects/search/QUERY
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `query` | string | yes | A string contained in the project name |
//! | `order_by` | string | no | Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields |
//! | `sort` | string | no | Return requests sorted in `asc` or `desc` order |

use serde_json;
use serde_urlencoded;

use BuildQuery;
use Projects;
use projects::{SearchProjectListerInternal, ListingOrderBy};

#[derive(Debug, Clone)]
pub struct ProjectsLister<'a> {
    gl: &'a ::GitLab,
    /// A string contained in the project name.
    query: String,
    internal: SearchProjectListerInternal,
}

impl<'a> ProjectsLister<'a> {
    pub fn new(gl: &'a ::GitLab, query: String) -> ProjectsLister {
        ProjectsLister {
            gl: gl,
            query: query,
            internal: SearchProjectListerInternal {
                order_by: None,
                sort: None,
            },
        }
    }

    pub fn order_by(&'a mut self, order_by: ListingOrderBy) -> &'a mut ProjectsLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut ProjectsLister {
        self.internal.sort = Some(sort);
        self
    }

    /// Commit the lister: Query GitLab and return a list of projects.
    pub fn list(&self) -> Projects {
        // let query = serde_urlencoded::to_string(&self);
        let query = self.build_query();
        debug!("query: {:?}", query);

        let projects: Result<Projects, serde_json::Error> = self.gl.get(&query);

        projects.unwrap()
    }
}

impl<'a> BuildQuery for ProjectsLister<'a> {
    fn build_query(&self) -> String {

        let encoded = serde_urlencoded::to_string(&self.internal).unwrap();
        let mut query = format!("projects/search/{}", self.query);
        if !encoded.is_empty() {
            query.push_str("?");
            query.push_str(&encoded);
        }
        debug!("query: {}", query);

        query
    }
}

#[cfg(test)]
mod tests {
    use BuildQuery;
    use projects::ListingOrderBy;

    const TEST_SEARCH_QUERY: &'static str = "SearchPattern";

    #[test]
    fn build_query_default() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX");
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/search/{}", TEST_SEARCH_QUERY);

        let lister = gl.projects().search(TEST_SEARCH_QUERY.to_string());
        let query = lister.build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX");
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/search/{}?order_by=id", TEST_SEARCH_QUERY);
        let query = gl.projects()
                      .search(TEST_SEARCH_QUERY.to_string())
                      .order_by(ListingOrderBy::Id)
                      .build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/search/{}?order_by=name", TEST_SEARCH_QUERY);
        let query = gl.projects()
                      .search(TEST_SEARCH_QUERY.to_string())
                      .order_by(ListingOrderBy::Name)
                      .build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/search/{}?order_by=created_at", TEST_SEARCH_QUERY);
        let query = gl.projects()
                      .search(TEST_SEARCH_QUERY.to_string())
                      .order_by(ListingOrderBy::CreatedAt)
                      .build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/search/{}?order_by=last_activity_at",
                                      TEST_SEARCH_QUERY);
        let query = gl.projects()
                      .search(TEST_SEARCH_QUERY.to_string())
                      .order_by(ListingOrderBy::LastActivityAt)
                      .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX");
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/search/{}?sort=asc", TEST_SEARCH_QUERY);
        let query = gl.projects()
                      .search(TEST_SEARCH_QUERY.to_string())
                      .sort(::ListingSort::Asc)
                      .build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/search/{}?sort=desc", TEST_SEARCH_QUERY);
        let query = gl.projects()
                      .search(TEST_SEARCH_QUERY.to_string())
                      .sort(::ListingSort::Desc)
                      .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn groups_build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX");
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/search/{}?order_by=created_at&sort=desc",
                                      TEST_SEARCH_QUERY);
        let query = gl.projects()
                      .search(TEST_SEARCH_QUERY.to_string())
                      .order_by(ListingOrderBy::CreatedAt)
                      .sort(::ListingSort::Desc)
                      .build_query();
        assert_eq!(query, expected_string);
    }
}
<|endoftext|>


<commit_before>/// 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.

// CarbonReporter sends a message to a carbon end point at a regular basis.
use std::time::Duration;
use std::thread;
use reporter::Reporter;
use metrics::{CounterSnapshot, GaugeSnapshot, MeterSnapshot, Metric};
use histogram::Histogram;
use time;
use time::Timespec;
use std::io::Write;
use std::io::Error;
use std::sync::mpsc;
use std::net::TcpStream;
use std::collections::HashMap;

struct CarbonMetricEntry {
    metric_name: String,
    metric: Metric,
}

struct CarbonStream {
    graphite_stream: Option<TcpStream>,
    host_and_port: String,
}

// TODO perhaps we autodiscover the host and port
//
pub struct CarbonReporter {
    metrics: mpsc::Sender<Result<CarbonMetricEntry, &'static str>>,
    reporter_name: String,
    join_handle: thread::JoinHandle<Result<(), String>>,
}

impl CarbonStream {
    pub fn new<S: Into<String>>(host_and_port: S) -> Self {
        CarbonStream {
            host_and_port: host_and_port.into(),
            graphite_stream: None,
        }
    }

    pub fn connect(&mut self) -> Result<(), Error> {
        let graphite_stream = try!(TcpStream::connect(&(*self.host_and_port)));
        self.graphite_stream = Some(graphite_stream);
        Ok(())
    }

    pub fn write<S: Into<String>>(&mut self,
                                  metric_path: S,
                                  value: S,
                                  timespec: Timespec)
                                  -> Result<(), Error> {
        if self.graphite_stream.is_none() {
            try!(self.connect());
        }
        if let Some(ref mut stream) = self.graphite_stream {
            let carbon_command =
                format!("{} {} {}\n", metric_path.into(), value.into(), timespec.sec).into_bytes();
            try!(stream.write_all(&carbon_command));
        }
        Ok(())
    }
}

impl Reporter for CarbonReporter {
    fn get_unique_reporter_name(&self) -> &str {
        &self.reporter_name
    }
    fn stop(self) -> Result<thread::JoinHandle<Result<(), String>>, String> {
        match self.metrics.send(Err("stop")) {
            Ok(_) => Ok(self.join_handle),
            Err(x) => Err(format!("Unable to stop reporter {}", x)),
        }
    }
    fn addl<S: Into<String>>(&mut self,
                             name: S,
                             metric: Metric,
                             labels: Option<HashMap<String, String>>)
                             -> Result<(), String> {
        // Todo maybe do something about the labels
        match self.metrics
            .send(Ok(CarbonMetricEntry {
                metric_name: name.into(),
                metric: metric,
            })) {
            Ok(_) => Ok(()),
            Err(x) => Err(format!("Unable to send metric reporter{}", x)),
        }
    }
}

fn prefix(metric_line: String, prefix_str: &str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

fn send_meter_metric(metric_name: &str,
                     meter: MeterSnapshot,
                     carbon: &mut CarbonStream,
                     prefix_string: String,
                     ts: Timespec)
                     -> Result<(), Error> {
    let prefix_str = &(*prefix_string);

    let count = meter.count.to_string();
    let m1_rate = meter.rates[0].to_string();
    let m5_rate = meter.rates[1].to_string();
    let m15_rate = meter.rates[2].to_string();
    let mean_rate = meter.mean.to_string();
    try!(carbon.write(prefix(format!("{}.count", metric_name), prefix_str),
                      count,
                      ts));
    try!(carbon.write(prefix(format!("{}.m1", metric_name), prefix_str),
                      m1_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.m5", metric_name), prefix_str),
                      m5_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.m15", metric_name), prefix_str),
                      m15_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.mean", metric_name), prefix_str),
                      mean_rate,
                      ts));
    Ok(())
}

fn send_gauge_metric(metric_name: &str,
                     gauge: GaugeSnapshot,
                     carbon: &mut CarbonStream,
                     prefix_string: String,
                     ts: Timespec)
                     -> Result<(), Error> {
    let prefix_str = &(*prefix_string);
    try!(carbon.write(prefix(format!("{}", metric_name), prefix_str),
                      gauge.value.to_string(),
                      ts));
    Ok(())
}

fn send_counter_metric(metric_name: &str,
                       counter: CounterSnapshot,
                       carbon: &mut CarbonStream,
                       prefix_string: String,
                       ts: Timespec)
                       -> Result<(), Error> {
    let prefix_str = &(*prefix_string);
    try!(carbon.write(prefix(format!("{}", metric_name), prefix_str),
                      counter.value.to_string(),
                      ts));
    Ok(())
}
fn send_histogram_metric(metric_name: &str,
                         histogram: &Histogram,
                         carbon: &mut CarbonStream,
                         prefix_string: String,
                         ts: Timespec)
                         -> Result<(), Error> {
    let prefix_str = &(*prefix_string);
    let count = histogram.into_iter().count();
    let max = histogram.percentile(100.0).unwrap();
    let min = histogram.percentile(0.0).unwrap();

    let p50 = histogram.percentile(50.0).unwrap();
    let p75 = histogram.percentile(75.0).unwrap();
    let p95 = histogram.percentile(95.0).unwrap();
    let p98 = histogram.percentile(98.0).unwrap();
    let p99 = histogram.percentile(99.0).unwrap();
    let p999 = histogram.percentile(99.9).unwrap();
    let p9999 = histogram.percentile(99.99).unwrap();
    let p99999 = histogram.percentile(99.999).unwrap();

    try!(carbon.write(prefix(format!("{}.count", metric_name), prefix_str),
                      count.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.max", metric_name), prefix_str),
                      max.to_string(),
                      ts));

    // carbon
    // .write(prefix(format!("{}.mean", metric_name), prefix_str),
    // mean.into_string(),
    // ts);

    try!(carbon.write(prefix(format!("{}.min", metric_name), prefix_str),
                      min.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p50", metric_name), prefix_str),
                      p50.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p75", metric_name), prefix_str),
                      p75.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p95", metric_name), prefix_str),
                      p95.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p98", metric_name), prefix_str),
                      p98.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p99", metric_name), prefix_str),
                      p99.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p999", metric_name), prefix_str),
                      p999.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p9999", metric_name), prefix_str),
                      p9999.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p99999", metric_name), prefix_str),
                      p99999.to_string(),
                      ts));
    Ok(())
}

impl CarbonReporter {
    pub fn new<S1: Into<String>, S2: Into<String>, S3: Into<String>>(reporter_name: S1,
                                                                     host_and_port: S2,
                                                                     prefix: S3,
                                                                     aggregation_timer: u64)
                                                                     -> Self {
        let (tx, rx) = mpsc::channel();
        let hp = host_and_port.into();
        let pr = prefix.into();
        let rn = reporter_name.into();

        CarbonReporter {
            metrics: tx,
            reporter_name: rn.clone(),
            join_handle: report_to_carbon_continuously(pr, hp, aggregation_timer, rx),
        }
    }
}
fn report_to_carbon_continuously(prefix: String,
                                 host_and_port: String,
                                 delay_ms: u64,
                                 rx: mpsc::Receiver<Result<CarbonMetricEntry, &'static str>>)
                                 -> thread::JoinHandle<Result<(), String>> {
    thread::spawn(move || {
        let mut carbon = CarbonStream::new(host_and_port);
        let mut stop = false;
        let mut metrics = vec!();

        while !stop {
            while let Ok(msg) = rx.try_recv() {
                match msg {
                    Ok(metric) => metrics.push(metric),
                    Err(_) => stop = true,
                }
            }
            let ts = time::get_time();
            let delay_ms = delay_ms as i64;
            let next_tick_ms = (ts.sec * 1000 / delay_ms + 1) * delay_ms;
            let next_tick = Timespec {
                sec: (next_tick_ms / 1000),
                nsec: ((next_tick_ms % 1000) * 1_000_000) as i32,
            };
            thread::sleep((next_tick - time::get_time()).to_std().unwrap());
            for entry in &metrics {
                let metric_name = &entry.metric_name;
                let metric = &entry.metric;
                // Maybe one day we can do more to handle this failure
                match *metric {
                    Metric::Meter(ref x) => {
                        send_meter_metric(metric_name,
                                          x.snapshot(),
                                          &mut carbon,
                                          prefix.clone(),
                                          ts)
                    }
                    Metric::Gauge(ref x) => {
                        send_gauge_metric(metric_name,
                                          x.snapshot(),
                                          &mut carbon,
                                          prefix.clone(),
                                          ts)
                    }
                    Metric::Counter(ref x) => {
                        send_counter_metric(metric_name,
                                            x.snapshot(),
                                            &mut carbon,
                                            prefix.clone(),
                                            ts)
                    }
                    Metric::Histogram(ref x) => {
                        send_histogram_metric(metric_name,
                                              &x,
                                              &mut carbon,
                                              prefix.clone(),
                                              ts)
                    }
                };
            }
        }
        Ok(())
    })
}

#[cfg(test)]
mod test {
    use histogram::Histogram;
    use metrics::{Counter, Gauge, Meter, Metric, StdCounter, StdGauge, StdMeter};
    use std::net::TcpListener;
    use super::CarbonReporter;
    use reporter::Reporter;

    #[test]
    fn meter() {
        let m = StdMeter::new();
        m.mark(100);

        let c = StdCounter::new();
        c.inc();

        let g = StdGauge::new();
        g.set(2);

        let mut h = Histogram::configure()
            .max_value(100)
            .precision(1)
            .build()
            .unwrap();

        h.increment_by(1, 1).unwrap();

        let test_port = "127.0.0.1:34254";
        let listener = TcpListener::bind(test_port).unwrap();
        let mut reporter = CarbonReporter::new("test", test_port, "asd.asdf", 1024);
        reporter.add("meter1", Metric::Meter(m.clone()));
        reporter.add("counter1", Metric::Counter(c.clone()));
        reporter.add("gauge1", Metric::Gauge(g.clone()));
        reporter.add("histogram", Metric::Histogram(h));
        reporter.stop().unwrap().join().unwrap().unwrap();
    }
}
<commit_msg>fix a heisenbug when delay_ms is not an integer number of second<commit_after>/// 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.

// CarbonReporter sends a message to a carbon end point at a regular basis.
use std::time::Duration;
use std::thread;
use reporter::Reporter;
use metrics::{CounterSnapshot, GaugeSnapshot, MeterSnapshot, Metric};
use histogram::Histogram;
use time;
use time::Timespec;
use std::io::Write;
use std::io::Error;
use std::sync::mpsc;
use std::net::TcpStream;
use std::collections::HashMap;

struct CarbonMetricEntry {
    metric_name: String,
    metric: Metric,
}

struct CarbonStream {
    graphite_stream: Option<TcpStream>,
    host_and_port: String,
}

// TODO perhaps we autodiscover the host and port
//
pub struct CarbonReporter {
    metrics: mpsc::Sender<Result<CarbonMetricEntry, &'static str>>,
    reporter_name: String,
    join_handle: thread::JoinHandle<Result<(), String>>,
}

impl CarbonStream {
    pub fn new<S: Into<String>>(host_and_port: S) -> Self {
        CarbonStream {
            host_and_port: host_and_port.into(),
            graphite_stream: None,
        }
    }

    pub fn connect(&mut self) -> Result<(), Error> {
        let graphite_stream = try!(TcpStream::connect(&(*self.host_and_port)));
        self.graphite_stream = Some(graphite_stream);
        Ok(())
    }

    pub fn write<S: Into<String>>(&mut self,
                                  metric_path: S,
                                  value: S,
                                  timespec: Timespec)
                                  -> Result<(), Error> {
        if self.graphite_stream.is_none() {
            try!(self.connect());
        }
        if let Some(ref mut stream) = self.graphite_stream {
            let carbon_command =
                format!("{} {} {}\n", metric_path.into(), value.into(), timespec.sec).into_bytes();
            try!(stream.write_all(&carbon_command));
        }
        Ok(())
    }
}

impl Reporter for CarbonReporter {
    fn get_unique_reporter_name(&self) -> &str {
        &self.reporter_name
    }
    fn stop(self) -> Result<thread::JoinHandle<Result<(), String>>, String> {
        match self.metrics.send(Err("stop")) {
            Ok(_) => Ok(self.join_handle),
            Err(x) => Err(format!("Unable to stop reporter {}", x)),
        }
    }
    fn addl<S: Into<String>>(&mut self,
                             name: S,
                             metric: Metric,
                             labels: Option<HashMap<String, String>>)
                             -> Result<(), String> {
        // Todo maybe do something about the labels
        match self.metrics
            .send(Ok(CarbonMetricEntry {
                metric_name: name.into(),
                metric: metric,
            })) {
            Ok(_) => Ok(()),
            Err(x) => Err(format!("Unable to send metric reporter{}", x)),
        }
    }
}

fn prefix(metric_line: String, prefix_str: &str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

fn send_meter_metric(metric_name: &str,
                     meter: MeterSnapshot,
                     carbon: &mut CarbonStream,
                     prefix_string: String,
                     ts: Timespec)
                     -> Result<(), Error> {
    let prefix_str = &(*prefix_string);

    let count = meter.count.to_string();
    let m1_rate = meter.rates[0].to_string();
    let m5_rate = meter.rates[1].to_string();
    let m15_rate = meter.rates[2].to_string();
    let mean_rate = meter.mean.to_string();
    try!(carbon.write(prefix(format!("{}.count", metric_name), prefix_str),
                      count,
                      ts));
    try!(carbon.write(prefix(format!("{}.m1", metric_name), prefix_str),
                      m1_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.m5", metric_name), prefix_str),
                      m5_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.m15", metric_name), prefix_str),
                      m15_rate,
                      ts));
    try!(carbon.write(prefix(format!("{}.mean", metric_name), prefix_str),
                      mean_rate,
                      ts));
    Ok(())
}

fn send_gauge_metric(metric_name: &str,
                     gauge: GaugeSnapshot,
                     carbon: &mut CarbonStream,
                     prefix_string: String,
                     ts: Timespec)
                     -> Result<(), Error> {
    let prefix_str = &(*prefix_string);
    try!(carbon.write(prefix(format!("{}", metric_name), prefix_str),
                      gauge.value.to_string(),
                      ts));
    Ok(())
}

fn send_counter_metric(metric_name: &str,
                       counter: CounterSnapshot,
                       carbon: &mut CarbonStream,
                       prefix_string: String,
                       ts: Timespec)
                       -> Result<(), Error> {
    let prefix_str = &(*prefix_string);
    try!(carbon.write(prefix(format!("{}", metric_name), prefix_str),
                      counter.value.to_string(),
                      ts));
    Ok(())
}
fn send_histogram_metric(metric_name: &str,
                         histogram: &Histogram,
                         carbon: &mut CarbonStream,
                         prefix_string: String,
                         ts: Timespec)
                         -> Result<(), Error> {
    let prefix_str = &(*prefix_string);
    let count = histogram.into_iter().count();
    let max = histogram.percentile(100.0).unwrap();
    let min = histogram.percentile(0.0).unwrap();

    let p50 = histogram.percentile(50.0).unwrap();
    let p75 = histogram.percentile(75.0).unwrap();
    let p95 = histogram.percentile(95.0).unwrap();
    let p98 = histogram.percentile(98.0).unwrap();
    let p99 = histogram.percentile(99.0).unwrap();
    let p999 = histogram.percentile(99.9).unwrap();
    let p9999 = histogram.percentile(99.99).unwrap();
    let p99999 = histogram.percentile(99.999).unwrap();

    try!(carbon.write(prefix(format!("{}.count", metric_name), prefix_str),
                      count.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.max", metric_name), prefix_str),
                      max.to_string(),
                      ts));

    // carbon
    // .write(prefix(format!("{}.mean", metric_name), prefix_str),
    // mean.into_string(),
    // ts);

    try!(carbon.write(prefix(format!("{}.min", metric_name), prefix_str),
                      min.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p50", metric_name), prefix_str),
                      p50.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p75", metric_name), prefix_str),
                      p75.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p95", metric_name), prefix_str),
                      p95.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p98", metric_name), prefix_str),
                      p98.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p99", metric_name), prefix_str),
                      p99.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p999", metric_name), prefix_str),
                      p999.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p9999", metric_name), prefix_str),
                      p9999.to_string(),
                      ts));

    try!(carbon.write(prefix(format!("{}.p99999", metric_name), prefix_str),
                      p99999.to_string(),
                      ts));
    Ok(())
}

impl CarbonReporter {
    pub fn new<S1: Into<String>, S2: Into<String>, S3: Into<String>>(reporter_name: S1,
                                                                     host_and_port: S2,
                                                                     prefix: S3,
                                                                     aggregation_timer: u64)
                                                                     -> Self {
        let (tx, rx) = mpsc::channel();
        let hp = host_and_port.into();
        let pr = prefix.into();
        let rn = reporter_name.into();

        CarbonReporter {
            metrics: tx,
            reporter_name: rn.clone(),
            join_handle: report_to_carbon_continuously(pr, hp, aggregation_timer, rx),
        }
    }
}
fn report_to_carbon_continuously(prefix: String,
                                 host_and_port: String,
                                 delay_ms: u64,
                                 rx: mpsc::Receiver<Result<CarbonMetricEntry, &'static str>>)
                                 -> thread::JoinHandle<Result<(), String>> {
    thread::spawn(move || {
        let mut carbon = CarbonStream::new(host_and_port);
        let mut stop = false;
        let mut metrics = vec!();

        while !stop {
            while let Ok(msg) = rx.try_recv() {
                match msg {
                    Ok(metric) => metrics.push(metric),
                    Err(_) => stop = true,
                }
            }
            let ts = time::get_time();
            let delay_ms = delay_ms as i64;
            let next_tick_ms = ((ts.sec * 1000 + ts.nsec as i64 / 1_000_000)/ delay_ms + 1) * delay_ms;
            let next_tick = Timespec {
                sec: (next_tick_ms / 1000),
                nsec: ((next_tick_ms % 1000) * 1_000_000) as i32,
            };
            thread::sleep((next_tick - ts).to_std().unwrap());
            for entry in &metrics {
                let metric_name = &entry.metric_name;
                let metric = &entry.metric;
                // Maybe one day we can do more to handle this failure
                match *metric {
                    Metric::Meter(ref x) => {
                        send_meter_metric(metric_name,
                                          x.snapshot(),
                                          &mut carbon,
                                          prefix.clone(),
                                          ts)
                    }
                    Metric::Gauge(ref x) => {
                        send_gauge_metric(metric_name,
                                          x.snapshot(),
                                          &mut carbon,
                                          prefix.clone(),
                                          ts)
                    }
                    Metric::Counter(ref x) => {
                        send_counter_metric(metric_name,
                                            x.snapshot(),
                                            &mut carbon,
                                            prefix.clone(),
                                            ts)
                    }
                    Metric::Histogram(ref x) => {
                        send_histogram_metric(metric_name,
                                              &x,
                                              &mut carbon,
                                              prefix.clone(),
                                              ts)
                    }
                };
            }
        }
        Ok(())
    })
}

#[cfg(test)]
mod test {
    use histogram::Histogram;
    use metrics::{Counter, Gauge, Meter, Metric, StdCounter, StdGauge, StdMeter};
    use std::net::TcpListener;
    use super::CarbonReporter;
    use reporter::Reporter;

    #[test]
    fn meter() {
        let m = StdMeter::new();
        m.mark(100);

        let c = StdCounter::new();
        c.inc();

        let g = StdGauge::new();
        g.set(2);

        let mut h = Histogram::configure()
            .max_value(100)
            .precision(1)
            .build()
            .unwrap();

        h.increment_by(1, 1).unwrap();

        let test_port = "127.0.0.1:34254";
        let listener = TcpListener::bind(test_port).unwrap();
        let mut reporter = CarbonReporter::new("test", test_port, "asd.asdf", 1024);
        reporter.add("meter1", Metric::Meter(m.clone()));
        reporter.add("counter1", Metric::Counter(c.clone()));
        reporter.add("gauge1", Metric::Gauge(g.clone()));
        reporter.add("histogram", Metric::Histogram(h));
        reporter.stop().unwrap().join().unwrap().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate gigasecond;

/*
 * Students,
 *
 * Rust does not currently have a library for handling Time. To solve this exercise
 * you'll need to use the Chrono 'crate' (which is Rust's term for an external library).
 *
 * The first time you run `cargo test`, the Chrono crate will automatically be downloaded
 * and installed. More information on crates can be found at
 * https://doc.rust-lang.org/book/guessing-game.html#generating-a-secret-number
 *
 * In order to use the crate, your solution will need to start with the two following lines
*/
extern crate chrono;
use chrono::*;

#[test]
fn test_date() {
    let start_date = Utc.ymd(2011, 4, 25).and_hms(0,0,0);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(2043, 1, 1).and_hms(1,46,40));
}

#[test]
#[ignore]
fn test_another_date() {
    let start_date = Utc.ymd(1977, 6, 13).and_hms(0,0,0);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(2009, 2, 19).and_hms(1,46,40));
}

#[test]
#[ignore]
fn test_third_date() {
    let start_date = Utc.ymd(1959, 7, 19).and_hms(0,0,0);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(1991, 3, 27).and_hms(1,46,40));
}

#[test]
#[ignore]
fn test_datetime() {
    let start_date = Utc.ymd(2015, 1, 24).and_hms(22,0,0);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(2046, 10, 2).and_hms(23,46,40));
}

#[test]
#[ignore]
fn test_another_datetime() {
    let start_date = Utc.ymd(2015, 1, 24).and_hms(23,59,59);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(2046, 10, 3).and_hms(1,46,39));
}
<commit_msg>gigasecond: link to second edition of Rust book (#357)<commit_after>extern crate gigasecond;

/*
 * Students,
 *
 * Rust does not currently have a library for handling Time. To solve this exercise
 * you'll need to use the Chrono 'crate' (which is Rust's term for an external library).
 *
 * The first time you run `cargo test`, the Chrono crate will automatically be downloaded
 * and installed. More information on crates can be found at
 * https://doc.rust-lang.org/book/second-edition/ch02-00-guessing-game-tutorial.html#generating-a-random-number
 *
 * In order to use the crate, your solution will need to start with the two following lines
*/
extern crate chrono;
use chrono::*;

#[test]
fn test_date() {
    let start_date = Utc.ymd(2011, 4, 25).and_hms(0,0,0);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(2043, 1, 1).and_hms(1,46,40));
}

#[test]
#[ignore]
fn test_another_date() {
    let start_date = Utc.ymd(1977, 6, 13).and_hms(0,0,0);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(2009, 2, 19).and_hms(1,46,40));
}

#[test]
#[ignore]
fn test_third_date() {
    let start_date = Utc.ymd(1959, 7, 19).and_hms(0,0,0);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(1991, 3, 27).and_hms(1,46,40));
}

#[test]
#[ignore]
fn test_datetime() {
    let start_date = Utc.ymd(2015, 1, 24).and_hms(22,0,0);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(2046, 10, 2).and_hms(23,46,40));
}

#[test]
#[ignore]
fn test_another_datetime() {
    let start_date = Utc.ymd(2015, 1, 24).and_hms(23,59,59);
    assert_eq!(gigasecond::after(start_date), Utc.ymd(2046, 10, 3).and_hms(1,46,39));
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use utils::slice_str;

#[derive(Debug, Clone, Copy)]
pub struct Match{
	first_start: usize,
	second_start: usize,
	size: usize
}

impl Ord for Match {
    fn cmp(&self, other: &Match) -> Ordering {
        self.size.cmp(&other.size)
    }
}

impl PartialOrd for Match {
    fn partial_cmp(&self, other: &Match) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

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

impl Eq for Match { }

pub struct SequenceMatcher<'a>{
	first_sequence: &'a str,
	second_sequence: &'a str,
	matching_blocks: Option<Vec<Match>>
}

impl<'a> SequenceMatcher<'a>{
	pub fn new(first_sequence: &'a str, second_sequence: &'a str) -> SequenceMatcher<'a>
	{
		SequenceMatcher{
			first_sequence: first_sequence,
			second_sequence: second_sequence,
			matching_blocks: None
		}
	}

	pub fn find_longest_match(&self, first_start: usize, first_end: usize, second_start: usize, second_end: usize) -> Option<Match>
	{
		let first_sequence: Vec<char> = slice_str(self.first_sequence, first_start, first_end).unwrap_or("").chars().collect();
		let second_sequence: Vec<char> = slice_str(self.second_sequence, second_start, second_end).unwrap_or("").chars().collect();
		let mut max_i = 0;
		let mut max_j = 0;
		let mut arr: Vec<Vec<usize>> = vec![vec![0; second_sequence.len() + 1]; first_sequence.len() + 1];
		for i in 0..first_sequence.len(){
			for j in 0..second_sequence.len(){
				if first_sequence[i] == second_sequence[j]{
					arr[i + 1][j + 1] = arr[i][j] + 1;
					if arr[i + 1][j + 1] > arr[max_i][max_j] {
                        max_i = i + 1;
                        max_j = j + 1;
                   }
				}
			}
		}
		if max_i == 0 && max_j == 0{
			return None
		}
		else{
			let size = arr[max_i][max_j];
			Some(Match{
				first_start: max_i - size + first_start,
				second_start: max_j - size + second_start,
				size: size
			})
		}
	}

	pub fn get_matching_blocks(&mut self) -> Vec<Match>
	{
		if self.matching_blocks.as_ref().is_some(){
            return self.matching_blocks.as_ref().unwrap().clone()
		}
		let (first_length, second_length) = (self.first_sequence.len(), self.second_sequence.len());
		let mut matches = Vec::new();
		let mut queue = vec![(0, first_length, 0, second_length)];
		while !queue.is_empty(){
			let (first_start, first_end, second_start, second_end) = queue.pop().unwrap();
			let m = self.find_longest_match(first_start, first_end, second_start, second_end);
			match m {
			    Some(m) => {
			    	if first_start < m.first_start && second_start < m.second_start{
			    		queue.push((first_start, m.first_start, second_start, m.second_start));
			    	}
			    	if m.first_start + m.size < first_end && m.second_start + m.size < second_end{
			    		queue.push((m.first_start + m.size, first_end, m.second_start + m.size, second_end));
			    	}
			    	matches.push(m);
			    },
			    None => {},
			}
		}
		matches.sort_by(|a, b| a.cmp(b));
		let (mut first_start, mut second_start, mut size) = (0, 0, 0);
		let mut non_adjacent = Vec::new();
		for m in &matches{
			if first_start + size == m.first_start && second_start + size == m.second_start{
				size += m.size
			}
			else {
			    if size != 0{
			    	non_adjacent.push(m.clone());
			    }
			    first_start = m.first_start;
			    second_start = m.second_start;
			    size = m.size;
			}
		}
		self.matching_blocks = Some(non_adjacent);
		self.matching_blocks.as_ref().unwrap().clone()
	}
}<commit_msg>Fix bug with last match in get_matching_blocks. Add opcodes<commit_after>use std::cmp::Ordering;
use utils::slice_str;

#[derive(Debug, Clone, Copy)]
pub struct Match{
	first_start: usize,
	second_start: usize,
	size: usize
}

impl Ord for Match {
    fn cmp(&self, other: &Match) -> Ordering {
        self.size.cmp(&other.size)
    }
}

impl PartialOrd for Match {
    fn partial_cmp(&self, other: &Match) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

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

impl Eq for Match { }

impl Match{
	fn new(first_start: usize, second_start: usize, size: usize) -> Match {
		Match{
			first_start: first_start,
			second_start: second_start,
			size: size
		}
	}
}

pub struct SequenceMatcher<'a>{
	first_sequence: &'a str,
	second_sequence: &'a str,
	matching_blocks: Option<Vec<Match>>,
	opcodes: Option<Vec<(String, usize, usize, usize, usize)>>
}

impl<'a> SequenceMatcher<'a>{
	pub fn new(first_sequence: &'a str, second_sequence: &'a str) -> SequenceMatcher<'a> {
		SequenceMatcher{
			first_sequence: first_sequence,
			second_sequence: second_sequence,
			matching_blocks: None,
			opcodes: None
		}
	}

	pub fn find_longest_match(&self, first_start: usize, first_end: usize, second_start: usize, second_end: usize) -> Option<Match> {
		let first_sequence: Vec<char> = slice_str(self.first_sequence, first_start, first_end).unwrap_or("").chars().collect();
		let second_sequence: Vec<char> = slice_str(self.second_sequence, second_start, second_end).unwrap_or("").chars().collect();
		let mut max_i = 0;
		let mut max_j = 0;
		let mut arr: Vec<Vec<usize>> = vec![vec![0; second_sequence.len() + 1]; first_sequence.len() + 1];
		for i in 0..first_sequence.len(){
			for j in 0..second_sequence.len(){
				if first_sequence[i] == second_sequence[j]{
					arr[i + 1][j + 1] = arr[i][j] + 1;
					if arr[i + 1][j + 1] > arr[max_i][max_j] {
                        max_i = i + 1;
                        max_j = j + 1;
                   }
				}
			}
		}
		if max_i == 0 && max_j == 0{
			return None
		}
		else{
			let size = arr[max_i][max_j];
			Some(Match{
				first_start: max_i - size + first_start,
				second_start: max_j - size + second_start,
				size: size
			})
		}
	}

	pub fn get_matching_blocks(&mut self) -> Vec<Match> {
		if self.matching_blocks.as_ref().is_some(){
            return self.matching_blocks.as_ref().unwrap().clone()
		}
		let (first_length, second_length) = (self.first_sequence.len(), self.second_sequence.len());
		let mut matches = Vec::new();
		let mut queue = vec![(0, first_length, 0, second_length)];
		while !queue.is_empty(){
			let (first_start, first_end, second_start, second_end) = queue.pop().unwrap();
			let m = self.find_longest_match(first_start, first_end, second_start, second_end);
			match m {
			    Some(m) => {
			    	if first_start < m.first_start && second_start < m.second_start{
			    		queue.push((first_start, m.first_start, second_start, m.second_start));
			    	}
			    	if m.first_start + m.size < first_end && m.second_start + m.size < second_end{
			    		queue.push((m.first_start + m.size, first_end, m.second_start + m.size, second_end));
			    	}
			    	matches.push(m);
			    },
			    None => {},
			}
		}
		matches.sort_by(|a, b| b.cmp(a));
		let (mut first_start, mut second_start, mut size) = (0, 0, 0);
		let mut non_adjacent = Vec::new();
		for m in &matches{
			if first_start + size == m.first_start && second_start + size == m.second_start{
				size += m.size
			}
			else {
			    if size != 0{
			    	non_adjacent.push(Match::new(first_start, second_start, size));
			    }
			    first_start = m.first_start;
			    second_start = m.second_start;
			    size = m.size;
			}
		}
		if size != 0{
			non_adjacent.push(Match::new(first_start, second_start, size));
		}
		non_adjacent.push(Match::new(first_length, second_length, 0));
		self.matching_blocks = Some(non_adjacent);
		self.matching_blocks.as_ref().unwrap().clone()
	}

	pub fn get_opcodes(&mut self) -> Vec<(String, usize, usize, usize, usize)>{
		if self.opcodes.as_ref().is_some(){
            return self.opcodes.as_ref().unwrap().clone()
		}
		let mut opcodes = Vec::new();
		let (mut i, mut j) = (0, 0);
		for m in self.get_matching_blocks(){
			let mut tag = String::new();
			if i < m.first_start && j < m.second_start{
				tag = String::from("replace");
			}
			else if i < m.first_start{
				tag = String::from("delete");
			}
			else if j < m.second_start{
				tag = String::from("insert");
			}
			if !tag.is_empty(){
				opcodes.push( (tag, i, m.first_start, j, m.second_start) );
			}
			i = m.first_start + m.size;
			j = m.second_start + m.size;
			if m.size != 0{
				opcodes.push( (String::from("equal"), m.first_start, i, m.second_start, j) );
			}
		}
		self.opcodes = Some(opcodes);
		return self.opcodes.as_ref().unwrap().clone()
	}
}<|endoftext|>