<commit_before>//! Tracing and profiling functions. Error and warning log.

use libc::{c_char, c_int, c_void};
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::str;

use super::ffi;
use {SqliteError, SqliteResult, SqliteConnection};

/// Set up the process-wide SQLite error logging callback.
/// This function is marked unsafe for two reasons:
///
/// * The function is not threadsafe. No other SQLite calls may be made while
///   `config_log` is running, and multiple threads may not call `config_log`
///   simultaneously.
/// * The provided `callback` itself function has two requirements:
///     * It must not invoke any SQLite calls.
///     * It must be threadsafe if SQLite is used in a multithreaded way.
///
/// cf [The Error And Warning Log](http://sqlite.org/errlog.html).
pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> SqliteResult<()> {
    extern "C" fn log_callback(p_arg: *mut c_void, err: c_int, msg: *const c_char) {
        let c_slice = unsafe { CStr::from_ptr(msg).to_bytes() };
        let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) };

        if let Ok(s) = str::from_utf8(c_slice) {
            callback(err, s);
        }
    }

    let rc = match callback {
        Some(f) => {
            let p_arg: *mut c_void = mem::transmute(f);
            ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, Some(log_callback), p_arg)
        },
        None => {
            let nullptr: *mut c_void = ptr::null_mut();
            ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr)
        }
    };

    if rc != ffi::SQLITE_OK {
        return Err(SqliteError{ code: rc, message: "sqlite3_config(SQLITE_CONFIG_LOG, ...)".to_string() });
    }

    Ok(())
}

/// Write a message into the error log established by `config_log`.
pub fn log(err_code: c_int, msg: &str) {
    let msg = CString::new(msg).expect("SQLite log messages cannot contain embedded zeroes");
    unsafe {
        ffi::sqlite3_log(err_code, msg.as_ptr());
    }
}

/// The profile callback function signature.
pub type ProfileCallback =
    Option<extern "C" fn (p_arg: *mut c_void, z_sql: *const c_char, nanoseconds: u64)>;

impl SqliteConnection {
    /// Register or clear a callback function that can be used for tracing the execution of SQL statements.
    ///
    /// Prepared statement placeholders are replaced/logged with their assigned values.
    /// There can only be a single tracer defined for each database connection.
    /// Setting a new tracer clears the old one.
    pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
        extern "C" fn trace_callback (p_arg: *mut c_void, z_sql: *const c_char) {
            let trace_fn: fn(&str) = unsafe { mem::transmute(p_arg) };
            let c_slice = unsafe { CStr::from_ptr(z_sql).to_bytes() };
            if let Ok(s) = str::from_utf8(c_slice) {
                trace_fn(s);
            }
        }

        let c = self.db.borrow_mut();
        match trace_fn {
            Some(f) => unsafe { ffi::sqlite3_trace(c.db(), Some(trace_callback), mem::transmute(f)); },
            None    => unsafe { ffi::sqlite3_trace(c.db(), None, ptr::null_mut()); },
        }
    }

    /// Register or clear a callback function that can be used for profiling the execution of SQL statements.
    ///
    /// There can only be a single profiler defined for each database connection.
    /// Setting a new profiler clears the old one.
    pub fn profile(&mut self, x_profile: ProfileCallback) {
        let c = self.db.borrow_mut();
        unsafe { ffi::sqlite3_profile(c.db(), x_profile, ptr::null_mut()); }
    }
}

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

    use SqliteConnection;

    #[test]
    fn test_trace() {
        lazy_static! {
            static ref TRACED_STMTS: Mutex<Vec<String>> = Mutex::new(Vec::new());
        }
        fn tracer(s: &str) {
            let mut traced_stmts = TRACED_STMTS.lock().unwrap();
            traced_stmts.push(s.to_owned());
        }

        let mut db = SqliteConnection::open_in_memory().unwrap();
        db.trace(Some(tracer));
        {
            let _ = db.query_row("SELECT ?", &[&1i32], |_| {});
            let _ = db.query_row("SELECT ?", &[&"hello"], |_| {});
        }
        db.trace(None);
        {
            let _ = db.query_row("SELECT ?", &[&2i32], |_| {});
            let _ = db.query_row("SELECT ?", &[&"goodbye"], |_| {});
        }

        let traced_stmts = TRACED_STMTS.lock().unwrap();
        assert_eq!(traced_stmts.len(), 2);
        assert_eq!(traced_stmts[0], "SELECT 1");
        assert_eq!(traced_stmts[1], "SELECT 'hello'");
    }

    extern "C" fn profile_callback(_: *mut ::libc::c_void, sql: *const ::libc::c_char, nanoseconds: u64) {
        use std::time::Duration;
        unsafe {
            let c_slice = ::std::ffi::CStr::from_ptr(sql).to_bytes();
            let d = Duration::from_millis(nanoseconds / 1_000_000);
            let _ = writeln!(::std::io::stderr(), "PROFILE: {:?} ({:?})", ::std::str::from_utf8(c_slice), d);
        }
    }

    #[test]
    fn test_profile() {
        let mut db = SqliteConnection::open_in_memory().unwrap();
        db.profile(Some(profile_callback));
        db.execute_batch("PRAGMA application_id = 1").unwrap();
    }
}
<commit_msg>Change profile() to take a Rust fn instead of an extern "C" fn.<commit_after>//! Tracing and profiling functions. Error and warning log.

use libc::{c_char, c_int, c_void};
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::str;
use std::time::Duration;

use super::ffi;
use {SqliteError, SqliteResult, SqliteConnection};

/// Set up the process-wide SQLite error logging callback.
/// This function is marked unsafe for two reasons:
///
/// * The function is not threadsafe. No other SQLite calls may be made while
///   `config_log` is running, and multiple threads may not call `config_log`
///   simultaneously.
/// * The provided `callback` itself function has two requirements:
///     * It must not invoke any SQLite calls.
///     * It must be threadsafe if SQLite is used in a multithreaded way.
///
/// cf [The Error And Warning Log](http://sqlite.org/errlog.html).
pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> SqliteResult<()> {
    extern "C" fn log_callback(p_arg: *mut c_void, err: c_int, msg: *const c_char) {
        let c_slice = unsafe { CStr::from_ptr(msg).to_bytes() };
        let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) };

        if let Ok(s) = str::from_utf8(c_slice) {
            callback(err, s);
        }
    }

    let rc = match callback {
        Some(f) => {
            let p_arg: *mut c_void = mem::transmute(f);
            ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, Some(log_callback), p_arg)
        },
        None => {
            let nullptr: *mut c_void = ptr::null_mut();
            ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr)
        }
    };

    if rc != ffi::SQLITE_OK {
        return Err(SqliteError{ code: rc, message: "sqlite3_config(SQLITE_CONFIG_LOG, ...)".to_string() });
    }

    Ok(())
}

/// Write a message into the error log established by `config_log`.
pub fn log(err_code: c_int, msg: &str) {
    let msg = CString::new(msg).expect("SQLite log messages cannot contain embedded zeroes");
    unsafe {
        ffi::sqlite3_log(err_code, msg.as_ptr());
    }
}

impl SqliteConnection {
    /// Register or clear a callback function that can be used for tracing the execution of SQL statements.
    ///
    /// Prepared statement placeholders are replaced/logged with their assigned values.
    /// There can only be a single tracer defined for each database connection.
    /// Setting a new tracer clears the old one.
    pub fn trace(&mut self, trace_fn: Option<fn(&str)>) {
        extern "C" fn trace_callback (p_arg: *mut c_void, z_sql: *const c_char) {
            let trace_fn: fn(&str) = unsafe { mem::transmute(p_arg) };
            let c_slice = unsafe { CStr::from_ptr(z_sql).to_bytes() };
            if let Ok(s) = str::from_utf8(c_slice) {
                trace_fn(s);
            }
        }

        let c = self.db.borrow_mut();
        match trace_fn {
            Some(f) => unsafe { ffi::sqlite3_trace(c.db(), Some(trace_callback), mem::transmute(f)); },
            None    => unsafe { ffi::sqlite3_trace(c.db(), None, ptr::null_mut()); },
        }
    }

    /// Register or clear a callback function that can be used for profiling the execution of SQL statements.
    ///
    /// There can only be a single profiler defined for each database connection.
    /// Setting a new profiler clears the old one.
    pub fn profile(&mut self, profile_fn: Option<fn(&str, Duration)>) {
        extern "C" fn profile_callback(p_arg: *mut c_void, z_sql: *const c_char, nanoseconds: u64) {
            let profile_fn: fn(&str, Duration) = unsafe { mem::transmute(p_arg) };
            let c_slice = unsafe { CStr::from_ptr(z_sql).to_bytes() };
            if let Ok(s) = str::from_utf8(c_slice) {
                const NANOS_PER_SEC: u64 = 1_000_000_000;

                let duration = Duration::new(nanoseconds / NANOS_PER_SEC,
                                             (nanoseconds % NANOS_PER_SEC) as u32);
                profile_fn(s, duration);
            }
        }

        let c = self.db.borrow_mut();
        match profile_fn {
            Some(f) => unsafe { ffi::sqlite3_profile(c.db(), Some(profile_callback), mem::transmute(f)) },
            None    => unsafe { ffi::sqlite3_profile(c.db(), None, ptr::null_mut()) },
        };
    }
}

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

    use SqliteConnection;

    #[test]
    fn test_trace() {
        lazy_static! {
            static ref TRACED_STMTS: Mutex<Vec<String>> = Mutex::new(Vec::new());
        }
        fn tracer(s: &str) {
            let mut traced_stmts = TRACED_STMTS.lock().unwrap();
            traced_stmts.push(s.to_owned());
        }

        let mut db = SqliteConnection::open_in_memory().unwrap();
        db.trace(Some(tracer));
        {
            let _ = db.query_row("SELECT ?", &[&1i32], |_| {});
            let _ = db.query_row("SELECT ?", &[&"hello"], |_| {});
        }
        db.trace(None);
        {
            let _ = db.query_row("SELECT ?", &[&2i32], |_| {});
            let _ = db.query_row("SELECT ?", &[&"goodbye"], |_| {});
        }

        let traced_stmts = TRACED_STMTS.lock().unwrap();
        assert_eq!(traced_stmts.len(), 2);
        assert_eq!(traced_stmts[0], "SELECT 1");
        assert_eq!(traced_stmts[1], "SELECT 'hello'");
    }

    #[test]
    fn test_profile() {
        lazy_static! {
            static ref PROFILED: Mutex<Vec<(String, Duration)>> = Mutex::new(Vec::new());
        }
        fn profiler(s: &str, d: Duration) {
            let mut profiled = PROFILED.lock().unwrap();
            profiled.push((s.to_owned(), d));
        }

        let mut db = SqliteConnection::open_in_memory().unwrap();
        db.profile(Some(profiler));
        db.execute_batch("PRAGMA application_id = 1").unwrap();
        db.profile(None);
        db.execute_batch("PRAGMA application_id = 2").unwrap();

        let profiled = PROFILED.lock().unwrap();
        assert_eq!(profiled.len(), 1);
        assert_eq!(profiled[0].0, "PRAGMA application_id = 1");
    }
}
<|endoftext|>


<commit_before>use core::slice;

/// Internal enum mapping type
///
/// This trait is internally used by `#[derive(EnumMap)]`. Despite it being
/// a public trait, it's not intended to be public. `Internal<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
/// Users aren't expected to use this trait directly, but rather to use
/// `EnumMap<K, V>` which uses this internally.
///
/// This trait is also implemented by `bool`, `u8` and `Option` type. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Internal<V>: Sized {
    /// Representation of an enum map for type `V`, usually an array.
    type Array;
    #[doc(hidden)]
    fn slice(array: &Self::Array) -> &[V];
    #[doc(hidden)]
    fn slice_mut(array: &mut Self::Array) -> &mut [V];
    #[doc(hidden)]
    fn from_usize(value: usize) -> Self;
    #[doc(hidden)]
    fn to_usize(self) -> usize;
    #[doc(hidden)]
    fn from_function<F: FnMut(Self) -> V>(f: F) -> Self::Array;
}

impl<T> Internal<T> for bool {
    type Array = [T; 2];
    fn slice(array: &[T; 2]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 2]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 2] {
        [f(false), f(true)]
    }
}

impl<T> Internal<T> for u8 {
    type Array = [T; 256];
    fn slice(array: &[T; 256]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 256]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        value as u8
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 256] {
        array![|i| f(i as u8); 256]
    }
}

// C representation is needed to ensure Rust compiler won't reorder those 2 fields.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct OptionInternal<T, U> {
    none: T,
    some: U,
}

#[deprecated(since = "0.2.30", note = "the implementation is unsafe, and will be removed in enum-map 0.3.0")]
impl<T, U: Internal<T>> Internal<T> for Option<U> {
    type Array = OptionInternal<T, U::Array>;
    fn slice(array: &Self::Array) -> &[T] {
        unsafe {
            slice::from_raw_parts(
                array as *const _ as *const T,
                1 + U::slice(&array.some).len(),
            )
        }
    }
    fn slice_mut(array: &mut Self::Array) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(array as *mut _ as *mut T, 1 + U::slice(&array.some).len())
        }
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => None,
            v => Some(U::from_usize(v - 1)),
        }
    }
    fn to_usize(self) -> usize {
        match self {
            None => 0,
            Some(x) => x.to_usize() + 1,
        }
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> Self::Array {
        OptionInternal {
            none: f(None),
            some: U::from_function(|x| f(Some(x))),
        }
    }
}
<commit_msg>Reformat code<commit_after>use core::slice;

/// Internal enum mapping type
///
/// This trait is internally used by `#[derive(EnumMap)]`. Despite it being
/// a public trait, it's not intended to be public. `Internal<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
/// Users aren't expected to use this trait directly, but rather to use
/// `EnumMap<K, V>` which uses this internally.
///
/// This trait is also implemented by `bool`, `u8` and `Option` type. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Internal<V>: Sized {
    /// Representation of an enum map for type `V`, usually an array.
    type Array;
    #[doc(hidden)]
    fn slice(array: &Self::Array) -> &[V];
    #[doc(hidden)]
    fn slice_mut(array: &mut Self::Array) -> &mut [V];
    #[doc(hidden)]
    fn from_usize(value: usize) -> Self;
    #[doc(hidden)]
    fn to_usize(self) -> usize;
    #[doc(hidden)]
    fn from_function<F: FnMut(Self) -> V>(f: F) -> Self::Array;
}

impl<T> Internal<T> for bool {
    type Array = [T; 2];
    fn slice(array: &[T; 2]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 2]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 2] {
        [f(false), f(true)]
    }
}

impl<T> Internal<T> for u8 {
    type Array = [T; 256];
    fn slice(array: &[T; 256]) -> &[T] {
        array
    }
    fn slice_mut(array: &mut [T; 256]) -> &mut [T] {
        array
    }
    fn from_usize(value: usize) -> Self {
        value as u8
    }
    fn to_usize(self) -> usize {
        self as usize
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 256] {
        array![|i| f(i as u8); 256]
    }
}

// C representation is needed to ensure Rust compiler won't reorder those 2 fields.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct OptionInternal<T, U> {
    none: T,
    some: U,
}

#[deprecated(
    since = "0.2.30", note = "the implementation is unsafe, and will be removed in enum-map 0.3.0"
)]
impl<T, U: Internal<T>> Internal<T> for Option<U> {
    type Array = OptionInternal<T, U::Array>;
    fn slice(array: &Self::Array) -> &[T] {
        unsafe {
            slice::from_raw_parts(
                array as *const _ as *const T,
                1 + U::slice(&array.some).len(),
            )
        }
    }
    fn slice_mut(array: &mut Self::Array) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(array as *mut _ as *mut T, 1 + U::slice(&array.some).len())
        }
    }
    fn from_usize(value: usize) -> Self {
        match value {
            0 => None,
            v => Some(U::from_usize(v - 1)),
        }
    }
    fn to_usize(self) -> usize {
        match self {
            None => 0,
            Some(x) => x.to_usize() + 1,
        }
    }
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> Self::Array {
        OptionInternal {
            none: f(None),
            some: U::from_function(|x| f(Some(x))),
        }
    }
}
<|endoftext|>


<commit_before>fn slice<'a, T>(list: &'a [T], i: uint, k: uint) -> &'a [T] {
    list.slice(i-1, k)
}

fn main() {
    let list = ~['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
    println!("{:?}", slice(list, 3, 7));
    println!("{:?}", slice(list, 3, 7));
}

<commit_msg>Cleanup Problem 18<commit_after>// The author of this work hereby waives all claim of copyright (economic and
// moral) in this work and immediately places it in the public domain; it may
// be used, distorted or destroyed in any manner whatsoever without further
// attribution or notice to the creator.

//! Problem 18: Vectors: slice
//!
//! Given two indices, `i` and `k`, the slice is the vector containing the
//! elements between the `i`th and `k`th element of the original vector (first
//! limit included only).  Start counting the elements with 0.  Your function
//! should not fail in case one or the other indices point outside the vector.
//!
//! Your function could have this signature:
//! `fn dupli<T>(vec: &'a [T], i: uint, k: uint) -> &'a [T]`

use std::cmp::min;

fn slice<'a, T>(vec: &'a [T], i: uint, k: uint) -> &'a [T] {
    vec.slice(min(i, vec.len()), min(k, vec.len()))
}

#[test]
fn slice_ok() {
    let vec = ~['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
    assert_eq!(slice(vec, 3, 7), &['d', 'e', 'f', 'g']);
}

#[test]
fn slice_outside() {
    let vec = ~['a', 'b', 'c', 'd', 'e'];
    assert_eq!(slice(vec, 7, 10), &[]);
}

<|endoftext|>


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

use common::*;
use common::stats::Stat;
use request::BenchmarkConfig;
use tic::{Interest, Meters, Percentile, Receiver};

pub fn stats_receiver_init(config: &BenchmarkConfig,
                           listen: Option<String>,
                           waterfall: Option<String>,
                           trace: Option<String>)
                           -> Receiver<Stat> {
    let mut stats_config = Receiver::<Stat>::configure()
        .batch_size(1024)
        .capacity(4096)
        .duration(config.duration())
        .windows(config.windows());

    if let Some(addr) = listen {
        stats_config = stats_config.http_listen(addr);
    }

    let mut stats_receiver = stats_config.build();

    let counts = vec![Stat::Window,
                      Stat::ResponseOk,
                      Stat::ResponseOkHit,
                      Stat::ResponseOkMiss,
                      Stat::ResponseError,
                      Stat::ResponseTimeout,
                      Stat::RequestPrepared,
                      Stat::RequestSent,
                      Stat::ConnectOk,
                      Stat::ConnectError,
                      Stat::ConnectTimeout,
                      Stat::SocketCreate,
                      Stat::SocketClose,
                      Stat::SocketRead,
                      Stat::SocketFlush,
                      Stat::SocketWrite];

    for c in counts {
        stats_receiver.add_interest(Interest::Count(c));
    }

    for c in vec![Stat::ResponseOk,
                  Stat::ResponseOkHit,
                  Stat::ResponseOkMiss,
                  Stat::ConnectOk] {
        stats_receiver.add_interest(Interest::Percentile(c));
    }

    if let Some(w) = waterfall {
        stats_receiver.add_interest(Interest::Waterfall(Stat::ResponseOk, w));
    }

    if let Some(t) = trace {
        stats_receiver.add_interest(Interest::Trace(Stat::ResponseOk, t));
    }

    stats_receiver
}

pub fn meters_delta(t0: &Meters<Stat>, t1: &Meters<Stat>, stat: &Stat) -> u64 {
    *t1.count(stat).unwrap_or(&0) - *t0.count(stat).unwrap_or(&0)
}

pub fn run(mut receiver: Receiver<Stat>, windows: usize, infinite: bool) {

    let mut window = 0;
    let mut warmup = true;

    let clocksource = receiver.get_clocksource().clone();
    let mut sender = receiver.get_sender().clone();
    sender.set_batch_size(1);

    let mut t0 = clocksource.counter();
    let mut m0 = receiver.clone_meters();

    debug!("stats: collection ready");
    loop {
        receiver.run_once();
        let t1 = clocksource.counter();
        let m1 = receiver.clone_meters();

        if warmup {
            info!("-----");
            if meters_delta(&m0, &m1, &Stat::ConnectOk) == 0 {
                halt!("No connections established. Please check that server(s) are available");
            }
            info!("Warmup complete");
            warmup = false;
        } else {
            let responses = meters_delta(&m0, &m1, &Stat::ResponseOk) +
                            meters_delta(&m0, &m1, &Stat::ResponseError);

            let rate = responses as f64 /
                       ((clocksource.convert(t1) - clocksource.convert(t0)) as f64 /
                        1_000_000_000.0);

            let success_rate = if responses > 0 {
                100.0 * (responses - meters_delta(&m0, &m1, &Stat::ResponseError)) as f64 /
                (responses + meters_delta(&m0, &m1, &Stat::ResponseTimeout)) as f64
            } else {
                0.0
            };

            let hit = meters_delta(&m0, &m1, &Stat::ResponseOkHit);
            let miss = meters_delta(&m0, &m1, &Stat::ResponseOkMiss);

            let hit_rate = if (hit + miss) > 0 {
                100.0 * hit as f64 / (hit + miss) as f64
            } else {
                0.0
            };

            info!("-----");
            info!("Window: {}", window);
            let inflight = *m1.count(&Stat::RequestSent).unwrap_or(&0) as i64 -
                           *m1.count(&Stat::ResponseOk).unwrap_or(&0) as i64 -
                           *m1.count(&Stat::ResponseError).unwrap_or(&0) as i64 -
                           *m1.count(&Stat::ResponseTimeout).unwrap_or(&0) as i64;
            let open = *m1.count(&Stat::SocketCreate).unwrap_or(&0) as i64 -
                       *m1.count(&Stat::SocketClose).unwrap_or(&0) as i64;
            info!("Connections: Ok: {} Error: {} Timeout: {} Open: {}",
                  meters_delta(&m0, &m1, &Stat::ConnectOk),
                  meters_delta(&m0, &m1, &Stat::ConnectError),
                  meters_delta(&m0, &m1, &Stat::ConnectTimeout),
                  open);
            info!("Sockets: Create: {} Close: {} Read: {} Write: {} Flush: {}",
                  meters_delta(&m0, &m1, &Stat::SocketCreate),
                  meters_delta(&m0, &m1, &Stat::SocketClose),
                  meters_delta(&m0, &m1, &Stat::SocketRead),
                  meters_delta(&m0, &m1, &Stat::SocketWrite),
                  meters_delta(&m0, &m1, &Stat::SocketFlush));
            info!("Requests: Sent: {} Prepared: {} In-Flight: {}",
                  meters_delta(&m0, &m1, &Stat::RequestSent),
                  meters_delta(&m0, &m1, &Stat::RequestPrepared),
                  inflight);
            info!("Responses: Ok: {} Error: {} Timeout: {} Hit: {} Miss: {}",
                  meters_delta(&m0, &m1, &Stat::ResponseOk),
                  meters_delta(&m0, &m1, &Stat::ResponseError),
                  meters_delta(&m0, &m1, &Stat::ResponseTimeout),
                  meters_delta(&m0, &m1, &Stat::ResponseOkHit),
                  meters_delta(&m0, &m1, &Stat::ResponseOkMiss));
            info!("Rate: {:.*} rps Success: {:.*} % Hit Rate: {:.*} %",
                  2,
                  rate,
                  2,
                  success_rate,
                  2,
                  hit_rate);
            display_percentiles(&m1, &Stat::ResponseOk, "Response OK");
        }

        m0 = m1;
        t0 = t1;
        window += 1;

        if window > windows {
            receiver.save_files();
            if infinite {
                window = 0;
                receiver.clear_heatmaps();
            } else {
                break;
            }
        }
    }
}

fn display_percentiles(meters: &Meters<Stat>, stat: &Stat, label: &str) {
    info!("Percentiles: {} (us): min: {} p50: {} p90: {} p99: {} p999: {} p9999: {} max: {}",
                    label,
                    meters.percentile(stat,
                        Percentile("min".to_owned(), 0.0)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p50".to_owned(), 50.0)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p90".to_owned(), 90.0)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p99".to_owned(), 99.0)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p999".to_owned(), 99.9)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p9999".to_owned(), 99.99)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("max".to_owned(), 100.0)).unwrap_or(&0) / 1000,
                );
}
<commit_msg>bugfix for window display<commit_after>//  rpc-perf - RPC Performance Testing
//  Copyright 2015 Twitter, Inc
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

use common::*;
use common::stats::Stat;
use request::BenchmarkConfig;
use tic::{Interest, Meters, Percentile, Receiver};

pub fn stats_receiver_init(config: &BenchmarkConfig,
                           listen: Option<String>,
                           waterfall: Option<String>,
                           trace: Option<String>)
                           -> Receiver<Stat> {
    let mut stats_config = Receiver::<Stat>::configure()
        .batch_size(1024)
        .capacity(4096)
        .duration(config.duration())
        .windows(config.windows());

    if let Some(addr) = listen {
        stats_config = stats_config.http_listen(addr);
    }

    let mut stats_receiver = stats_config.build();

    let counts = vec![Stat::Window,
                      Stat::ResponseOk,
                      Stat::ResponseOkHit,
                      Stat::ResponseOkMiss,
                      Stat::ResponseError,
                      Stat::ResponseTimeout,
                      Stat::RequestPrepared,
                      Stat::RequestSent,
                      Stat::ConnectOk,
                      Stat::ConnectError,
                      Stat::ConnectTimeout,
                      Stat::SocketCreate,
                      Stat::SocketClose,
                      Stat::SocketRead,
                      Stat::SocketFlush,
                      Stat::SocketWrite];

    for c in counts {
        stats_receiver.add_interest(Interest::Count(c));
    }

    for c in vec![Stat::ResponseOk,
                  Stat::ResponseOkHit,
                  Stat::ResponseOkMiss,
                  Stat::ConnectOk] {
        stats_receiver.add_interest(Interest::Percentile(c));
    }

    if let Some(w) = waterfall {
        stats_receiver.add_interest(Interest::Waterfall(Stat::ResponseOk, w));
    }

    if let Some(t) = trace {
        stats_receiver.add_interest(Interest::Trace(Stat::ResponseOk, t));
    }

    stats_receiver
}

pub fn meters_delta(t0: &Meters<Stat>, t1: &Meters<Stat>, stat: &Stat) -> u64 {
    *t1.count(stat).unwrap_or(&0) - *t0.count(stat).unwrap_or(&0)
}

pub fn run(mut receiver: Receiver<Stat>, windows: usize, infinite: bool) {

    let mut window = 0;
    let mut warmup = true;
    let mut next_window = window + windows;

    let clocksource = receiver.get_clocksource().clone();
    let mut sender = receiver.get_sender().clone();
    sender.set_batch_size(1);

    let mut t0 = clocksource.counter();
    let mut m0 = receiver.clone_meters();

    debug!("stats: collection ready");
    loop {
        receiver.run_once();
        let t1 = clocksource.counter();
        let m1 = receiver.clone_meters();

        if warmup {
            info!("-----");
            if meters_delta(&m0, &m1, &Stat::ConnectOk) == 0 {
                halt!("No connections established. Please check that server(s) are available");
            }
            info!("Warmup complete");
            warmup = false;
        } else {
            let responses = meters_delta(&m0, &m1, &Stat::ResponseOk) +
                            meters_delta(&m0, &m1, &Stat::ResponseError);

            let rate = responses as f64 /
                       ((clocksource.convert(t1) - clocksource.convert(t0)) as f64 /
                        1_000_000_000.0);

            let success_rate = if responses > 0 {
                100.0 * (responses - meters_delta(&m0, &m1, &Stat::ResponseError)) as f64 /
                (responses + meters_delta(&m0, &m1, &Stat::ResponseTimeout)) as f64
            } else {
                0.0
            };

            let hit = meters_delta(&m0, &m1, &Stat::ResponseOkHit);
            let miss = meters_delta(&m0, &m1, &Stat::ResponseOkMiss);

            let hit_rate = if (hit + miss) > 0 {
                100.0 * hit as f64 / (hit + miss) as f64
            } else {
                0.0
            };

            info!("-----");
            info!("Window: {}", window);
            let inflight = *m1.count(&Stat::RequestSent).unwrap_or(&0) as i64 -
                           *m1.count(&Stat::ResponseOk).unwrap_or(&0) as i64 -
                           *m1.count(&Stat::ResponseError).unwrap_or(&0) as i64 -
                           *m1.count(&Stat::ResponseTimeout).unwrap_or(&0) as i64;
            let open = *m1.count(&Stat::SocketCreate).unwrap_or(&0) as i64 -
                       *m1.count(&Stat::SocketClose).unwrap_or(&0) as i64;
            info!("Connections: Ok: {} Error: {} Timeout: {} Open: {}",
                  meters_delta(&m0, &m1, &Stat::ConnectOk),
                  meters_delta(&m0, &m1, &Stat::ConnectError),
                  meters_delta(&m0, &m1, &Stat::ConnectTimeout),
                  open);
            info!("Sockets: Create: {} Close: {} Read: {} Write: {} Flush: {}",
                  meters_delta(&m0, &m1, &Stat::SocketCreate),
                  meters_delta(&m0, &m1, &Stat::SocketClose),
                  meters_delta(&m0, &m1, &Stat::SocketRead),
                  meters_delta(&m0, &m1, &Stat::SocketWrite),
                  meters_delta(&m0, &m1, &Stat::SocketFlush));
            info!("Requests: Sent: {} Prepared: {} In-Flight: {}",
                  meters_delta(&m0, &m1, &Stat::RequestSent),
                  meters_delta(&m0, &m1, &Stat::RequestPrepared),
                  inflight);
            info!("Responses: Ok: {} Error: {} Timeout: {} Hit: {} Miss: {}",
                  meters_delta(&m0, &m1, &Stat::ResponseOk),
                  meters_delta(&m0, &m1, &Stat::ResponseError),
                  meters_delta(&m0, &m1, &Stat::ResponseTimeout),
                  meters_delta(&m0, &m1, &Stat::ResponseOkHit),
                  meters_delta(&m0, &m1, &Stat::ResponseOkMiss));
            info!("Rate: {:.*} rps Success: {:.*} % Hit Rate: {:.*} %",
                  2,
                  rate,
                  2,
                  success_rate,
                  2,
                  hit_rate);
            display_percentiles(&m1, &Stat::ResponseOk, "Response OK");
        }

        m0 = m1;
        t0 = t1;
        window += 1;

        if window > next_window {
            receiver.save_files();
            if infinite {
                next_window += windows;
                receiver.clear_heatmaps();
            } else {
                break;
            }
        }
    }
}

fn display_percentiles(meters: &Meters<Stat>, stat: &Stat, label: &str) {
    info!("Percentiles: {} (us): min: {} p50: {} p90: {} p99: {} p999: {} p9999: {} max: {}",
                    label,
                    meters.percentile(stat,
                        Percentile("min".to_owned(), 0.0)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p50".to_owned(), 50.0)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p90".to_owned(), 90.0)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p99".to_owned(), 99.0)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p999".to_owned(), 99.9)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("p9999".to_owned(), 99.99)).unwrap_or(&0) / 1000,
                    meters.percentile(stat,
                        Percentile("max".to_owned(), 100.0)).unwrap_or(&0) / 1000,
                );
}
<|endoftext|>


<commit_before>#![allow(dead_code, non_camel_case_types)]

extern crate libc;

pub use self::os::{mdb_mode_t, mdb_filehandle_t};
use libc::{c_int, c_uint, c_void, c_char, size_t};

#[cfg(any(target_os = "macos", target_os = "ios", target_os = "linux",
          target_os = "freebsd", target_os = "dragonfly",
          target_os = "android"))]
mod os {
    use libc;

    pub type mdb_mode_t = libc::mode_t;

    pub type mdb_filehandle_t = libc::c_int;
}

#[cfg(target_os = "windows")]
mod os {
    use libc::{c_int, c_void};

    pub type mdb_mode_t = c_int;

    pub type mdb_filehandle_t = *const c_void;
}

pub type MDB_dbi = c_uint;

pub type MDB_rel_func = fn(*const MDB_val, *const c_void, *const c_void, *const c_void);
pub type MDB_msg_func = fn(*const c_char, *const c_void) -> c_int;
pub type MDB_cmp_func = fn(*const MDB_val, *const MDB_val) -> c_int;

#[derive(Copy, Clone)]
#[allow(raw_pointer_derive)]
#[repr(C)]
pub struct MDB_val {
    pub mv_size: size_t,
    pub mv_data: *const c_void,
}

#[allow(missing_copy_implementations)]
pub enum MDB_env {}

#[allow(missing_copy_implementations)]
pub enum MDB_txn {}

#[allow(missing_copy_implementations)]
pub enum MDB_cursor {}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct MDB_stat {
    pub ms_psize: c_uint,
    pub ms_depth: c_uint,
    pub ms_branch_pages: size_t,
    pub ms_leaf_pages: size_t,
    pub ms_overflow_pages: size_t,
    pub ms_entries: size_t
}

#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct MDB_envinfo {
    pub me_mapaddr: *const c_void,
    pub me_mapsize: size_t,
    pub me_last_pgno: size_t,
    pub me_last_txnid: size_t,
    pub me_maxreaders: c_uint,
    pub me_numreaders: c_uint
}

#[repr(C)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum MDB_cursor_op {
    MDB_FIRST,
    MDB_FIRST_DUP,
    MDB_GET_BOTH,
    MDB_GET_BOTH_RANGE,
    MDB_GET_CURRENT,
    MDB_GET_MULTIPLE,
    MDB_LAST,
    MDB_LAST_DUP,
    MDB_NEXT,
    MDB_NEXT_DUP,
    MDB_NEXT_MULTIPLE,
    MDB_NEXT_NODUP,
    MDB_PREV,
    MDB_PREV_DUP,
    MDB_PREV_NODUP,
    MDB_SET,
    MDB_SET_KEY,
    MDB_SET_RANGE
}

// Return codes
pub const MDB_SUCCESS: c_int = 0;
pub const MDB_KEYEXIST: c_int = -30799;
pub const MDB_NOTFOUND: c_int = -30798;
pub const MDB_PAGE_NOTFOUND: c_int = -30797;
pub const MDB_CORRUPTED: c_int = -30796;
pub const MDB_PANIC: c_int = -30795;
pub const MDB_VERSION_MISMATCH: c_int = -30794;
pub const MDB_INVALID: c_int = -30793;
pub const MDB_MAP_FULL: c_int = -30792;
pub const MDB_DBS_FULL: c_int = -30791;
pub const MDB_READERS_FULL: c_int = -30790;
pub const MDB_TLS_FULL: c_int = -30789;
pub const MDB_TXN_FULL: c_int = -30788;
pub const MDB_CURSOR_FULL: c_int = -30787;
pub const MDB_PAGE_FULL: c_int = -30786;
pub const MDB_MAP_RESIZED: c_int = -30785;
pub const MDB_INCOMPATIBLE: c_int = -30784;
pub const MDB_BAD_RSLOT: c_int = -30783;
pub const MDB_BAD_TXN: c_int = -30782;
pub const MDB_BAD_VALSIZE: c_int = -30781;

// Write flags
pub const MDB_NOOVERWRITE: c_uint = 0x10;
pub const MDB_NODUPDATA: c_uint = 0x20;
pub const MDB_CURRENT: c_uint = 0x40;
pub const MDB_RESERVE: c_uint = 0x10000;
pub const MDB_APPEND: c_uint = 0x20000;
pub const MDB_APPENDDUP: c_uint = 0x40000;
pub const MDB_MULTIPLE: c_uint = 0x80000;

// Database flags
pub const MDB_REVERSEKEY: c_uint = 0x02;
pub const MDB_DUPSORT: c_uint = 0x04;
pub const MDB_INTEGERKEY: c_uint = 0x08;
pub const MDB_DUPFIXED: c_uint = 0x10;
pub const MDB_INTEGERDUP: c_uint = 0x20;
pub const MDB_REVERSEDUP: c_uint =  0x40;
pub const MDB_CREATE: c_uint = 0x40000;

// Environment flags
pub const MDB_FIXEDMAP: c_uint =  0x01;
pub const MDB_NOSUBDIR: c_uint = 0x4000;
pub const MDB_NOSYNC: c_uint = 0x10000;
pub const MDB_RDONLY: c_uint = 0x20000;
pub const MDB_NOMETASYNC: c_uint = 0x40000;
pub const MDB_WRITEMAP: c_uint = 0x80000;
pub const MDB_MAPASYNC: c_uint = 0x100000;
pub const MDB_NOTLS: c_uint = 0x200000;
pub const MDB_NOLOCK: c_uint =  0x400000;
pub const MDB_NORDAHEAD: c_uint = 0x800000;
pub const MDB_NOMEMINIT: c_uint =  0x1000000;

// Embedding should work better for now
extern "C" {
    pub fn mdb_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> *const c_char;
    pub fn mdb_strerror(err: c_int) -> *const c_char;
    pub fn mdb_env_create(env: *mut *mut MDB_env) -> c_int;
    pub fn mdb_env_open(env: *mut MDB_env, path: *const c_char, flags: c_uint, mode: mdb_mode_t) -> c_int;
    pub fn mdb_env_copy(env: *mut MDB_env, path: *const c_char) -> c_int;
    pub fn mdb_env_copyfd(env: *mut MDB_env, fd: mdb_filehandle_t) -> c_int;
    pub fn mdb_env_stat(env: *mut MDB_env, stat: *mut MDB_stat) -> c_int;
    pub fn mdb_env_info(env: *mut MDB_env, info: *mut MDB_envinfo) -> c_int;
    pub fn mdb_env_sync(env: *mut MDB_env, force: c_int) -> c_int;
    pub fn mdb_env_close(env: *mut MDB_env);
    pub fn mdb_env_set_flags(env: *mut MDB_env, flags: c_uint, onoff: c_int) -> c_int;
    pub fn mdb_env_get_flags(env: *mut MDB_env, flags: *mut c_uint) -> c_int;
    pub fn mdb_env_get_path(env: *mut MDB_env, path: *mut *mut c_char) -> c_int;
    pub fn mdb_env_get_fd(env: *mut MDB_env, fd: *mut mdb_filehandle_t) -> c_int;
    pub fn mdb_env_set_mapsize(env: *mut MDB_env, size: size_t) -> c_int;
    pub fn mdb_env_set_maxreaders(env: *mut MDB_env, readers: c_uint) -> c_int;
    pub fn mdb_env_get_maxreaders(env: *mut MDB_env, readers: *mut c_uint) -> c_int;
    pub fn mdb_env_set_maxdbs(env: *mut MDB_env, dbs: MDB_dbi) -> c_int;
    pub fn mdb_env_get_maxkeysize(env: *mut MDB_env) -> c_int;
    pub fn mdb_txn_begin(env: *mut MDB_env, parent: *mut MDB_txn, flags: c_uint, txn: *mut *mut MDB_txn) -> c_int;
    pub fn mdb_txn_env(txn: *mut MDB_txn) -> *mut MDB_env;
    pub fn mdb_txn_commit(txn: *mut MDB_txn) -> c_int;
    pub fn mdb_txn_abort(txn: *mut MDB_txn);
    pub fn mdb_txn_reset(txn: *mut MDB_txn);
    pub fn mdb_txn_renew(txn: *mut MDB_txn) -> c_int;
    pub fn mdb_dbi_open(txn: *mut MDB_txn, name: *const c_char, flags: c_uint, dbi: *mut MDB_dbi) -> c_int;
    pub fn mdb_stat(txn: *mut MDB_txn, dbi: MDB_dbi, stat: *mut MDB_stat) -> c_int;
    pub fn mdb_dbi_flags(txn: *mut MDB_txn, dbi: MDB_dbi, flags: *mut c_uint) -> c_int;
    pub fn mdb_dbi_close(txn: *mut MDB_env, dbi: MDB_dbi);
    pub fn mdb_drop(txn: *mut MDB_txn, dbi: MDB_dbi, del: c_int) -> c_int;
    pub fn mdb_set_compare(txn: *mut MDB_txn, dbi: MDB_dbi, cmp: MDB_cmp_func) -> c_int;
    pub fn mdb_set_dupsort(txn: *mut MDB_txn, dbi: MDB_dbi, cmp: MDB_cmp_func) -> c_int;
    pub fn mdb_set_relfunc(txn: *mut MDB_txn, dbi: MDB_dbi, rel: MDB_rel_func) -> c_int;
    pub fn mdb_set_relctx(txn: *mut MDB_txn, dbi: MDB_dbi, ctx: *const c_void) -> c_int;
    pub fn mdb_get(txn: *mut MDB_txn, dbi: MDB_dbi, key: *mut MDB_val, data: *mut MDB_val) -> c_int;
    pub fn mdb_put(txn: *mut MDB_txn, dbi: MDB_dbi, key: *mut MDB_val, data: *mut MDB_val, flags: c_uint) -> c_int;
    pub fn mdb_del(txn: *mut MDB_txn, dbi: MDB_dbi, key: *mut MDB_val, data: *mut MDB_val) -> c_int;
    pub fn mdb_cursor_open(txn: *mut MDB_txn, dbi: MDB_dbi, cursor: *mut *mut MDB_cursor) -> c_int;
    pub fn mdb_cursor_close(cursor: *mut MDB_cursor) -> c_int;
    pub fn mdb_cursor_renew(txn: *mut MDB_txn, cursor: *mut MDB_cursor) -> c_int;
    pub fn mdb_cursor_txn(cursor: *mut MDB_cursor) -> *mut MDB_txn;
    pub fn mdb_cursor_dbi(cursor: *mut MDB_cursor) -> *mut MDB_dbi;
    pub fn mdb_cursor_get(cursor: *mut MDB_cursor, key: *mut MDB_val, data: *mut MDB_val, op: MDB_cursor_op) -> c_int;
    pub fn mdb_cursor_put(cursor: *mut MDB_cursor, key: *mut MDB_val, data: *mut MDB_val, flags: c_uint) -> c_int;
    pub fn mdb_cursor_del(cursor: *mut MDB_cursor, flags: c_uint) -> c_int;
    pub fn mdb_cursor_count(cursor: *mut MDB_cursor, countp: *mut size_t) -> c_int;
    pub fn mdb_cmp(txn: *mut MDB_txn, dbi: MDB_dbi, a: *mut MDB_val, b: *mut MDB_val) -> c_int;
    pub fn mdb_dcmp(txn: *mut MDB_txn, dbi: MDB_dbi, a: *mut MDB_val, b: *mut MDB_val) -> c_int;
    pub fn mdb_reader_list(env: *mut MDB_env, func: MDB_msg_func, ctx: *const c_void) -> c_int;
    pub fn mdb_reader_check(env: *mut MDB_env, dead: *mut c_int) -> c_int;
}

impl std::fmt::Debug for MDB_val {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        unsafe {
            let buf: &[u8] = std::slice::from_raw_parts(std::mem::transmute(self.mv_data),
                                                        self.mv_size as usize);
            write!(fmt, "{:?}@{:?}", buf, self.mv_data)
        }
    }
}
<commit_msg>Fix compiler warnings on "Rust calling convention in foreign module"<commit_after>#![allow(dead_code, non_camel_case_types)]

extern crate libc;

pub use self::os::{mdb_mode_t, mdb_filehandle_t};
use libc::{c_int, c_uint, c_void, c_char, size_t};

#[cfg(any(target_os = "macos", target_os = "ios", target_os = "linux",
          target_os = "freebsd", target_os = "dragonfly",
          target_os = "android"))]
mod os {
    use libc;

    pub type mdb_mode_t = libc::mode_t;

    pub type mdb_filehandle_t = libc::c_int;
}

#[cfg(target_os = "windows")]
mod os {
    use libc::{c_int, c_void};

    pub type mdb_mode_t = c_int;

    pub type mdb_filehandle_t = *const c_void;
}

pub type MDB_dbi = c_uint;

pub type MDB_rel_func = extern fn(*const MDB_val, *const c_void, *const c_void, *const c_void);
pub type MDB_msg_func = extern fn(*const c_char, *const c_void) -> c_int;
pub type MDB_cmp_func = extern fn(*const MDB_val, *const MDB_val) -> c_int;

#[derive(Copy, Clone)]
#[allow(raw_pointer_derive)]
#[repr(C)]
pub struct MDB_val {
    pub mv_size: size_t,
    pub mv_data: *const c_void,
}

#[allow(missing_copy_implementations)]
pub enum MDB_env {}

#[allow(missing_copy_implementations)]
pub enum MDB_txn {}

#[allow(missing_copy_implementations)]
pub enum MDB_cursor {}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct MDB_stat {
    pub ms_psize: c_uint,
    pub ms_depth: c_uint,
    pub ms_branch_pages: size_t,
    pub ms_leaf_pages: size_t,
    pub ms_overflow_pages: size_t,
    pub ms_entries: size_t
}

#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct MDB_envinfo {
    pub me_mapaddr: *const c_void,
    pub me_mapsize: size_t,
    pub me_last_pgno: size_t,
    pub me_last_txnid: size_t,
    pub me_maxreaders: c_uint,
    pub me_numreaders: c_uint
}

#[repr(C)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum MDB_cursor_op {
    MDB_FIRST,
    MDB_FIRST_DUP,
    MDB_GET_BOTH,
    MDB_GET_BOTH_RANGE,
    MDB_GET_CURRENT,
    MDB_GET_MULTIPLE,
    MDB_LAST,
    MDB_LAST_DUP,
    MDB_NEXT,
    MDB_NEXT_DUP,
    MDB_NEXT_MULTIPLE,
    MDB_NEXT_NODUP,
    MDB_PREV,
    MDB_PREV_DUP,
    MDB_PREV_NODUP,
    MDB_SET,
    MDB_SET_KEY,
    MDB_SET_RANGE
}

// Return codes
pub const MDB_SUCCESS: c_int = 0;
pub const MDB_KEYEXIST: c_int = -30799;
pub const MDB_NOTFOUND: c_int = -30798;
pub const MDB_PAGE_NOTFOUND: c_int = -30797;
pub const MDB_CORRUPTED: c_int = -30796;
pub const MDB_PANIC: c_int = -30795;
pub const MDB_VERSION_MISMATCH: c_int = -30794;
pub const MDB_INVALID: c_int = -30793;
pub const MDB_MAP_FULL: c_int = -30792;
pub const MDB_DBS_FULL: c_int = -30791;
pub const MDB_READERS_FULL: c_int = -30790;
pub const MDB_TLS_FULL: c_int = -30789;
pub const MDB_TXN_FULL: c_int = -30788;
pub const MDB_CURSOR_FULL: c_int = -30787;
pub const MDB_PAGE_FULL: c_int = -30786;
pub const MDB_MAP_RESIZED: c_int = -30785;
pub const MDB_INCOMPATIBLE: c_int = -30784;
pub const MDB_BAD_RSLOT: c_int = -30783;
pub const MDB_BAD_TXN: c_int = -30782;
pub const MDB_BAD_VALSIZE: c_int = -30781;

// Write flags
pub const MDB_NOOVERWRITE: c_uint = 0x10;
pub const MDB_NODUPDATA: c_uint = 0x20;
pub const MDB_CURRENT: c_uint = 0x40;
pub const MDB_RESERVE: c_uint = 0x10000;
pub const MDB_APPEND: c_uint = 0x20000;
pub const MDB_APPENDDUP: c_uint = 0x40000;
pub const MDB_MULTIPLE: c_uint = 0x80000;

// Database flags
pub const MDB_REVERSEKEY: c_uint = 0x02;
pub const MDB_DUPSORT: c_uint = 0x04;
pub const MDB_INTEGERKEY: c_uint = 0x08;
pub const MDB_DUPFIXED: c_uint = 0x10;
pub const MDB_INTEGERDUP: c_uint = 0x20;
pub const MDB_REVERSEDUP: c_uint =  0x40;
pub const MDB_CREATE: c_uint = 0x40000;

// Environment flags
pub const MDB_FIXEDMAP: c_uint =  0x01;
pub const MDB_NOSUBDIR: c_uint = 0x4000;
pub const MDB_NOSYNC: c_uint = 0x10000;
pub const MDB_RDONLY: c_uint = 0x20000;
pub const MDB_NOMETASYNC: c_uint = 0x40000;
pub const MDB_WRITEMAP: c_uint = 0x80000;
pub const MDB_MAPASYNC: c_uint = 0x100000;
pub const MDB_NOTLS: c_uint = 0x200000;
pub const MDB_NOLOCK: c_uint =  0x400000;
pub const MDB_NORDAHEAD: c_uint = 0x800000;
pub const MDB_NOMEMINIT: c_uint =  0x1000000;

// Embedding should work better for now
extern "C" {
    pub fn mdb_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> *const c_char;
    pub fn mdb_strerror(err: c_int) -> *const c_char;
    pub fn mdb_env_create(env: *mut *mut MDB_env) -> c_int;
    pub fn mdb_env_open(env: *mut MDB_env, path: *const c_char, flags: c_uint, mode: mdb_mode_t) -> c_int;
    pub fn mdb_env_copy(env: *mut MDB_env, path: *const c_char) -> c_int;
    pub fn mdb_env_copyfd(env: *mut MDB_env, fd: mdb_filehandle_t) -> c_int;
    pub fn mdb_env_stat(env: *mut MDB_env, stat: *mut MDB_stat) -> c_int;
    pub fn mdb_env_info(env: *mut MDB_env, info: *mut MDB_envinfo) -> c_int;
    pub fn mdb_env_sync(env: *mut MDB_env, force: c_int) -> c_int;
    pub fn mdb_env_close(env: *mut MDB_env);
    pub fn mdb_env_set_flags(env: *mut MDB_env, flags: c_uint, onoff: c_int) -> c_int;
    pub fn mdb_env_get_flags(env: *mut MDB_env, flags: *mut c_uint) -> c_int;
    pub fn mdb_env_get_path(env: *mut MDB_env, path: *mut *mut c_char) -> c_int;
    pub fn mdb_env_get_fd(env: *mut MDB_env, fd: *mut mdb_filehandle_t) -> c_int;
    pub fn mdb_env_set_mapsize(env: *mut MDB_env, size: size_t) -> c_int;
    pub fn mdb_env_set_maxreaders(env: *mut MDB_env, readers: c_uint) -> c_int;
    pub fn mdb_env_get_maxreaders(env: *mut MDB_env, readers: *mut c_uint) -> c_int;
    pub fn mdb_env_set_maxdbs(env: *mut MDB_env, dbs: MDB_dbi) -> c_int;
    pub fn mdb_env_get_maxkeysize(env: *mut MDB_env) -> c_int;
    pub fn mdb_txn_begin(env: *mut MDB_env, parent: *mut MDB_txn, flags: c_uint, txn: *mut *mut MDB_txn) -> c_int;
    pub fn mdb_txn_env(txn: *mut MDB_txn) -> *mut MDB_env;
    pub fn mdb_txn_commit(txn: *mut MDB_txn) -> c_int;
    pub fn mdb_txn_abort(txn: *mut MDB_txn);
    pub fn mdb_txn_reset(txn: *mut MDB_txn);
    pub fn mdb_txn_renew(txn: *mut MDB_txn) -> c_int;
    pub fn mdb_dbi_open(txn: *mut MDB_txn, name: *const c_char, flags: c_uint, dbi: *mut MDB_dbi) -> c_int;
    pub fn mdb_stat(txn: *mut MDB_txn, dbi: MDB_dbi, stat: *mut MDB_stat) -> c_int;
    pub fn mdb_dbi_flags(txn: *mut MDB_txn, dbi: MDB_dbi, flags: *mut c_uint) -> c_int;
    pub fn mdb_dbi_close(txn: *mut MDB_env, dbi: MDB_dbi);
    pub fn mdb_drop(txn: *mut MDB_txn, dbi: MDB_dbi, del: c_int) -> c_int;
    pub fn mdb_set_compare(txn: *mut MDB_txn, dbi: MDB_dbi, cmp: MDB_cmp_func) -> c_int;
    pub fn mdb_set_dupsort(txn: *mut MDB_txn, dbi: MDB_dbi, cmp: MDB_cmp_func) -> c_int;
    pub fn mdb_set_relfunc(txn: *mut MDB_txn, dbi: MDB_dbi, rel: MDB_rel_func) -> c_int;
    pub fn mdb_set_relctx(txn: *mut MDB_txn, dbi: MDB_dbi, ctx: *const c_void) -> c_int;
    pub fn mdb_get(txn: *mut MDB_txn, dbi: MDB_dbi, key: *mut MDB_val, data: *mut MDB_val) -> c_int;
    pub fn mdb_put(txn: *mut MDB_txn, dbi: MDB_dbi, key: *mut MDB_val, data: *mut MDB_val, flags: c_uint) -> c_int;
    pub fn mdb_del(txn: *mut MDB_txn, dbi: MDB_dbi, key: *mut MDB_val, data: *mut MDB_val) -> c_int;
    pub fn mdb_cursor_open(txn: *mut MDB_txn, dbi: MDB_dbi, cursor: *mut *mut MDB_cursor) -> c_int;
    pub fn mdb_cursor_close(cursor: *mut MDB_cursor) -> c_int;
    pub fn mdb_cursor_renew(txn: *mut MDB_txn, cursor: *mut MDB_cursor) -> c_int;
    pub fn mdb_cursor_txn(cursor: *mut MDB_cursor) -> *mut MDB_txn;
    pub fn mdb_cursor_dbi(cursor: *mut MDB_cursor) -> *mut MDB_dbi;
    pub fn mdb_cursor_get(cursor: *mut MDB_cursor, key: *mut MDB_val, data: *mut MDB_val, op: MDB_cursor_op) -> c_int;
    pub fn mdb_cursor_put(cursor: *mut MDB_cursor, key: *mut MDB_val, data: *mut MDB_val, flags: c_uint) -> c_int;
    pub fn mdb_cursor_del(cursor: *mut MDB_cursor, flags: c_uint) -> c_int;
    pub fn mdb_cursor_count(cursor: *mut MDB_cursor, countp: *mut size_t) -> c_int;
    pub fn mdb_cmp(txn: *mut MDB_txn, dbi: MDB_dbi, a: *mut MDB_val, b: *mut MDB_val) -> c_int;
    pub fn mdb_dcmp(txn: *mut MDB_txn, dbi: MDB_dbi, a: *mut MDB_val, b: *mut MDB_val) -> c_int;
    pub fn mdb_reader_list(env: *mut MDB_env, func: MDB_msg_func, ctx: *const c_void) -> c_int;
    pub fn mdb_reader_check(env: *mut MDB_env, dead: *mut c_int) -> c_int;
}

impl std::fmt::Debug for MDB_val {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        unsafe {
            let buf: &[u8] = std::slice::from_raw_parts(std::mem::transmute(self.mv_data),
                                                        self.mv_size as usize);
            write!(fmt, "{:?}@{:?}", buf, self.mv_data)
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io::Read;

use decoder::{decode, DecodedMap};
use errors::{Result, Error};

/// Represents a raw token
///
/// Raw tokens are used internally to represent the sourcemap
/// in a memory efficient way.  If you construct sourcemaps yourself
/// then you need to create these objects, otherwise they are invisible
/// to you as a user.
#[derive(PartialEq, Copy, Clone)]
pub struct RawToken {
    /// the destination (minified) line number
    pub dst_line: u32,
    /// the destination (minified) column number
    pub dst_col: u32,
    /// the source line number
    pub src_line: u32,
    /// the source line column
    pub src_col: u32,
    /// source identifier
    pub src_id: u32,
    /// name identifier (`!0` in case there is no associated name)
    pub name_id: u32,
}

/// Represents a token from a sourcemap
pub struct Token<'a> {
    raw: &'a RawToken,
    i: &'a SourceMap,
}

impl<'a> Token<'a> {
    /// get the destination (minified) line number
    pub fn get_dst_line(&self) -> u32 {
        self.raw.dst_line
    }

    /// get the destination (minified) column number
    pub fn get_dst_col(&self) -> u32 {
        self.raw.dst_col
    }

    /// get the destination line and column
    pub fn get_dst(&self) -> (u32, u32) {
        (self.get_dst_line(), self.get_dst_col())
    }

    /// get the source line number
    pub fn get_src_line(&self) -> u32 {
        self.raw.src_line
    }

    /// get the source column number
    pub fn get_src_col(&self) -> u32 {
        self.raw.src_col
    }

    /// get the source line and column
    pub fn get_src(&self) -> (u32, u32) {
        (self.get_src_line(), self.get_src_col())
    }

    /// get the source if it exists as string
    pub fn get_source(&self) -> &str {
        if self.raw.src_id == !0 {
            ""
        } else {
            &self.i.sources[self.raw.src_id as usize][..]
        }
    }

    /// get the name if it exists as string
    pub fn get_name(&self) -> Option<&str> {
        if self.raw.name_id == !0 {
            None
        } else {
            Some(&self.i.names[self.raw.name_id as usize][..])
        }
    }

    /// returns `true` if a name exists, `false` otherwise
    pub fn has_name(&self) -> bool {
        self.get_name().is_some()
    }

    /// Converts the token into a debug tuple in the form
    /// `(source, src_line, src_col, name)`
    pub fn to_tuple(&self) -> (&str, u32, u32, Option<&str>) {
        (
            self.get_source(),
            self.get_src_line(),
            self.get_src_col(),
            self.get_name()
        )
    }

    /// Get the underlying raw token
    pub fn get_raw_token(&self) -> RawToken {
        *self.raw
    }
}

/// Iterates over all tokens in a sourcemap
pub struct TokenIter<'a> {
    i: &'a SourceMap,
    next_idx: u32,
}

impl<'a> Iterator for TokenIter<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Token<'a>> {
        self.i.get_token(self.next_idx).map(|tok| {
            self.next_idx += 1;
            tok
        })
    }
}

impl<'a> fmt::Debug for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Token {}>", self)
    }
}

impl<'a> fmt::Display for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}:{}{}",
               self.get_source(),
               self.get_src_line(),
               self.get_src_col(),
               self.get_name().map(|x| format!(" name={}", x))
                   .unwrap_or("".into()))
    }
}

/// Represents a section in a sourcemap index
pub struct SourceMapSection {
    offset: (u32, u32),
    url: Option<String>,
    map: Option<Box<SourceMap>>,
}

/// Iterates over all sections in a sourcemap index
pub struct SourceMapSectionIter<'a> {
    i: &'a SourceMapIndex,
    next_idx: u32,
}

impl<'a> Iterator for SourceMapSectionIter<'a> {
    type Item = &'a SourceMapSection;

    fn next(&mut self) -> Option<&'a SourceMapSection> {
        self.i.get_section(self.next_idx).map(|sec| {
            self.next_idx += 1;
            sec
        })
    }
}

/// Represents a sourcemap index in memory
pub struct SourceMapIndex {
    version: u32,
    file: Option<String>,
    sections: Vec<SourceMapSection>,
}

/// Represents a sourcemap in memory
///
/// This is always represents a regular "non-indexed" sourcemap.  Particularly
/// in case the `from_reader` method is used an index sourcemap will be
/// rejected with an error on reading.
pub struct SourceMap {
    version: u32,
    file: Option<String>,
    tokens: Vec<RawToken>,
    index: Vec<(u32, u32, u32)>,
    names: Vec<String>,
    sources: Vec<String>,
    sources_content: Vec<Option<String>>,
}

impl SourceMap {

    /// Creates a sourcemap from a reader over a JSON stream in UTF-8
    /// format.  Optionally a "garbage header" as defined by the
    /// sourcemap draft specification is supported.  In case an indexed
    /// sourcemap is encountered an error is returned.
    ///
    /// ```rust
    /// use sourcemap::SourceMap;
    /// let input: &[_] = b"{
    ///     \"version\":3,
    ///     \"sources\":[\"coolstuff.js\"],
    ///     \"names\":[\"x\",\"alert\"],
    ///     \"mappings\":\"AAAA,GAAIA,GAAI,EACR,IAAIA,GAAK,EAAG,CACVC,MAAM\"
    /// }";
    /// let sm = SourceMap::from_reader(input).unwrap();
    /// ```
    pub fn from_reader<R: Read>(rdr: R) -> Result<SourceMap> {
        match try!(decode(rdr)) {
            DecodedMap::Regular(sm) => Ok(sm),
            DecodedMap::Index(_) => Err(Error::IndexedSourcemap),
        }
    }

    /// Constructs a new sourcemap from raw components.
    ///
    /// - `version`: the version is typically `3` which is the current darft version
    /// - `file`: an optional filename of the sourcemap
    /// - `tokens`: a list of raw tokens
    /// - `index`: a sorted mapping of line and column to token index
    /// - `names`: a vector of names
    /// - `sources` a vector of source filenames
    /// - `sources_content` optional source contents
    pub fn new(version: u32, file: Option<String>, tokens: Vec<RawToken>,
               index: Vec<(u32, u32, u32)>, names: Vec<String>,
               sources: Vec<String>,
               sources_content: Option<Vec<Option<String>>>) -> SourceMap {
        SourceMap {
            version: version,
            file: file,
            tokens: tokens,
            index: index,
            names: names,
            sources: sources,
            sources_content: sources_content.unwrap_or(vec![]),
        }
    }

    /// Returns the version of the sourcemap.
    pub fn get_version(&self) -> u32 {
        self.version
    }

    /// Returns the embedded filename in case there is one.
    pub fn get_file(&self) -> Option<&str> {
        self.file.as_ref().map(|x| &x[..])
    }

    /// Looks up a token by its index.
    pub fn get_token<'a>(&'a self, idx: u32) -> Option<Token<'a>> {
        self.tokens.get(idx as usize).map(|raw| {
            Token { raw: raw, i: self }
        })
    }

    /// Returns the number of tokens in the sourcemap.
    pub fn get_token_count(&self) -> u32 {
        self.tokens.len() as u32
    }

    /// Returns an iterator over the tokens.
    pub fn tokens<'a>(&'a self) -> TokenIter<'a> {
        TokenIter { i: self, next_idx: 0 }
    }

    /// Looks up the closest token to a given line and column.
    pub fn lookup_token<'a>(&'a self, line: u32, col: u32) -> Option<Token<'a>> {
        let mut low = 0;
        let mut high = self.index.len();

        while low < high {
            let mid = (low + high) / 2;
            if (line, col, 0) < self.index[mid as usize] {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        if low > 0 {
            self.get_token(self.index[low as usize].2)
        } else {
            None
        }
    }

    /// Returns the number of sources in the sourcemap.
    pub fn get_source_count(&self) -> u32 {
        self.sources.len() as u32
    }

    /// Looks up a source for a specific index.
    pub fn get_source(&self, idx: u32) -> Option<&str> {
        self.sources.get(idx as usize).map(|x| &x[..])
    }

    /// Looks up the content for a source.
    pub fn get_source_contents(&self, idx: u32) -> Option<&str> {
        self.sources_content.get(idx as usize)
            .and_then(|bucket| bucket.as_ref()).map(|x| &**x)
    }

    /// Returns the number of names in the sourcemap.
    pub fn get_name_count(&self) -> u32 {
        self.names.len() as u32
    }

    /// Looks up a name for a specific index.
    pub fn get_name(&self, idx: u32) -> Option<&str> {
        self.names.get(idx as usize).map(|x| &x[..])
    }
}

impl SourceMapIndex {

    /// Creates a sourcemap index from a reader over a JSON stream in UTF-8
    /// format.  Optionally a "garbage header" as defined by the
    /// sourcemap draft specification is supported.  In case a regular
    /// sourcemap is encountered an error is returned.
    pub fn from_reader<R: Read>(rdr: R) -> Result<SourceMapIndex> {
        match try!(decode(rdr)) {
            DecodedMap::Regular(_) => Err(Error::RegularSourcemap),
            DecodedMap::Index(smi) => Ok(smi),
        }
    }

    /// Constructs a new sourcemap index from raw components.
    ///
    /// - `version`: the version is typically `3` which is the current darft version
    /// - `file`: an optional filename of the index
    /// - `sections`: a vector of source map index sections
    pub fn new(version: u32, file: Option<String>,
               sections: Vec<SourceMapSection>) -> SourceMapIndex {
        SourceMapIndex {
            version: version,
            file: file,
            sections: sections,
        }
    }

    /// Returns the version of the sourcemap index.
    pub fn get_version(&self) -> u32 {
        self.version
    }

    /// Returns the embedded filename in case there is one.
    pub fn get_file(&self) -> Option<&str> {
        self.file.as_ref().map(|x| &x[..])
    }

    /// Returns the number of sections in this index
    pub fn get_section_count(&self) -> u32 {
        self.sections.len() as u32
    }

    /// Looks up a single section and returns it
    pub fn get_section(&self, idx: u32) -> Option<&SourceMapSection> {
        self.sections.get(idx as usize)
    }

    /// Looks up a single section and returns it as a mutable ref
    pub fn get_section_mut(&mut self, idx: u32) -> Option<&mut SourceMapSection> {
        self.sections.get_mut(idx as usize)
    }

    /// Iterates over all sections
    pub fn sections<'a>(&'a self) -> SourceMapSectionIter<'a> {
        SourceMapSectionIter {
            i: self,
            next_idx: 0
        }
    }

    /// Looks up the closest token to a given line and column.
    ///
    /// This requires that the referenced sourcemaps are actually loaded.
    /// If a sourcemap is encountered that is not embedded but just
    /// externally referenced it is silently skipped.
    pub fn lookup_token<'a>(&'a self, line: u32, col: u32) -> Option<Token<'a>> {
        for section in self.sections() {
            let (off_line, off_col) = section.get_offset();
            if off_line < line || off_col < col {
                continue;
            }
            if let Some(map) = section.get_sourcemap() {
                if let Some(tok) = map.lookup_token(line - off_line, col - off_col) {
                    return Some(tok);
                }
            }
        }
        None
    }
}

impl SourceMapSection {

    /// Create a new sourcemap index section
    ///
    /// - `offset`: offset as line and column
    /// - `url`: optional URL of where the sourcemap is located
    /// - `map`: an optional already resolved internal sourcemap
    pub fn new(offset: (u32, u32), url: Option<String>, map: Option<SourceMap>) -> SourceMapSection {
        SourceMapSection {
            offset: offset,
            url: url,
            map: map.map(|x| Box::new(x)),
        }
    }

    /// Returns the offset line
    pub fn get_offset_line(&self) -> u32 {
        self.offset.0
    }

    /// Returns the offset column
    pub fn get_offset_col(&self) -> u32 {
        self.offset.1
    }

    /// Returns the offset as tuple
    pub fn get_offset(&self) -> (u32, u32) {
        self.offset
    }

    /// Returns the URL of the referenced map if available
    pub fn get_url(&self) -> Option<&str> {
        self.url.as_ref().map(|x| &**x)
    }

    /// Returns a reference to the embedded sourcemap if available
    pub fn get_sourcemap(&self) -> Option<&SourceMap> {
        self.map.as_ref().map(|x| &**x)
    }

    /// Replaces the embedded sourcemap
    pub fn set_sourcemap(&mut self, sm: SourceMap) {
        self.map = Some(Box::new(sm));
    }
}
<commit_msg>Added support for index iteration<commit_after>use std::fmt;
use std::io::Read;

use decoder::{decode, DecodedMap};
use errors::{Result, Error};

/// Represents a raw token
///
/// Raw tokens are used internally to represent the sourcemap
/// in a memory efficient way.  If you construct sourcemaps yourself
/// then you need to create these objects, otherwise they are invisible
/// to you as a user.
#[derive(PartialEq, Copy, Clone)]
pub struct RawToken {
    /// the destination (minified) line number
    pub dst_line: u32,
    /// the destination (minified) column number
    pub dst_col: u32,
    /// the source line number
    pub src_line: u32,
    /// the source line column
    pub src_col: u32,
    /// source identifier
    pub src_id: u32,
    /// name identifier (`!0` in case there is no associated name)
    pub name_id: u32,
}

/// Represents a token from a sourcemap
pub struct Token<'a> {
    raw: &'a RawToken,
    i: &'a SourceMap,
}

impl<'a> Token<'a> {
    /// get the destination (minified) line number
    pub fn get_dst_line(&self) -> u32 {
        self.raw.dst_line
    }

    /// get the destination (minified) column number
    pub fn get_dst_col(&self) -> u32 {
        self.raw.dst_col
    }

    /// get the destination line and column
    pub fn get_dst(&self) -> (u32, u32) {
        (self.get_dst_line(), self.get_dst_col())
    }

    /// get the source line number
    pub fn get_src_line(&self) -> u32 {
        self.raw.src_line
    }

    /// get the source column number
    pub fn get_src_col(&self) -> u32 {
        self.raw.src_col
    }

    /// get the source line and column
    pub fn get_src(&self) -> (u32, u32) {
        (self.get_src_line(), self.get_src_col())
    }

    /// get the source if it exists as string
    pub fn get_source(&self) -> &str {
        if self.raw.src_id == !0 {
            ""
        } else {
            &self.i.sources[self.raw.src_id as usize][..]
        }
    }

    /// get the name if it exists as string
    pub fn get_name(&self) -> Option<&str> {
        if self.raw.name_id == !0 {
            None
        } else {
            Some(&self.i.names[self.raw.name_id as usize][..])
        }
    }

    /// returns `true` if a name exists, `false` otherwise
    pub fn has_name(&self) -> bool {
        self.get_name().is_some()
    }

    /// Converts the token into a debug tuple in the form
    /// `(source, src_line, src_col, name)`
    pub fn to_tuple(&self) -> (&str, u32, u32, Option<&str>) {
        (
            self.get_source(),
            self.get_src_line(),
            self.get_src_col(),
            self.get_name()
        )
    }

    /// Get the underlying raw token
    pub fn get_raw_token(&self) -> RawToken {
        *self.raw
    }
}

/// Iterates over all tokens in a sourcemap
pub struct TokenIter<'a> {
    i: &'a SourceMap,
    next_idx: u32,
}

impl<'a> Iterator for TokenIter<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Token<'a>> {
        self.i.get_token(self.next_idx).map(|tok| {
            self.next_idx += 1;
            tok
        })
    }
}

/// Iterates over all index items in a sourcemap
pub struct IndexIter<'a> {
    i: &'a SourceMap,
    next_idx: usize,
}

impl<'a> Iterator for IndexIter<'a> {
    type Item = (u32, u32, u32);

    fn next(&mut self) -> Option<(u32, u32, u32)> {
        self.i.index.get(self.next_idx).map(|idx| {
            self.next_idx += 1;
            *idx
        })
    }
}

impl<'a> fmt::Debug for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Token {}>", self)
    }
}

impl<'a> fmt::Display for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}:{}{}",
               self.get_source(),
               self.get_src_line(),
               self.get_src_col(),
               self.get_name().map(|x| format!(" name={}", x))
                   .unwrap_or("".into()))
    }
}

/// Represents a section in a sourcemap index
pub struct SourceMapSection {
    offset: (u32, u32),
    url: Option<String>,
    map: Option<Box<SourceMap>>,
}

/// Iterates over all sections in a sourcemap index
pub struct SourceMapSectionIter<'a> {
    i: &'a SourceMapIndex,
    next_idx: u32,
}

impl<'a> Iterator for SourceMapSectionIter<'a> {
    type Item = &'a SourceMapSection;

    fn next(&mut self) -> Option<&'a SourceMapSection> {
        self.i.get_section(self.next_idx).map(|sec| {
            self.next_idx += 1;
            sec
        })
    }
}

/// Represents a sourcemap index in memory
pub struct SourceMapIndex {
    version: u32,
    file: Option<String>,
    sections: Vec<SourceMapSection>,
}

/// Represents a sourcemap in memory
///
/// This is always represents a regular "non-indexed" sourcemap.  Particularly
/// in case the `from_reader` method is used an index sourcemap will be
/// rejected with an error on reading.
pub struct SourceMap {
    version: u32,
    file: Option<String>,
    tokens: Vec<RawToken>,
    index: Vec<(u32, u32, u32)>,
    names: Vec<String>,
    sources: Vec<String>,
    sources_content: Vec<Option<String>>,
}

impl SourceMap {

    /// Creates a sourcemap from a reader over a JSON stream in UTF-8
    /// format.  Optionally a "garbage header" as defined by the
    /// sourcemap draft specification is supported.  In case an indexed
    /// sourcemap is encountered an error is returned.
    ///
    /// ```rust
    /// use sourcemap::SourceMap;
    /// let input: &[_] = b"{
    ///     \"version\":3,
    ///     \"sources\":[\"coolstuff.js\"],
    ///     \"names\":[\"x\",\"alert\"],
    ///     \"mappings\":\"AAAA,GAAIA,GAAI,EACR,IAAIA,GAAK,EAAG,CACVC,MAAM\"
    /// }";
    /// let sm = SourceMap::from_reader(input).unwrap();
    /// ```
    pub fn from_reader<R: Read>(rdr: R) -> Result<SourceMap> {
        match try!(decode(rdr)) {
            DecodedMap::Regular(sm) => Ok(sm),
            DecodedMap::Index(_) => Err(Error::IndexedSourcemap),
        }
    }

    /// Constructs a new sourcemap from raw components.
    ///
    /// - `version`: the version is typically `3` which is the current darft version
    /// - `file`: an optional filename of the sourcemap
    /// - `tokens`: a list of raw tokens
    /// - `index`: a sorted mapping of line and column to token index
    /// - `names`: a vector of names
    /// - `sources` a vector of source filenames
    /// - `sources_content` optional source contents
    pub fn new(version: u32, file: Option<String>, tokens: Vec<RawToken>,
               index: Vec<(u32, u32, u32)>, names: Vec<String>,
               sources: Vec<String>,
               sources_content: Option<Vec<Option<String>>>) -> SourceMap {
        SourceMap {
            version: version,
            file: file,
            tokens: tokens,
            index: index,
            names: names,
            sources: sources,
            sources_content: sources_content.unwrap_or(vec![]),
        }
    }

    /// Returns the version of the sourcemap.
    pub fn get_version(&self) -> u32 {
        self.version
    }

    /// Returns the embedded filename in case there is one.
    pub fn get_file(&self) -> Option<&str> {
        self.file.as_ref().map(|x| &x[..])
    }

    /// Looks up a token by its index.
    pub fn get_token<'a>(&'a self, idx: u32) -> Option<Token<'a>> {
        self.tokens.get(idx as usize).map(|raw| {
            Token { raw: raw, i: self }
        })
    }

    /// Returns the number of tokens in the sourcemap.
    pub fn get_token_count(&self) -> u32 {
        self.tokens.len() as u32
    }

    /// Returns an iterator over the tokens.
    pub fn tokens<'a>(&'a self) -> TokenIter<'a> {
        TokenIter { i: self, next_idx: 0 }
    }

    /// Looks up the closest token to a given line and column.
    pub fn lookup_token<'a>(&'a self, line: u32, col: u32) -> Option<Token<'a>> {
        let mut low = 0;
        let mut high = self.index.len();

        while low < high {
            let mid = (low + high) / 2;
            if (line, col, 0) < self.index[mid as usize] {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        if low > 0 {
            self.get_token(self.index[low as usize].2)
        } else {
            None
        }
    }

    /// Returns the number of sources in the sourcemap.
    pub fn get_source_count(&self) -> u32 {
        self.sources.len() as u32
    }

    /// Looks up a source for a specific index.
    pub fn get_source(&self, idx: u32) -> Option<&str> {
        self.sources.get(idx as usize).map(|x| &x[..])
    }

    /// Looks up the content for a source.
    pub fn get_source_contents(&self, idx: u32) -> Option<&str> {
        self.sources_content.get(idx as usize)
            .and_then(|bucket| bucket.as_ref()).map(|x| &**x)
    }

    /// Returns the number of names in the sourcemap.
    pub fn get_name_count(&self) -> u32 {
        self.names.len() as u32
    }

    /// Looks up a name for a specific index.
    pub fn get_name(&self, idx: u32) -> Option<&str> {
        self.names.get(idx as usize).map(|x| &x[..])
    }

    /// Returns the number of items in the index
    pub fn get_index_size(&self) -> usize {
        self.index.len()
    }

    /// Returns the number of items in the index
    pub fn index_iter<'a>(&'a self) -> IndexIter<'a> {
        IndexIter { i: self, next_idx: 0 }
    }
}

impl SourceMapIndex {

    /// Creates a sourcemap index from a reader over a JSON stream in UTF-8
    /// format.  Optionally a "garbage header" as defined by the
    /// sourcemap draft specification is supported.  In case a regular
    /// sourcemap is encountered an error is returned.
    pub fn from_reader<R: Read>(rdr: R) -> Result<SourceMapIndex> {
        match try!(decode(rdr)) {
            DecodedMap::Regular(_) => Err(Error::RegularSourcemap),
            DecodedMap::Index(smi) => Ok(smi),
        }
    }

    /// Constructs a new sourcemap index from raw components.
    ///
    /// - `version`: the version is typically `3` which is the current darft version
    /// - `file`: an optional filename of the index
    /// - `sections`: a vector of source map index sections
    pub fn new(version: u32, file: Option<String>,
               sections: Vec<SourceMapSection>) -> SourceMapIndex {
        SourceMapIndex {
            version: version,
            file: file,
            sections: sections,
        }
    }

    /// Returns the version of the sourcemap index.
    pub fn get_version(&self) -> u32 {
        self.version
    }

    /// Returns the embedded filename in case there is one.
    pub fn get_file(&self) -> Option<&str> {
        self.file.as_ref().map(|x| &x[..])
    }

    /// Returns the number of sections in this index
    pub fn get_section_count(&self) -> u32 {
        self.sections.len() as u32
    }

    /// Looks up a single section and returns it
    pub fn get_section(&self, idx: u32) -> Option<&SourceMapSection> {
        self.sections.get(idx as usize)
    }

    /// Looks up a single section and returns it as a mutable ref
    pub fn get_section_mut(&mut self, idx: u32) -> Option<&mut SourceMapSection> {
        self.sections.get_mut(idx as usize)
    }

    /// Iterates over all sections
    pub fn sections<'a>(&'a self) -> SourceMapSectionIter<'a> {
        SourceMapSectionIter {
            i: self,
            next_idx: 0
        }
    }

    /// Looks up the closest token to a given line and column.
    ///
    /// This requires that the referenced sourcemaps are actually loaded.
    /// If a sourcemap is encountered that is not embedded but just
    /// externally referenced it is silently skipped.
    pub fn lookup_token<'a>(&'a self, line: u32, col: u32) -> Option<Token<'a>> {
        for section in self.sections() {
            let (off_line, off_col) = section.get_offset();
            if off_line < line || off_col < col {
                continue;
            }
            if let Some(map) = section.get_sourcemap() {
                if let Some(tok) = map.lookup_token(line - off_line, col - off_col) {
                    return Some(tok);
                }
            }
        }
        None
    }
}

impl SourceMapSection {

    /// Create a new sourcemap index section
    ///
    /// - `offset`: offset as line and column
    /// - `url`: optional URL of where the sourcemap is located
    /// - `map`: an optional already resolved internal sourcemap
    pub fn new(offset: (u32, u32), url: Option<String>, map: Option<SourceMap>) -> SourceMapSection {
        SourceMapSection {
            offset: offset,
            url: url,
            map: map.map(|x| Box::new(x)),
        }
    }

    /// Returns the offset line
    pub fn get_offset_line(&self) -> u32 {
        self.offset.0
    }

    /// Returns the offset column
    pub fn get_offset_col(&self) -> u32 {
        self.offset.1
    }

    /// Returns the offset as tuple
    pub fn get_offset(&self) -> (u32, u32) {
        self.offset
    }

    /// Returns the URL of the referenced map if available
    pub fn get_url(&self) -> Option<&str> {
        self.url.as_ref().map(|x| &**x)
    }

    /// Returns a reference to the embedded sourcemap if available
    pub fn get_sourcemap(&self) -> Option<&SourceMap> {
        self.map.as_ref().map(|x| &**x)
    }

    /// Replaces the embedded sourcemap
    pub fn set_sourcemap(&mut self, sm: SourceMap) {
        self.map = Some(Box::new(sm));
    }
}
<|endoftext|>


<commit_before>//! Useful stuff related to the spaceapi.

/// An ``Optional`` can contain ``Optional::Value<T>`` or ``Optional::Absent``.
/// It is similar to an ``Option``, but ``Optional::Absent`` means it will be
/// omitted when serialized, while ``None`` will be serialized to ``null``.
#[derive(Debug, Copy, Clone)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    pub fn is_absent(&self) -> bool {
        match *self {
            Optional::Absent => true,
            _ => false
        }
    }

}
<commit_msg>spaceapi: Add documentation to `Optional` methods<commit_after>//! Useful stuff related to the spaceapi.

/// An ``Optional`` can contain ``Optional::Value<T>`` or ``Optional::Absent``.
/// It is similar to an ``Option``, but ``Optional::Absent`` means it will be
/// omitted when serialized, while ``None`` will be serialized to ``null``.
#[derive(Debug, Copy, Clone)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    /// Converts from `Optional<T>` to `Optional<&mut T>`
    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Converts from `Optional<T>` to `Optional<&T>`
    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Returns `true` if the optional is a `Absent` value
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(x.is_absent(), false);
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(x.is_absent(), true);
    /// ```
    pub fn is_absent(&self) -> bool {
        match *self {
            Optional::Absent => true,
            _ => false
        }
    }

}
<|endoftext|>


<commit_before>/// Convenience functions for inflating DEFLATE compressed data.
///
/// # Example
/// ```
/// use inflate::inflate_bytes;
/// use std::str::from_utf8;
///
/// let encoded = [243, 72, 205, 201, 201, 215, 81, 40, 207, 47, 202, 73, 1, 0];
/// let decoded = inflate_bytes(&encoded).unwrap();
/// println!("{}", from_utf8(&decoded).unwrap()); // prints "Hello, world"
/// ```

use InflateStream;

fn inflate(inflater: &mut InflateStream, data: &[u8]) -> Result<Vec<u8>, String> {
    let mut decoded = Vec::<u8>::new();

    let mut n = 0;
    loop {
        let (num_bytes_read, bytes) = inflater.update(&data[n..])?;
        if bytes.is_empty() {
            break;
        }
        n += num_bytes_read;
        decoded.extend(bytes.iter().map(|v| *v));
    }

    Ok(decoded)
}

/// Decompress the given slice of DEFLATE compressed data.
///
/// Returns a `Vec` with the decompressed data or an error message.
pub fn inflate_bytes(data: &[u8]) -> Result<Vec<u8>, String> {
    inflate(&mut InflateStream::new(), data)
}

/// Decompress the given slice of DEFLATE compressed (with zlib headers and trailers) data.
///
/// Returns a `Vec` with the decompressed data or an error message.
pub fn inflate_bytes_zlib(data: &[u8]) -> Result<Vec<u8>, String> {
    inflate(&mut InflateStream::from_zlib(), data)
}

/// Decompress the given slice of DEFLATE compressed (with zlib headers and trailers) data,
/// without calculating and validating the checksum.
///
/// Returns a `Vec` with the decompressed data or an error message.
pub fn inflate_bytes_zlib_no_checksum(data: &[u8]) -> Result<Vec<u8>, String> {
    inflate(&mut InflateStream::from_zlib_no_checksum(), data)
}

#[cfg(test)]
mod test {
    #[test]
    fn inflate_bytes_with_zlib() {
        use super::inflate_bytes_zlib;
        use std::str::from_utf8;

        let encoded = [120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201,
                       76, 82, 4, 0, 27, 101, 4, 19];
        let decoded = inflate_bytes_zlib(&encoded).unwrap();
        assert!(from_utf8(&decoded).unwrap() == "Hello, zlib!");
    }

    #[test]
    fn inflate_bytes_with_zlib_checksum_fail() {
        use super::inflate_bytes_zlib;

        // The last 4 bytes are the checksum, we set them to 0 here to check that decoding fails
        // if the checksum is wrong.
        let encoded = [120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201,
                       76, 82, 4, 0, 0, 0, 0, 0];
        inflate_bytes_zlib(&encoded).unwrap_err();
    }

    #[test]
    fn inflate_bytes_with_zlib_trailing() {
        use super::inflate_bytes_zlib;
        use std::str::from_utf8;

        // The additional 4 bytes should be ignored.
        let encoded = [120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201,
                       76, 82, 4, 0, 27, 101, 4, 19, 0, 0, 0, 0];
        let decoded = inflate_bytes_zlib(&encoded).unwrap();
        assert!(from_utf8(&decoded).unwrap() == "Hello, zlib!");
    }

}
<commit_msg>Use `extended_from_slice`<commit_after>/// Convenience functions for inflating DEFLATE compressed data.
///
/// # Example
/// ```
/// use inflate::inflate_bytes;
/// use std::str::from_utf8;
///
/// let encoded = [243, 72, 205, 201, 201, 215, 81, 40, 207, 47, 202, 73, 1, 0];
/// let decoded = inflate_bytes(&encoded).unwrap();
/// println!("{}", from_utf8(&decoded).unwrap()); // prints "Hello, world"
/// ```

use InflateStream;

fn inflate(inflater: &mut InflateStream, data: &[u8]) -> Result<Vec<u8>, String> {
    let mut decoded = Vec::<u8>::new();

    let mut n = 0;
    loop {
        let (num_bytes_read, bytes) = inflater.update(&data[n..])?;
        if bytes.is_empty() {
            break;
        }
        n += num_bytes_read;
        decoded.extend_from_slice(bytes);
    }

    Ok(decoded)
}

/// Decompress the given slice of DEFLATE compressed data.
///
/// Returns a `Vec` with the decompressed data or an error message.
pub fn inflate_bytes(data: &[u8]) -> Result<Vec<u8>, String> {
    inflate(&mut InflateStream::new(), data)
}

/// Decompress the given slice of DEFLATE compressed (with zlib headers and trailers) data.
///
/// Returns a `Vec` with the decompressed data or an error message.
pub fn inflate_bytes_zlib(data: &[u8]) -> Result<Vec<u8>, String> {
    inflate(&mut InflateStream::from_zlib(), data)
}

/// Decompress the given slice of DEFLATE compressed (with zlib headers and trailers) data,
/// without calculating and validating the checksum.
///
/// Returns a `Vec` with the decompressed data or an error message.
pub fn inflate_bytes_zlib_no_checksum(data: &[u8]) -> Result<Vec<u8>, String> {
    inflate(&mut InflateStream::from_zlib_no_checksum(), data)
}

#[cfg(test)]
mod test {
    #[test]
    fn inflate_bytes_with_zlib() {
        use super::inflate_bytes_zlib;
        use std::str::from_utf8;

        let encoded = [120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201,
                       76, 82, 4, 0, 27, 101, 4, 19];
        let decoded = inflate_bytes_zlib(&encoded).unwrap();
        assert!(from_utf8(&decoded).unwrap() == "Hello, zlib!");
    }

    #[test]
    fn inflate_bytes_with_zlib_checksum_fail() {
        use super::inflate_bytes_zlib;

        // The last 4 bytes are the checksum, we set them to 0 here to check that decoding fails
        // if the checksum is wrong.
        let encoded = [120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201,
                       76, 82, 4, 0, 0, 0, 0, 0];
        inflate_bytes_zlib(&encoded).unwrap_err();
    }

    #[test]
    fn inflate_bytes_with_zlib_trailing() {
        use super::inflate_bytes_zlib;
        use std::str::from_utf8;

        // The additional 4 bytes should be ignored.
        let encoded = [120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201,
                       76, 82, 4, 0, 27, 101, 4, 19, 0, 0, 0, 0];
        let decoded = inflate_bytes_zlib(&encoded).unwrap();
        assert!(from_utf8(&decoded).unwrap() == "Hello, zlib!");
    }

}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![crate_name="struct_variant_xc_aux"]
#![crate_type = "lib"]

pub enum Enum {
    Variant(u8),
    StructVariant { arg: u8 }
}
<commit_msg>test: silence a warning<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![crate_name="struct_variant_xc_aux"]
#![crate_type = "lib"]

#[derive(Copy)]
pub enum Enum {
    Variant(u8),
    StructVariant { arg: u8 }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate std;
extern crate getopts;
extern crate test;

use test::{TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use getopts::{getopts, reqopt};
use std::{os, str};
use std::io::fs;
use std::io::Reader;
use std::io::process::{Process, ProcessConfig, Ignored, CreatePipe, InheritFd, ExitStatus};

#[deriving(Clone)]
struct Config {
    source_dir: ~str,
    filter: Option<~str>
}

fn main() {
    let args = os::args();
    let config = parse_config(args);
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    match run_tests_console(&opts, tests) {
        Ok(false) => os::set_exit_status(1), // tests failed
        Err(_) => os::set_exit_status(2),    // I/O-related failure
        _ => (),
    }
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt("s", "source-dir", "source-dir", "source-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail!(f.to_err_msg())
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some(matches.free.as_slice().head().unwrap().clone())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        ratchet_metrics: None,
        ratchet_noise_percent: None,
        save_metrics: None,
        test_shard: None,
        logfile: None
    }
}

fn find_tests(config: Config) -> Vec<TestDescAndFn> {
    let files_res = fs::readdir(&Path::new(config.source_dir));
    let mut files = match files_res {
        Ok(files) => files,
        _ => fail!("Error reading directory."),
    };
    files.retain(|file| file.extension_str() == Some("html") );
    return files.iter().map(|file| make_test(file.display().to_str()) ).collect();
}

fn make_test(file: ~str) -> TestDescAndFn {
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file.clone()),
            ignore: false,
            should_fail: false
        },
        testfn: DynTestFn(proc() { run_test(file) })
    }
}

fn run_test(file: ~str) {
    let path = os::make_absolute(&Path::new(file));
    // FIXME (#1094): not the right way to transform a path
    let infile = ~"file://" + path.display().to_str();
    let stdout = CreatePipe(false, true);
    let stderr = InheritFd(2);

    let config = ProcessConfig {
        program: "./servo",
        args: &[~"-z", ~"-f", infile.clone()],
        stdin: Ignored,
        stdout: stdout,
        stderr: stderr,
        .. ProcessConfig::new()
    };
    let mut prc = match Process::configure(config) {
        Ok(p) => p,
        _ => fail!("Unable to configure process."),
    };
    let mut output = ~[];
    loop {
        let byte = prc.stdout.get_mut_ref().read_byte();
        match byte {
            Ok(byte) => {
                print!("{}", byte as char);
                output.push(byte);
            }
            _ => break
        }
    }

    let out = str::from_utf8(output);
    let lines: ~[&str] = out.unwrap().split('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            fail!(line.to_owned());
        }
    }

    let retval = prc.wait();
    if retval != ExitStatus(0) {
        fail!("Servo exited with non-zero status {}", retval);
    }
}
<commit_msg>~[] to Vec in harness/contenttest/contenttest.rs<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate std;
extern crate getopts;
extern crate test;

use test::{TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use getopts::{getopts, reqopt};
use std::{os, str};
use std::io::fs;
use std::io::Reader;
use std::io::process::{Process, ProcessConfig, Ignored, CreatePipe, InheritFd, ExitStatus};

#[deriving(Clone)]
struct Config {
    source_dir: ~str,
    filter: Option<~str>
}

fn main() {
    let args = os::args();
    let config = parse_config(args);
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    match run_tests_console(&opts, tests) {
        Ok(false) => os::set_exit_status(1), // tests failed
        Err(_) => os::set_exit_status(2),    // I/O-related failure
        _ => (),
    }
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt("s", "source-dir", "source-dir", "source-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail!(f.to_err_msg())
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some(matches.free.as_slice().head().unwrap().clone())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        ratchet_metrics: None,
        ratchet_noise_percent: None,
        save_metrics: None,
        test_shard: None,
        logfile: None
    }
}

fn find_tests(config: Config) -> Vec<TestDescAndFn> {
    let files_res = fs::readdir(&Path::new(config.source_dir));
    let mut files = match files_res {
        Ok(files) => files,
        _ => fail!("Error reading directory."),
    };
    files.retain(|file| file.extension_str() == Some("html") );
    return files.iter().map(|file| make_test(file.display().to_str()) ).collect();
}

fn make_test(file: ~str) -> TestDescAndFn {
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file.clone()),
            ignore: false,
            should_fail: false
        },
        testfn: DynTestFn(proc() { run_test(file) })
    }
}

fn run_test(file: ~str) {
    let path = os::make_absolute(&Path::new(file));
    // FIXME (#1094): not the right way to transform a path
    let infile = ~"file://" + path.display().to_str();
    let stdout = CreatePipe(false, true);
    let stderr = InheritFd(2);

    let config = ProcessConfig {
        program: "./servo",
        args: &[~"-z", ~"-f", infile.clone()],
        stdin: Ignored,
        stdout: stdout,
        stderr: stderr,
        .. ProcessConfig::new()
    };
    let mut prc = match Process::configure(config) {
        Ok(p) => p,
        _ => fail!("Unable to configure process."),
    };
    let mut output = Vec::new();
    loop {
        let byte = prc.stdout.get_mut_ref().read_byte();
        match byte {
            Ok(byte) => {
                print!("{}", byte as char);
                output.push(byte);
            }
            _ => break
        }
    }

    let out = str::from_utf8(output.as_slice());
    let lines: ~[&str] = out.unwrap().split('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            fail!(line.to_owned());
        }
    }

    let retval = prc.wait();
    if retval != ExitStatus(0) {
        fail!("Servo exited with non-zero status {}", retval);
    }
}
<|endoftext|>