<commit_before>extern crate lmdb_rs as lmdb;

use lmdb::{FromMdbValue, ToMdbValue};
use lmdb::core::{MdbResult, Transaction};
use std::marker::PhantomData;

pub trait Tablename {
    fn as_str() -> &'static str;
}

pub trait IsNativeInt {}
impl IsNativeInt for i32 {}
impl IsNativeInt for u32 {}
impl IsNativeInt for i64 {}
impl IsNativeInt for u64 {}

/// A table that maps an integer to a set of integers.
/// Keys K1 and K2 must be native integers!
#[derive(Clone)]
pub struct IntToIntsTable<K1, K2, T> {
    pub db: lmdb::DbHandle,
    _k1: PhantomData<K1>,
    _k2: PhantomData<K2>,
    _t: PhantomData<T>,
}

/// A table that maps an integer to a blob.
#[derive(Clone)]
pub struct IntToBlobTable<K, T> {
    pub db: lmdb::DbHandle,
    _k: PhantomData<K>,
    _t: PhantomData<T>,
}

/// A table that maps an object of type `K` to a blob.
#[derive(Clone)]
pub struct KeyToBlobTable<K, T> {
    pub db: lmdb::DbHandle,
    _k: PhantomData<K>,
    _t: PhantomData<T>,
}

/// A table that maps an integer to a record/struct.
#[derive(Clone)]
pub struct IntToRecordTable<K, V, T> {
    pub db: lmdb::DbHandle,
    _k: PhantomData<K>,
    _v: PhantomData<V>,
    _t: PhantomData<T>,
}

/// Bound IntToRecordTable.
pub struct BoundIntToRecordTable<'a, K, V, T> {
    db: lmdb::Database<'a>,
    _k: PhantomData<K>,
    _v: PhantomData<V>,
    _t: PhantomData<T>,
}

/* Implementations */

impl<K1, K2, T> IntToIntsTable<K1, K2, T>
where K1: Sized + ToMdbValue + IsNativeInt + FromMdbValue,
      K2: Sized + ToMdbValue + IsNativeInt,
      T: Tablename
{
    fn flags() -> lmdb::core::DbFlags {
        lmdb::core::DbIntKey |
        lmdb::core::DbAllowDups | lmdb::core::DbAllowIntDups |
        lmdb::core::DbDupFixed
    }

    pub fn create(env: &lmdb::Environment) -> IntToIntsTable<K1, K2, T> {
        IntToIntsTable::new_from_handle(env.create_db(T::as_str(), Self::flags()).unwrap())
    }

    pub fn open(env: &lmdb::Environment) -> IntToIntsTable<K1, K2, T> {
        IntToIntsTable::new_from_handle(env.get_db(T::as_str(), Self::flags()).unwrap())
    }

    fn new_from_handle(db: lmdb::DbHandle) -> IntToIntsTable<K1, K2, T> {
        IntToIntsTable {db: db, _k1: PhantomData, _k2: PhantomData, _t: PhantomData}
    }

    // XXX: Can we optimize this, when iter is already sorted for example?
    pub fn insert_multiple<I>(&self, txn: &Transaction, iter: I) -> MdbResult<()> where I: Iterator<Item=(K1,K2)> {
        let db = txn.bind(&self.db);
        for (ref k1, ref k2) in iter {
            try!(db.set(k1, k2));
        }
        Ok(())
    }

    pub fn insert(&self, txn: &Transaction, kv: &(K1, K2)) -> MdbResult<()> {
        let db = txn.bind(&self.db);
        db.set(&kv.0, &kv.1)
    }

    fn last_key(&self, txn: &lmdb::core::ReadonlyTransaction) -> MdbResult<K1> {
        let db = txn.bind(&self.db);
        let mut cursor = try!(db.new_cursor());
        try!(cursor.to_last());
        cursor.get_key()
    }
}

impl<K, T> IntToBlobTable<K, T>
where K: Sized + ToMdbValue + IsNativeInt,
      T: Tablename
{
    fn flags() -> lmdb::core::DbFlags {
        lmdb::core::DbIntKey
    }

    pub fn create(env: &lmdb::Environment) -> IntToBlobTable<K, T> {
        IntToBlobTable::new_from_handle(env.create_db(T::as_str(), Self::flags()).unwrap())
    }

    pub fn open(env: &lmdb::Environment) -> IntToBlobTable<K, T> {
        IntToBlobTable::new_from_handle(env.get_db(T::as_str(), Self::flags()).unwrap())
    }

    fn new_from_handle(db: lmdb::DbHandle) -> IntToBlobTable<K, T> {
        IntToBlobTable {db: db, _k: PhantomData, _t: PhantomData}
    }

    pub fn insert(&self, txn: &Transaction, key: &K, val: &[u8]) -> MdbResult<()> {
        let db = txn.bind(&self.db);
        db.insert(key, &val)
    }

    // fn lookup
}

impl<K, T> KeyToBlobTable<K, T>
where K: Sized + ToMdbValue,
      T: Tablename
{
    fn flags() -> lmdb::core::DbFlags {
        lmdb::core::DbFlags::empty()
    }

    pub fn create(env: &lmdb::Environment) -> KeyToBlobTable<K, T> {
        KeyToBlobTable::new_from_handle(env.create_db(T::as_str(), Self::flags()).unwrap())
    }

    pub fn open(env: &lmdb::Environment) -> KeyToBlobTable<K, T> {
        KeyToBlobTable::new_from_handle(env.get_db(T::as_str(), Self::flags()).unwrap())
    }

    fn new_from_handle(db: lmdb::DbHandle) -> KeyToBlobTable<K, T> {
        KeyToBlobTable {db: db, _k: PhantomData, _t: PhantomData}
    }

    pub fn insert(&self, txn: &Transaction, key: &K, val: &[u8]) -> MdbResult<()> {
        let db = txn.bind(&self.db);
        db.insert(key, &val)
    }

    // fn lookup
}

//
// A unique(native-int) -> sized record value lookup table
//

impl<K, V, T> IntToRecordTable<K, V, T>
where K: Sized + ToMdbValue + IsNativeInt,
      V: Sized + ToMdbValue + FromMdbValue,
      T: Tablename
{
    fn flags() -> lmdb::core::DbFlags {
        lmdb::core::DbIntKey
    }

    pub fn create(env: &lmdb::Environment) -> IntToRecordTable<K, V, T> {
        IntToRecordTable::new_from_handle(env.create_db(T::as_str(), Self::flags()).unwrap())
    }

    pub fn open(env: &lmdb::Environment) -> IntToRecordTable<K, V, T> {
        IntToRecordTable::new_from_handle(env.get_db(T::as_str(), Self::flags()).unwrap())
    }

    fn new_from_handle(db: lmdb::DbHandle) -> IntToRecordTable<K, V, T> {
        IntToRecordTable {db: db, _k: PhantomData, _v: PhantomData, _t: PhantomData}
    }

    pub fn bind_to_txn<'a>(&self, txn: &'a lmdb::Transaction) -> BoundIntToRecordTable<'a, K, V, T> {
        BoundIntToRecordTable {
            db: txn.bind(&self.db),
            _k: PhantomData, _v: PhantomData, _t: PhantomData}
    }

    pub fn bind_to_ro_txn<'a>(&self, txn: &'a lmdb::ReadonlyTransaction) -> BoundIntToRecordTable<'a, K, V, T> {
        BoundIntToRecordTable {
            db: txn.bind(&self.db),
            _k: PhantomData, _v: PhantomData, _t: PhantomData}
    }
}

impl<'a, K, V, T> BoundIntToRecordTable<'a, K, V, T>
where K: Sized + ToMdbValue + IsNativeInt,
      V: Sized + ToMdbValue + FromMdbValue,
      T: Tablename
{
    // fails if key exists.
    pub fn insert(&self, key: &K, val: &V) -> MdbResult<()> {
        self.db.insert(key, val)
    }

    // XXX: Should go into ReadonlyBound...
    pub fn lookup(&self, key: &K) -> MdbResult<V> {
        self.db.get::<V>(key)
    }

    pub fn update<F>(&self, key: &K, update: F) -> MdbResult<()>
        where F: Fn(&mut V) -> bool {

        let mut cursor = try!(self.db.new_cursor());
        try!(cursor.to_key(key));

        let mut value: V = try!(cursor.get_value());

        let needs_update = update(&mut value);

        if needs_update {
            try!(cursor.replace(&value));
        }

        Ok(())
    }

    pub fn insert_or_update<N, F>(&self, key: &K, insert_fn: N, update_fn: F) -> MdbResult<()>
        where
                N: Fn() -> V,
                F: Fn(&mut V) -> bool {

        // Trying to update first
        {
                let mut cursor = try!(self.db.new_cursor());
                if let Ok(_) = cursor.to_key(key) {
                        let mut value: V = try!(cursor.get_value());
                        let needs_update = update_fn(&mut value);
                        if needs_update {
                                try!(cursor.replace(&value));
                        }
                        return Ok(());
                }
        }

        // Now try to insert
        {
            let value: V = insert_fn();
            try!(self.db.insert(key, &value));
            return Ok(());
        }
    }

}
<commit_msg>Add insert_or_update_default() function<commit_after>extern crate lmdb_rs as lmdb;

use lmdb::{FromMdbValue, ToMdbValue};
use lmdb::core::{MdbResult, Transaction};
use std::marker::PhantomData;

pub trait Tablename {
    fn as_str() -> &'static str;
}

pub trait IsNativeInt {}
impl IsNativeInt for i32 {}
impl IsNativeInt for u32 {}
impl IsNativeInt for i64 {}
impl IsNativeInt for u64 {}

/// A table that maps an integer to a set of integers.
/// Keys K1 and K2 must be native integers!
#[derive(Clone)]
pub struct IntToIntsTable<K1, K2, T> {
    pub db: lmdb::DbHandle,
    _k1: PhantomData<K1>,
    _k2: PhantomData<K2>,
    _t: PhantomData<T>,
}

/// A table that maps an integer to a blob.
#[derive(Clone)]
pub struct IntToBlobTable<K, T> {
    pub db: lmdb::DbHandle,
    _k: PhantomData<K>,
    _t: PhantomData<T>,
}

/// A table that maps an object of type `K` to a blob.
#[derive(Clone)]
pub struct KeyToBlobTable<K, T> {
    pub db: lmdb::DbHandle,
    _k: PhantomData<K>,
    _t: PhantomData<T>,
}

/// A table that maps an integer to a record/struct.
#[derive(Clone)]
pub struct IntToRecordTable<K, V, T> {
    pub db: lmdb::DbHandle,
    _k: PhantomData<K>,
    _v: PhantomData<V>,
    _t: PhantomData<T>,
}

/// Bound IntToRecordTable.
pub struct BoundIntToRecordTable<'a, K, V, T> {
    db: lmdb::Database<'a>,
    _k: PhantomData<K>,
    _v: PhantomData<V>,
    _t: PhantomData<T>,
}

/* Implementations */

impl<K1, K2, T> IntToIntsTable<K1, K2, T>
where K1: Sized + ToMdbValue + IsNativeInt + FromMdbValue,
      K2: Sized + ToMdbValue + IsNativeInt,
      T: Tablename
{
    fn flags() -> lmdb::core::DbFlags {
        lmdb::core::DbIntKey |
        lmdb::core::DbAllowDups | lmdb::core::DbAllowIntDups |
        lmdb::core::DbDupFixed
    }

    pub fn create(env: &lmdb::Environment) -> IntToIntsTable<K1, K2, T> {
        IntToIntsTable::new_from_handle(env.create_db(T::as_str(), Self::flags()).unwrap())
    }

    pub fn open(env: &lmdb::Environment) -> IntToIntsTable<K1, K2, T> {
        IntToIntsTable::new_from_handle(env.get_db(T::as_str(), Self::flags()).unwrap())
    }

    fn new_from_handle(db: lmdb::DbHandle) -> IntToIntsTable<K1, K2, T> {
        IntToIntsTable {db: db, _k1: PhantomData, _k2: PhantomData, _t: PhantomData}
    }

    // XXX: Can we optimize this, when iter is already sorted for example?
    pub fn insert_multiple<I>(&self, txn: &Transaction, iter: I) -> MdbResult<()> where I: Iterator<Item=(K1,K2)> {
        let db = txn.bind(&self.db);
        for (ref k1, ref k2) in iter {
            try!(db.set(k1, k2));
        }
        Ok(())
    }

    pub fn insert(&self, txn: &Transaction, kv: &(K1, K2)) -> MdbResult<()> {
        let db = txn.bind(&self.db);
        db.set(&kv.0, &kv.1)
    }

    fn last_key(&self, txn: &lmdb::core::ReadonlyTransaction) -> MdbResult<K1> {
        let db = txn.bind(&self.db);
        let mut cursor = try!(db.new_cursor());
        try!(cursor.to_last());
        cursor.get_key()
    }
}

impl<K, T> IntToBlobTable<K, T>
where K: Sized + ToMdbValue + IsNativeInt,
      T: Tablename
{
    fn flags() -> lmdb::core::DbFlags {
        lmdb::core::DbIntKey
    }

    pub fn create(env: &lmdb::Environment) -> IntToBlobTable<K, T> {
        IntToBlobTable::new_from_handle(env.create_db(T::as_str(), Self::flags()).unwrap())
    }

    pub fn open(env: &lmdb::Environment) -> IntToBlobTable<K, T> {
        IntToBlobTable::new_from_handle(env.get_db(T::as_str(), Self::flags()).unwrap())
    }

    fn new_from_handle(db: lmdb::DbHandle) -> IntToBlobTable<K, T> {
        IntToBlobTable {db: db, _k: PhantomData, _t: PhantomData}
    }

    pub fn insert(&self, txn: &Transaction, key: &K, val: &[u8]) -> MdbResult<()> {
        let db = txn.bind(&self.db);
        db.insert(key, &val)
    }

    // fn lookup
}

impl<K, T> KeyToBlobTable<K, T>
where K: Sized + ToMdbValue,
      T: Tablename
{
    fn flags() -> lmdb::core::DbFlags {
        lmdb::core::DbFlags::empty()
    }

    pub fn create(env: &lmdb::Environment) -> KeyToBlobTable<K, T> {
        KeyToBlobTable::new_from_handle(env.create_db(T::as_str(), Self::flags()).unwrap())
    }

    pub fn open(env: &lmdb::Environment) -> KeyToBlobTable<K, T> {
        KeyToBlobTable::new_from_handle(env.get_db(T::as_str(), Self::flags()).unwrap())
    }

    fn new_from_handle(db: lmdb::DbHandle) -> KeyToBlobTable<K, T> {
        KeyToBlobTable {db: db, _k: PhantomData, _t: PhantomData}
    }

    pub fn insert(&self, txn: &Transaction, key: &K, val: &[u8]) -> MdbResult<()> {
        let db = txn.bind(&self.db);
        db.insert(key, &val)
    }

    // fn lookup
}

//
// A unique(native-int) -> sized record value lookup table
//

impl<K, V, T> IntToRecordTable<K, V, T>
where K: Sized + ToMdbValue + IsNativeInt,
      V: Sized + ToMdbValue + FromMdbValue,
      T: Tablename
{
    fn flags() -> lmdb::core::DbFlags {
        lmdb::core::DbIntKey
    }

    pub fn create(env: &lmdb::Environment) -> IntToRecordTable<K, V, T> {
        IntToRecordTable::new_from_handle(env.create_db(T::as_str(), Self::flags()).unwrap())
    }

    pub fn open(env: &lmdb::Environment) -> IntToRecordTable<K, V, T> {
        IntToRecordTable::new_from_handle(env.get_db(T::as_str(), Self::flags()).unwrap())
    }

    fn new_from_handle(db: lmdb::DbHandle) -> IntToRecordTable<K, V, T> {
        IntToRecordTable {db: db, _k: PhantomData, _v: PhantomData, _t: PhantomData}
    }

    pub fn bind_to_txn<'a>(&self, txn: &'a lmdb::Transaction) -> BoundIntToRecordTable<'a, K, V, T> {
        BoundIntToRecordTable {
            db: txn.bind(&self.db),
            _k: PhantomData, _v: PhantomData, _t: PhantomData}
    }

    pub fn bind_to_ro_txn<'a>(&self, txn: &'a lmdb::ReadonlyTransaction) -> BoundIntToRecordTable<'a, K, V, T> {
        BoundIntToRecordTable {
            db: txn.bind(&self.db),
            _k: PhantomData, _v: PhantomData, _t: PhantomData}
    }
}

impl<'a, K, V, T> BoundIntToRecordTable<'a, K, V, T>
where K: Sized + ToMdbValue + IsNativeInt,
      V: Sized + ToMdbValue + FromMdbValue,
      T: Tablename
{
    // fails if key exists.
    pub fn insert(&self, key: &K, val: &V) -> MdbResult<()> {
        self.db.insert(key, val)
    }

    // XXX: Should go into ReadonlyBound...
    pub fn lookup(&self, key: &K) -> MdbResult<V> {
        self.db.get::<V>(key)
    }

    pub fn update<F>(&self, key: &K, update: F) -> MdbResult<()>
        where F: Fn(&mut V) -> bool {

        let mut cursor = try!(self.db.new_cursor());
        try!(cursor.to_key(key));

        let mut value: V = try!(cursor.get_value());

        let needs_update = update(&mut value);

        if needs_update {
            try!(cursor.replace(&value));
        }

        Ok(())
    }

    pub fn insert_or_update<N, F>(&self, key: &K, insert_fn: N, update_fn: F) -> MdbResult<()>
        where
                N: Fn() -> V,
                F: Fn(&mut V) -> bool {

        // Trying to update first
        {
                let mut cursor = try!(self.db.new_cursor());
                if let Ok(_) = cursor.to_key(key) {
                        let mut value: V = try!(cursor.get_value());
                        let needs_update = update_fn(&mut value);
                        if needs_update {
                                try!(cursor.replace(&value));
                        }
                        return Ok(());
                }
        }

        // Now try to insert
        {
            let value: V = insert_fn();
            try!(self.db.insert(key, &value));
            return Ok(());
        }
    }

    pub fn insert_or_update_default<F>(&self, key: &K, mut update_fn: F) -> MdbResult<()>
        where
                V: Default,
                F: FnMut(&mut V) -> bool {

        // Trying to update first
        {
                let mut cursor = try!(self.db.new_cursor());
                if let Ok(_) = cursor.to_key(key) {
                        let mut value: V = try!(cursor.get_value());
                        let needs_update = update_fn(&mut value);
                        if needs_update {
                                try!(cursor.replace(&value));
                        }
                        return Ok(());
                }
        }

        // Now try to insert
        {
            let mut value: V = V::default();
            let needs_update = update_fn(&mut value);
            if needs_update {
                try!(self.db.insert(key, &value));
            }
            return Ok(());
        }
    }
}
<|endoftext|>


<commit_before>pub trait CaseExt {
    type Owned;

    /// Create a new string from a string slice with replacing the first character with its
    /// to ASCII upper case counterpart (if one exists).
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&CaseExt::to_capitalized("stringy string"), "Stringy string");
    /// assert_eq!(&CaseExt::to_capitalized("言語"), "言語");
    /// ```
    fn to_capitalized(&self) -> Self::Owned;

    /// Check whether a string is capitalized.
    ///
    /// If the the list is empty, the string is not considered capitalized.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!("Stringy string".is_capitalized(), true);
    /// assert_eq!("hello world".is_capitalized(), false);
    /// assert_eq!("".is_capitalized(), false);
    /// ```
    fn is_capitalized(&self) -> bool;

    /// Convert a string slice from snake case to a new capitalized camel case string.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&"a_string_and_a_miss".to_camel(), "AStringAndAMiss");
    /// assert_eq!(&"fooby".to_camel(), "Fooby");
    /// assert_eq!(&"_wild__underscore_s_".to_camel(), "WildUnderscoreS");
    /// assert_eq!(&"言_語".to_camel(), "言語");
    /// ```
    fn to_camel(&self) -> Self::Owned;

    /// Convert a string slice from snake case to a new uncapitalized camel case string.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&"string_henry_iii".to_camel_lowercase(), "stringHenryIii");
    /// assert_eq!(&"fooby".to_camel_lowercase(), "fooby");
    /// assert_eq!(&"_wild__underscore_s_".to_camel_lowercase(), "WildUnderscoreS");
    /// assert_eq!(&"言_語".to_camel_lowercase(), "言語");
    /// ```
    fn to_camel_lowercase(&self) -> Self::Owned;

    /// Check whether a string is in camel lowercase.
    ///
    /// If the the list is empty, the string is not considered camel lowercase.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!("Stringy string".is_camel_lowercase(), false);
    /// assert_eq!("helloWorld".is_camel_lowercase(), true);
    /// assert_eq!("WildUnderscoreS".is_camel_lowercase(), false);
    /// assert_eq!("".is_capitalized(), false);
    /// ```
    fn is_camel_lowercase(&self) -> bool;

    /// Convert a string from camel case to snake case.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&"martinLutherStringJr".to_snake(), "martin_luther_string_jr");
    /// assert_eq!(&"fooby".to_snake(), "fooby");
    /// assert_eq!(&"WildUnderscoreS".to_snake(), "wild_underscore_s");
    /// assert_eq!(&"言語".to_snake(), "言語");
    /// ```
    fn to_snake(&self) -> Self::Owned;

    /// Replaces underscores with dashes in a string.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&"stringing_in_the_rain".to_dashed(), "stringing-in-the-rain");
    /// ```
    fn to_dashed(&self) -> Self::Owned;
}

impl CaseExt for str {
    type Owned = String;

    fn to_capitalized(&self) -> Self::Owned {
        let mut result = String::with_capacity(self.len());

        for (i, c) in self.chars().enumerate() {
            result.push(if i == 0 {
                c.to_ascii_uppercase()
            } else {
                c
            });
        }

        result
    }

    fn is_capitalized(&self) -> bool {
        if let Some(first) = self.chars().next() {
            first.is_uppercase()
        } else {
            false
        }
    }

    fn to_camel(&self) -> String {
        to_camel_internal(self, true)
    }

    fn is_camel_lowercase(&self) -> bool {
        match self.chars().next() {
            Some(first) if first.is_uppercase() => return false,
            _ => ()
        }

        !self.contains('_')
    }

    fn to_camel_lowercase(&self) -> String {
        to_camel_internal(self, false)
    }

    fn to_snake(&self) -> String {
        // The first character is never prepended with an underscore, so skip it even if it is an
        // uppercase ASCII character.
        let underscore_count = self.chars().skip(1).filter(|&c| is_ascii_uppercase(c)).count();
        let mut result = String::with_capacity(self.len() + underscore_count);

        for (i, c) in self.chars().enumerate() {
            if is_ascii_uppercase(c) {
                if i != 0 {
                    result.push('_');
                }
                result.push(c.to_ascii_lowercase());
            } else {
                result.push(c);
            }
        }

        result
    }

    fn to_dashed(&self) -> String {
        let mut result = String::with_capacity(self.len());

        for c in self.chars() {
            result.push(match c {
                '_' => '-',
                c => c
            });
        }

        result
    }
}

fn to_camel_internal(term: &str, uppercase_first_letter: bool) -> String {
    let underscore_count = term.chars().filter(|c| *c == '_').count();
    let mut result = String::with_capacity(term.len() - underscore_count);
    let mut at_new_word = uppercase_first_letter;

    for c in term.chars() {
        if c == '_' {
            at_new_word = true;
        } else if at_new_word {
            result.push(c.to_ascii_uppercase());
            at_new_word = false;
        } else {
            result.push(c);
        }
    }

    result
}

#[inline]
fn is_ascii_uppercase(c: char) -> bool {
    c >= 'A' && c <= 'Z'
}
<commit_msg>Fix the weird behavior of to_camel_lowercase with leading underscores.<commit_after>pub trait CaseExt {
    type Owned;

    /// Create a new string from a string slice with replacing the first character with its
    /// to ASCII upper case counterpart (if one exists).
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&CaseExt::to_capitalized("stringy string"), "Stringy string");
    /// assert_eq!(&CaseExt::to_capitalized("言語"), "言語");
    /// ```
    fn to_capitalized(&self) -> Self::Owned;

    /// Check whether a string is capitalized.
    ///
    /// If the the list is empty, the string is not considered capitalized.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!("Stringy string".is_capitalized(), true);
    /// assert_eq!("hello world".is_capitalized(), false);
    /// assert_eq!("".is_capitalized(), false);
    /// ```
    fn is_capitalized(&self) -> bool;

    /// Convert a string slice from snake case to a new capitalized camel case string.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&"a_string_and_a_miss".to_camel(), "AStringAndAMiss");
    /// assert_eq!(&"fooby".to_camel(), "Fooby");
    /// assert_eq!(&"_wild__underscore_s_".to_camel(), "WildUnderscoreS");
    /// assert_eq!(&"言_語".to_camel(), "言語");
    /// ```
    fn to_camel(&self) -> Self::Owned;

    /// Convert a string slice from snake case to a new uncapitalized camel case string.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&"string_henry_iii".to_camel_lowercase(), "stringHenryIii");
    /// assert_eq!(&"fooby".to_camel_lowercase(), "fooby");
    /// assert_eq!(&"_wild__underscore_s_".to_camel_lowercase(), "wildUnderscoreS");
    /// assert_eq!(&"言_語".to_camel_lowercase(), "言語");
    /// ```
    fn to_camel_lowercase(&self) -> Self::Owned;

    /// Check whether a string is in camel lowercase.
    ///
    /// If the the list is empty, the string is not considered camel lowercase.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!("Stringy string".is_camel_lowercase(), false);
    /// assert_eq!("helloWorld".is_camel_lowercase(), true);
    /// assert_eq!("WildUnderscoreS".is_camel_lowercase(), false);
    /// assert_eq!("".is_capitalized(), false);
    /// ```
    fn is_camel_lowercase(&self) -> bool;

    /// Convert a string from camel case to snake case.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&"martinLutherStringJr".to_snake(), "martin_luther_string_jr");
    /// assert_eq!(&"fooby".to_snake(), "fooby");
    /// assert_eq!(&"WildUnderscoreS".to_snake(), "wild_underscore_s");
    /// assert_eq!(&"言語".to_snake(), "言語");
    /// ```
    fn to_snake(&self) -> Self::Owned;

    /// Replaces underscores with dashes in a string.
    ///
    /// # Examples
    ///
    /// ```
    /// use case::CaseExt;
    ///
    /// assert_eq!(&"stringing_in_the_rain".to_dashed(), "stringing-in-the-rain");
    /// ```
    fn to_dashed(&self) -> Self::Owned;
}

impl CaseExt for str {
    type Owned = String;

    fn to_capitalized(&self) -> Self::Owned {
        let mut result = String::with_capacity(self.len());

        for (i, c) in self.chars().enumerate() {
            result.push(if i == 0 {
                c.to_ascii_uppercase()
            } else {
                c
            });
        }

        result
    }

    fn is_capitalized(&self) -> bool {
        if let Some(first) = self.chars().next() {
            first.is_uppercase()
        } else {
            false
        }
    }

    fn to_camel(&self) -> String {
        to_camel_internal(self, true)
    }

    fn is_camel_lowercase(&self) -> bool {
        match self.chars().next() {
            Some(first) if first.is_uppercase() => return false,
            _ => ()
        }

        !self.contains('_')
    }

    fn to_camel_lowercase(&self) -> String {
        to_camel_internal(self, false)
    }

    fn to_snake(&self) -> String {
        // The first character is never prepended with an underscore, so skip it even if it is an
        // uppercase ASCII character.
        let underscore_count = self.chars().skip(1).filter(|&c| is_ascii_uppercase(c)).count();
        let mut result = String::with_capacity(self.len() + underscore_count);

        for (i, c) in self.chars().enumerate() {
            if is_ascii_uppercase(c) {
                if i != 0 {
                    result.push('_');
                }
                result.push(c.to_ascii_lowercase());
            } else {
                result.push(c);
            }
        }

        result
    }

    fn to_dashed(&self) -> String {
        let mut result = String::with_capacity(self.len());

        for c in self.chars() {
            result.push(match c {
                '_' => '-',
                c => c
            });
        }

        result
    }
}

fn to_camel_internal(term: &str, uppercase_first_letter: bool) -> String {
    let underscore_count = term.chars().filter(|c| *c == '_').count();
    let mut result = String::with_capacity(term.len() - underscore_count);
    let mut at_new_word = uppercase_first_letter;

    for c in term.chars().skip_while(|&c| c == '_') {
        if c == '_' {
            at_new_word = true;
        } else if at_new_word {
            result.push(c.to_ascii_uppercase());
            at_new_word = false;
        } else {
            result.push(c);
        }
    }

    result
}

#[inline]
fn is_ascii_uppercase(c: char) -> bool {
    c >= 'A' && c <= 'Z'
}
<|endoftext|>


<commit_before>pub mod sentinel_list
{
	use std::ptr;
	use std::fmt::Debug;

	pub struct Link<T>
	{
		pub next: *mut Link<T>,
		pub prev: *mut Link<T>,
		pub value: Option<T>,
	}

	impl<T> Link<T>
	{
		fn new(v: T) -> Link<T>
		{
			Link {
				prev: ptr::null_mut(),
				next: ptr::null_mut(),
				value: Some(v),
			}
		}
	}

	pub type Handle<T> = Box<Link<T>>;

	pub fn new_sentinel<T>() -> Handle<T>
	{
		let mut h = Box::new(
			Link {
				prev: ptr::null_mut(),
				next: ptr::null_mut(),
				value: None,
			}
		);
		h.prev = &mut *h;
		h.next = &mut *h;
		h
	}

	pub fn new_handle<T>(v: T) -> Handle<T>
	{
		Box::new(Link::new(v))
	}

	pub fn insert_after<T>(after: &mut Handle<T>, h: &mut Handle<T>)
	{
		let n: *mut _ = after.next;

		h.prev = &mut **after;
		h.next = n;

		after.next = &mut **h;

		let n = unsafe { &mut *h.next };
		n.prev = &mut **h;
	}

	fn debug_print<T: Debug>(s: &mut Handle<T>)
	{
		let mut h = s.next;
		while h != &mut **s {
			let n = unsafe { &*h };
			println!("{:?}", n.value);
			h = n.next;
		}
	}
}

#[cfg(test)]
mod tests {
	use sentinel_list;

	#[test]
	fn it_works() {
		let mut s = sentinel_list::new_sentinel();
	}
}
<commit_msg>adding doc test<commit_after>//! The `sentinel_list` crate provides a simple sentinel based list implementation.
//! Once you insert element to the list you are given back a handle into this list.
//! This handle allows you to remove element from the list in O(1) time.
//!
//! # Examples
//!
//! ```rust
//! extern crate sentinel_list;
//! use sentinel_list::{new_sentinel, new_handle, insert_after, debug_print};
//!
//! fn main() {
//!     let mut s = new_sentinel();
//!     let mut h1 = new_handle(1);
//!     let mut h2 = new_handle(2);
//!     let mut h3 = new_handle(3);
//!     let mut h4 = new_handle(4);
//!
//!     println!("\nObjects:");
//!     println!("{:p} {:?}", s, s.value);
//!     println!("{:p} {:?}", h1, h1.value);
//!     println!("{:p} {:?}", h2, h2.value);
//!     println!("{:p} {:?}", h3, h3.value);
//!     println!("{:p} {:?}", h4, h4.value);
//!
//!     insert_after(&mut s, &mut h1);
//!     insert_after(&mut h1, &mut h2);
//!     insert_after(&mut h2, &mut h3);
//!     insert_after(&mut h3, &mut h4);
//!
//!     println!("\nLinked:");
//!     println!("{:p} {:?}", s, s.value);
//!     println!("{:p} {:?}", h1, h1.value);
//!     println!("{:p} {:?}", h2, h2.value);
//!     println!("{:p} {:?}", h3, h3.value);
//!     println!("{:p} {:?}", h4, h4.value);
//!
//!
//!     println!("\nDebug-print:");
//!     debug_print(&mut s);
//! }
//! ```

pub use self::sentinel_list::{new_handle, new_sentinel, Handle, insert_after, debug_print};

mod sentinel_list
{
	use std::ptr;
	use std::fmt::Debug;

	pub struct Link<T>
	{
		pub next: *mut Link<T>,
		pub prev: *mut Link<T>,
		pub value: Option<T>,
	}

	impl<T> Link<T>
	{
		fn new(v: T) -> Link<T>
		{
			Link {
				prev: ptr::null_mut(),
				next: ptr::null_mut(),
				value: Some(v),
			}
		}
	}

	pub type Handle<T> = Box<Link<T>>;

	pub fn new_sentinel<T>() -> Handle<T>
	{
		let mut h = Box::new(
			Link {
				prev: ptr::null_mut(),
				next: ptr::null_mut(),
				value: None,
			}
		);
		h.prev = &mut *h;
		h.next = &mut *h;
		h
	}

	pub fn new_handle<T>(v: T) -> Handle<T>
	{
		Box::new(Link::new(v))
	}

	pub fn insert_after<T>(after: &mut Handle<T>, h: &mut Handle<T>)
	{
		let n: *mut _ = after.next;

		h.prev = &mut **after;
		h.next = n;

		after.next = &mut **h;

		let n = unsafe { &mut *h.next };
		n.prev = &mut **h;
	}

	pub fn debug_print<T: Debug>(s: &mut Handle<T>)
	{
		let mut h = s.next;
		while h != &mut **s {
			let n = unsafe { &*h };
			println!("{:?}", n.value);
			h = n.next;
		}
	}
}

#[cfg(test)]
mod tests {
	use sentinel_list::{new_sentinel, new_handle, debug_print, insert_after};

	#[test]
	fn it_works() {
        let mut s = new_sentinel();
        let mut h1 = new_handle(1);
        let mut h2 = new_handle(2);
        let mut h3 = new_handle(3);
        let mut h4 = new_handle(4);

        println!("\nObjects:");
        println!("{:p} {:?}", s, s.value);
        println!("{:p} {:?}", h1, h1.value);
        println!("{:p} {:?}", h2, h2.value);
        println!("{:p} {:?}", h3, h3.value);
        println!("{:p} {:?}", h4, h4.value);

        insert_after(&mut s, &mut h1);
        insert_after(&mut h1, &mut h2);
        insert_after(&mut h2, &mut h3);
        insert_after(&mut h3, &mut h4);

        println!("\nLinked:");
        println!("{:p} {:?}", s, s.value);
        println!("{:p} {:?}", h1, h1.value);
        println!("{:p} {:?}", h2, h2.value);
        println!("{:p} {:?}", h3, h3.value);
        println!("{:p} {:?}", h4, h4.value);

        println!("\nDebug-print:");
        debug_print(&mut s);
	}
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::io::SeekFrom;
use std::mem;
use std::ptr;
use std::collections::HashMap;

extern crate libc;
extern crate encoding;

use encoding::{Encoding, DecoderTrap};
use encoding::all::UTF_16LE;

pub mod minidump_format;
use minidump_format as fmt;

#[allow(dead_code)]
pub struct Minidump {
    file : File,
    header : fmt::MDRawHeader,
    streams : HashMap<u32, fmt::MDRawDirectory>,
    swap : bool,
}

#[derive(Debug)]
pub enum Error {
    MissingHeader,
    HeaderMismatch,
    SwapNotImplemented,
    VersionMismatch,
    MissingDirectory,
    StreamReadFailure,
    StreamSizeMismatch,
    StreamNotFound,
    ModuleReadFailure,
    DataError,
}

pub struct MinidumpThreadList;
pub struct MinidumpMemoryList;
pub struct MinidumpException;
pub struct MinidumpAssertion;
pub struct MinidumpSystemInfo;
pub struct MinidumpMiscInfo;
pub struct MinidumpBreakpadInfo;
pub struct MinidumpMemoryInfoList;

pub trait MinidumpStream {
    //TODO: associated_consts when that stabilizes.
    fn stream_type() -> u32;
    fn read(f : &File, expected_size : usize) -> Result<Self, Error>;
}

pub trait Module {
    fn base_address(&self) -> u64;
    fn size(&self) -> u64;
}

pub struct MinidumpModule {
    pub raw : fmt::MDRawModule,
    pub name : String,
}

pub struct MinidumpModuleList {
    pub modules : Vec<MinidumpModule>,
}

//======================================================
// Implementations

fn read<T : Copy>(mut f : &File) -> std::io::Result<T> {
    let size = mem::size_of::<T>();
    let mut buf = vec!(0; size);
    let bytes = &mut buf[..];
    try!(f.read(bytes));
    Ok(unsafe {
        let mut val : T = mem::uninitialized();
        ptr::copy(bytes.as_mut_ptr(), &mut val as *mut T as *mut u8, size);
        val
    })
}

fn read_string(mut f : &File, offset : u64) -> Result<String, Error> {
    try!(f.seek(SeekFrom::Start(offset)).or(Err(Error::DataError)));
    let size = try!(read::<u32>(f).or(Err(Error::DataError))) as usize;
    // TODO: swap
    if size % 2 != 0 {
        return Err(Error::DataError);
    }
    let mut buf = vec!(0; size);
    let bytes = &mut buf[..];
    try!(f.read(bytes).or(Err(Error::DataError)));
    UTF_16LE.decode(bytes, DecoderTrap::Strict).or(Err(Error::DataError))
}

impl MinidumpModule {
    pub fn read(f : &File, raw : fmt::MDRawModule) -> Result<MinidumpModule, Error> {
        let name = try!(read_string(f, raw.module_name_rva as u64));
        // TODO: read debug info
        Ok(MinidumpModule { raw: raw, name: name})
    }
}

impl Module for MinidumpModule {
    fn base_address(&self) -> u64 { self.raw.base_of_image }
    fn size(&self) -> u64 { self.raw.size_of_image as u64 }
}

impl MinidumpStream for MinidumpModuleList {
    fn stream_type() -> u32 { fmt::MD_MODULE_LIST_STREAM }
    fn read(f : &File, expected_size : usize) -> Result<MinidumpModuleList, Error> {
        if expected_size < mem::size_of::<u32>() {
            return Err(Error::StreamSizeMismatch);
        }
        // TODO: swap
        let count = try!(read::<u32>(&f).or(Err(Error::StreamReadFailure))) as usize;
        match expected_size - (mem::size_of::<u32>() + count * fmt::MD_MODULE_SIZE as usize) {
            0 => {},
            4 => {
                // 4 bytes of padding.
                try!(read::<u32>(&f).or(Err(Error::StreamReadFailure)));
            },
            _ => return Err(Error::StreamSizeMismatch)
        };
        // read count MDRawModule
        let mut raw_modules = Vec::with_capacity(count);
        for _ in 0..count {
            let raw = try!(read::<fmt::MDRawModule>(f).or(Err(Error::ModuleReadFailure)));
            // TODO: swap
            if raw.size_of_image == 0 || raw.size_of_image as u64 > (u64::max_value() - raw.base_of_image) {
                // Bad image size.
                //println!("image {}: bad image size: {}", i, raw.size_of_image);
                // TODO: just drop this module, keep the rest?
                return Err(Error::ModuleReadFailure);
            }
            raw_modules.push(raw);
        }
        // read auxiliary data for each module
        let mut modules = Vec::with_capacity(count);
        for raw in raw_modules.into_iter() {
            modules.push(try!(MinidumpModule::read(f, raw)));
        }
        // store modules by address (interval?)
        Ok(MinidumpModuleList { modules: modules })
    }
}

impl Minidump {
    pub fn read(f : File) -> Result<Minidump, Error> {
        let header = try!(read::<fmt::MDRawHeader>(&f).or(Err(Error::MissingHeader)));
        let swap = false;
        if header.signature != fmt::MD_HEADER_SIGNATURE {
            if header.signature.swap_bytes() != fmt::MD_HEADER_SIGNATURE {
                return Err(Error::HeaderMismatch);
            }
            return Err(Error::SwapNotImplemented);
            // TODO: implement swapping
            //swap = true;
        }
        if (header.version & 0x0000ffff) != fmt::MD_HEADER_VERSION {
            return Err(Error::VersionMismatch);
        }
        let mut streams = HashMap::with_capacity(header.stream_count as usize);
        if header.stream_count != 0 {
            for _ in 0..header.stream_count {
                let dir = try!(read::<fmt::MDRawDirectory>(&f).or(Err(Error::MissingDirectory)));
                if dir.stream_type != fmt::MD_UNUSED_STREAM {
                    streams.insert(dir.stream_type, dir);
                }
            }
        }
        Ok(Minidump {
            file: f,
            header: header,
            streams: streams,
            swap: swap
        })
    }

    pub fn get_stream<T: MinidumpStream>(&mut self) -> Result<T, Error> {
        match self.streams.get_mut(&T::stream_type()) {
            None => Err(Error::StreamNotFound),
            Some(dir) => {
                try!(self.file.seek(SeekFrom::Start(dir.location.rva as u64)).or(Err(Error::StreamReadFailure)));
                // TODO: cache result
                T::read(&self.file, dir.location.data_size as usize)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use std::fs::File;
    use super::*;

    #[test]
    fn test_read_minidump() {
        let mut path = PathBuf::from(file!());
        path.pop();
        path.push("testdata/test.dmp");
        let f = File::open(&path).ok().expect(&format!("failed to open file: {:?}", path));
        let mut dump = Minidump::read(f).unwrap();
        assert_eq!(dump.streams.len(), 7);

        let module_list = dump.get_stream::<MinidumpModuleList>().unwrap();
        let modules = module_list.modules;
        assert_eq!(modules.len(), 13);
        assert_eq!(modules[0].name, "c:\\test_app.exe");
        assert_eq!(modules[0].base_address(), 0x400000);
        assert_eq!(modules[0].size(), 0x2d000);
        assert_eq!(modules[12].name, "C:\\WINDOWS\\system32\\psapi.dll");
        assert_eq!(modules[12].base_address(), 0x76bf0000);
        assert_eq!(modules[12].size(), 0xb000);
    }
}
<commit_msg>Read CodeView record<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::io::SeekFrom;
use std::mem;
use std::ptr;
use std::collections::HashMap;

extern crate libc;
extern crate encoding;

use encoding::{Encoding, DecoderTrap};
use encoding::all::UTF_16LE;

pub mod minidump_format;
use minidump_format as fmt;

#[allow(dead_code)]
pub struct Minidump {
    file : File,
    header : fmt::MDRawHeader,
    streams : HashMap<u32, fmt::MDRawDirectory>,
    swap : bool,
}

#[derive(Debug)]
pub enum Error {
    MissingHeader,
    HeaderMismatch,
    SwapNotImplemented,
    VersionMismatch,
    MissingDirectory,
    StreamReadFailure,
    StreamSizeMismatch,
    StreamNotFound,
    ModuleReadFailure,
    DataError,
    CodeViewReadFailure,
}

pub struct MinidumpThreadList;
pub struct MinidumpMemoryList;
pub struct MinidumpException;
pub struct MinidumpAssertion;
pub struct MinidumpSystemInfo;
pub struct MinidumpMiscInfo;
pub struct MinidumpBreakpadInfo;
pub struct MinidumpMemoryInfoList;

pub trait MinidumpStream {
    //TODO: associated_consts when that stabilizes.
    fn stream_type() -> u32;
    fn read(f : &File, expected_size : usize) -> Result<Self, Error>;
}

pub trait Module {
    fn base_address(&self) -> u64;
    fn size(&self) -> u64;
    fn code_file<'a>(&'a self) -> &'a String;
    //fn code_identifier(&self) -> Option<String>;
    //fn debug_file<'a>(&'a self) -> Option<&'a String>;
    //fn debug_identifier(&self) -> Option<String>;
    //fn version(&self) -> Option<String>;
}

pub enum CodeViewPDBRaw {
    PDB20(fmt::MDCVInfoPDB20),
    PDB70(fmt::MDCVInfoPDB70),
}

pub struct CodeViewPDB {
    pub raw : CodeViewPDBRaw,
    pub file : String,
}

pub enum CodeView {
    PDB(CodeViewPDB),
    Unknown { bytes: Vec<u8> },
}

pub struct MinidumpModule {
    pub raw : fmt::MDRawModule,
    name : String,
    pub codeview_info : Option<CodeView>,
    pub misc_info : Option<fmt::MDImageDebugMisc>,
}

pub struct MinidumpModuleList {
    pub modules : Vec<MinidumpModule>,
}

//======================================================
// Implementations

fn read_bytes(f : &File, count : usize) -> std::io::Result<Vec<u8>> {
    let mut buf = Vec::with_capacity(count);
    try!(f.take(count as u64).read_to_end(&mut buf));
    Ok(buf)
}

fn read<T : Copy>(f : &File) -> std::io::Result<T> {
    let size = mem::size_of::<T>();
    let mut buf = try!(read_bytes(f, size));
    let bytes = &mut buf[..];
    Ok(unsafe {
        let mut val : T = mem::uninitialized();
        ptr::copy(bytes.as_mut_ptr(), &mut val as *mut T as *mut u8, size);
        val
    })
}

fn read_string_utf16(mut f : &File, offset : u64) -> Result<String, Error> {
    try!(f.seek(SeekFrom::Start(offset)).or(Err(Error::DataError)));
    let size = try!(read::<u32>(f).or(Err(Error::DataError))) as usize;
    // TODO: swap
    if size % 2 != 0 {
        return Err(Error::DataError);
    }
    let buf = try!(read_bytes(f, size).or(Err(Error::DataError)));
    let bytes = &buf[..];
    UTF_16LE.decode(bytes, DecoderTrap::Strict).or(Err(Error::DataError))
}

fn read_codeview_pdb(mut f : &File, signature : u32, mut size : usize) -> Result<CodeView, Error> {
    let raw = match signature {
        fmt::MD_CVINFOPDB70_SIGNATURE => {
            size = size - mem::size_of::<fmt::MDCVInfoPDB70>() + 1;
            CodeViewPDBRaw::PDB70(try!(read::<fmt::MDCVInfoPDB70>(f).or(Err(Error::CodeViewReadFailure))))
        },
        fmt::MD_CVINFOPDB20_SIGNATURE => {
            size = size -mem::size_of::<fmt::MDCVInfoPDB20>() + 1;
            CodeViewPDBRaw::PDB20(try!(read::<fmt::MDCVInfoPDB20>(f).or(Err(Error::CodeViewReadFailure))))
        },
        _ => return Err(Error::CodeViewReadFailure),
    };
    // Both structs define a variable-length string with a placeholder
    // 1-byte array at the end, so seek back one byte and read the remaining
    // data as the string.
    try!(f.seek(SeekFrom::Current(-1)).or(Err(Error::CodeViewReadFailure)));
    let bytes = try!(read_bytes(f, size).or(Err(Error::CodeViewReadFailure)));
    // The string should have at least one trailing NUL.
    let file = String::from(String::from_utf8(bytes).unwrap().trim_right_matches('\0'));
    Ok(CodeView::PDB(CodeViewPDB { raw: raw, file: file}))
}

fn read_codeview(mut f : &File, location : fmt::MDLocationDescriptor) -> Result<CodeView, Error> {
    let size = location.data_size as usize;
    try!(f.seek(SeekFrom::Start(location.rva as u64)).or(Err(Error::CodeViewReadFailure)));
    // The CodeView data can contain a variable-length string at the end
    // and also can be one of a few different formats. Try to read the
    // signature first to figure out what format the data is.
    // TODO: swap
    let signature = try!(read::<u32>(f).or(Err(Error::CodeViewReadFailure)));
    // Seek back because the signature is part of the CV data.
    try!(f.seek(SeekFrom::Start(location.rva as u64)).or(Err(Error::CodeViewReadFailure)));
    match signature {
        fmt::MD_CVINFOPDB70_SIGNATURE | fmt::MD_CVINFOPDB20_SIGNATURE => {
            read_codeview_pdb(f, signature, size)
        },
        _ =>
            // Other formats aren't handled, but save the raw bytes.
            Ok(CodeView::Unknown { bytes: try!(read_bytes(f, size).or(Err(Error::CodeViewReadFailure))) })
    }
}

impl MinidumpModule {
    pub fn read(f : &File, raw : fmt::MDRawModule) -> Result<MinidumpModule, Error> {
        let name = try!(read_string_utf16(f, raw.module_name_rva as u64));
        let cv = if raw.cv_record.data_size > 0 {
            Some(try!(read_codeview(f, raw.cv_record).or(Err(Error::CodeViewReadFailure))))
        } else {
            None
        };
        Ok(MinidumpModule {
            raw: raw,
            name: name,
            codeview_info: cv,
            misc_info: None,
        })
    }
}

impl Module for MinidumpModule {
    fn base_address(&self) -> u64 { self.raw.base_of_image }
    fn size(&self) -> u64 { self.raw.size_of_image as u64 }
    fn code_file<'a>(&'a self) -> &'a String { &self.name }
/*
    fn code_identifier(&self) -> Option<String> {
        unimplemented!()
    }
    fn debug_file<'a>(&'a self) -> Option<&'a String> {
        match self.codeview_info {
            Some(CodeView::PDB(_)) => Some(self.codeview_info.file),
            _ => None,
        }
    }
    fn debug_identifier(&self) -> Option<String> {
        unimplemented!()
    }
    fn version(&self) -> Option<String> {
        unimplemented!()
    }
*/
}

impl MinidumpStream for MinidumpModuleList {
    fn stream_type() -> u32 { fmt::MD_MODULE_LIST_STREAM }
    fn read(f : &File, expected_size : usize) -> Result<MinidumpModuleList, Error> {
        if expected_size < mem::size_of::<u32>() {
            return Err(Error::StreamSizeMismatch);
        }
        // TODO: swap
        let count = try!(read::<u32>(&f).or(Err(Error::StreamReadFailure))) as usize;
        match expected_size - (mem::size_of::<u32>() + count * fmt::MD_MODULE_SIZE as usize) {
            0 => {},
            4 => {
                // 4 bytes of padding.
                try!(read::<u32>(&f).or(Err(Error::StreamReadFailure)));
            },
            _ => return Err(Error::StreamSizeMismatch)
        };
        // read count MDRawModule
        let mut raw_modules = Vec::with_capacity(count);
        for _ in 0..count {
            let raw = try!(read::<fmt::MDRawModule>(f).or(Err(Error::ModuleReadFailure)));
            // TODO: swap
            if raw.size_of_image == 0 || raw.size_of_image as u64 > (u64::max_value() - raw.base_of_image) {
                // Bad image size.
                //println!("image {}: bad image size: {}", i, raw.size_of_image);
                // TODO: just drop this module, keep the rest?
                return Err(Error::ModuleReadFailure);
            }
            raw_modules.push(raw);
        }
        // read auxiliary data for each module
        let mut modules = Vec::with_capacity(count);
        for raw in raw_modules.into_iter() {
            modules.push(try!(MinidumpModule::read(f, raw)));
        }
        // store modules by address (interval?)
        Ok(MinidumpModuleList { modules: modules })
    }
}

impl Minidump {
    pub fn read(f : File) -> Result<Minidump, Error> {
        let header = try!(read::<fmt::MDRawHeader>(&f).or(Err(Error::MissingHeader)));
        let swap = false;
        if header.signature != fmt::MD_HEADER_SIGNATURE {
            if header.signature.swap_bytes() != fmt::MD_HEADER_SIGNATURE {
                return Err(Error::HeaderMismatch);
            }
            return Err(Error::SwapNotImplemented);
            // TODO: implement swapping
            //swap = true;
        }
        if (header.version & 0x0000ffff) != fmt::MD_HEADER_VERSION {
            return Err(Error::VersionMismatch);
        }
        let mut streams = HashMap::with_capacity(header.stream_count as usize);
        if header.stream_count != 0 {
            for _ in 0..header.stream_count {
                let dir = try!(read::<fmt::MDRawDirectory>(&f).or(Err(Error::MissingDirectory)));
                if dir.stream_type != fmt::MD_UNUSED_STREAM {
                    streams.insert(dir.stream_type, dir);
                }
            }
        }
        Ok(Minidump {
            file: f,
            header: header,
            streams: streams,
            swap: swap
        })
    }

    pub fn get_stream<T: MinidumpStream>(&mut self) -> Result<T, Error> {
        match self.streams.get_mut(&T::stream_type()) {
            None => Err(Error::StreamNotFound),
            Some(dir) => {
                try!(self.file.seek(SeekFrom::Start(dir.location.rva as u64)).or(Err(Error::StreamReadFailure)));
                // TODO: cache result
                T::read(&self.file, dir.location.data_size as usize)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use std::fs::File;
    use super::*;

    #[test]
    fn test_read_minidump() {
        let mut path = PathBuf::from(file!());
        path.pop();
        path.push("testdata/test.dmp");
        let f = File::open(&path).ok().expect(&format!("failed to open file: {:?}", path));
        let mut dump = Minidump::read(f).unwrap();
        assert_eq!(dump.streams.len(), 7);

        let module_list = dump.get_stream::<MinidumpModuleList>().unwrap();
        let modules = module_list.modules;
        assert_eq!(modules.len(), 13);
        assert_eq!(modules[0].code_file(), "c:\\test_app.exe");
        assert_eq!(modules[0].base_address(), 0x400000);
        assert_eq!(modules[0].size(), 0x2d000);
        assert_eq!(modules[12].code_file(), "C:\\WINDOWS\\system32\\psapi.dll");
        assert_eq!(modules[12].base_address(), 0x76bf0000);
        assert_eq!(modules[12].size(), 0xb000);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 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 docs

#![allow(bad_style, overflowing_literals, improper_ctypes)]
#![crate_type = "rlib"]
#![crate_name = "libc"]
#![cfg_attr(cross_platform_docs, feature(no_core, lang_items, const_fn))]
#![cfg_attr(cross_platform_docs, no_core)]
#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
    html_favicon_url = "https://doc.rust-lang.org/favicon.ico"
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "x86_64"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-linux-gnu"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "x86"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/i686-unknown-linux-gnu"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "arm"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/arm-unknown-linux-gnueabihf"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "mips"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/mips-unknown-linux-gnu"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "aarch64"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/aarch64-unknown-linux-gnu"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_env = "musl"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-linux-musl"
    )
)]
#![cfg_attr(
    all(target_os = "macos", target_arch = "x86_64"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-apple-darwin"
    )
)]
#![cfg_attr(
    all(target_os = "macos", target_arch = "x86"),
    doc(html_root_url = "https://rust-lang.github.io/libc/i686-apple-darwin")
)]
#![cfg_attr(
    all(windows, target_arch = "x86_64", target_env = "gnu"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-pc-windows-gnu"
    )
)]
#![cfg_attr(
    all(windows, target_arch = "x86", target_env = "gnu"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/i686-pc-windows-gnu"
    )
)]
#![cfg_attr(
    all(windows, target_arch = "x86_64", target_env = "msvc"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-pc-windows-msvc"
    )
)]
#![cfg_attr(
    all(windows, target_arch = "x86", target_env = "msvc"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/i686-pc-windows-msvc"
    )
)]
#![cfg_attr(
    target_os = "android",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/arm-linux-androideabi"
    )
)]
#![cfg_attr(
    target_os = "freebsd",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-freebsd"
    )
)]
#![cfg_attr(
    target_os = "openbsd",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-openbsd"
    )
)]
#![cfg_attr(
    target_os = "bitrig",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-bitrig"
    )
)]
#![cfg_attr(
    target_os = "netbsd",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-netbsd"
    )
)]
#![cfg_attr(
    target_os = "dragonfly",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-dragonfly"
    )
)]
#![cfg_attr(
    target_os = "solaris",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-sun-solaris"
    )
)]
#![cfg_attr(
    all(target_os = "emscripten", target_arch = "asmjs"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/asmjs-unknown-emscripten"
    )
)]
#![cfg_attr(
    all(target_os = "emscripten", target_arch = "wasm32"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/wasm32-unknown-emscripten"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "sparc64"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/sparc64-unknown-linux-gnu"
    )
)]
// Attributes needed when building as part of the standard library
#![cfg_attr(feature = "rustc-dep-of-std", feature(staged_api, cfg_target_vendor))]
#![cfg_attr(feature = "rustc-dep-of-std", feature(link_cfg, repr_packed))]
#![cfg_attr(feature = "rustc-dep-of-std", feature(no_core))]
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
#![cfg_attr(feature = "rustc-dep-of-std", allow(warnings))]
#![cfg_attr(
    feature = "rustc-dep-of-std",
    unstable(
        feature = "libc",
        reason = "use `libc` from crates.io",
        issue = "27783"
    )
)]
#![cfg_attr(not(any(feature = "use_std", feature = "rustc-dep-of-std")), no_std)]

#[cfg(all(not(cross_platform_docs), feature = "use_std"))]
extern crate std as core;

#[cfg(feature = "rustc-dep-of-std")]
extern crate rustc_std_workspace_core as core;
#[cfg(feature = "rustc-dep-of-std")]
#[allow(unused_imports)]
use core::iter;
#[cfg(feature = "rustc-dep-of-std")]
#[allow(unused_imports)]
use core::option;

#[macro_use]
mod macros;

mod dox;

cfg_if! {
    if #[cfg(windows)] {
        mod windows;
        pub use windows::*;
    } else if #[cfg(target_os = "redox")] {
        mod redox;
        pub use redox::*;
    } else if #[cfg(target_os = "cloudabi")] {
        mod cloudabi;
        pub use cloudabi::*;
    } else if #[cfg(target_os = "fuchsia")] {
        mod fuchsia;
        pub use fuchsia::*;
    } else if #[cfg(target_os = "switch")] {
        mod switch;
        pub use switch::*;
    } else if #[cfg(unix)] {
        mod unix;
        pub use unix::*;
    } else if #[cfg(target_env = "sgx")] {
        mod sgx;
        pub use sgx::*;
    }  else {
        // non-supported targets: empty...
    }
}
<commit_msg>Remove unstable `libc` feature on rustc-dep-of-std<commit_after>// Copyright 2012-2015 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 docs

#![allow(bad_style, overflowing_literals, improper_ctypes)]
#![crate_type = "rlib"]
#![crate_name = "libc"]
#![cfg_attr(cross_platform_docs, feature(no_core, lang_items, const_fn))]
#![cfg_attr(cross_platform_docs, no_core)]
#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
    html_favicon_url = "https://doc.rust-lang.org/favicon.ico"
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "x86_64"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-linux-gnu"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "x86"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/i686-unknown-linux-gnu"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "arm"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/arm-unknown-linux-gnueabihf"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "mips"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/mips-unknown-linux-gnu"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "aarch64"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/aarch64-unknown-linux-gnu"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_env = "musl"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-linux-musl"
    )
)]
#![cfg_attr(
    all(target_os = "macos", target_arch = "x86_64"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-apple-darwin"
    )
)]
#![cfg_attr(
    all(target_os = "macos", target_arch = "x86"),
    doc(html_root_url = "https://rust-lang.github.io/libc/i686-apple-darwin")
)]
#![cfg_attr(
    all(windows, target_arch = "x86_64", target_env = "gnu"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-pc-windows-gnu"
    )
)]
#![cfg_attr(
    all(windows, target_arch = "x86", target_env = "gnu"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/i686-pc-windows-gnu"
    )
)]
#![cfg_attr(
    all(windows, target_arch = "x86_64", target_env = "msvc"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-pc-windows-msvc"
    )
)]
#![cfg_attr(
    all(windows, target_arch = "x86", target_env = "msvc"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/i686-pc-windows-msvc"
    )
)]
#![cfg_attr(
    target_os = "android",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/arm-linux-androideabi"
    )
)]
#![cfg_attr(
    target_os = "freebsd",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-freebsd"
    )
)]
#![cfg_attr(
    target_os = "openbsd",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-openbsd"
    )
)]
#![cfg_attr(
    target_os = "bitrig",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-bitrig"
    )
)]
#![cfg_attr(
    target_os = "netbsd",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-netbsd"
    )
)]
#![cfg_attr(
    target_os = "dragonfly",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-unknown-dragonfly"
    )
)]
#![cfg_attr(
    target_os = "solaris",
    doc(
        html_root_url = "https://rust-lang.github.io/libc/x86_64-sun-solaris"
    )
)]
#![cfg_attr(
    all(target_os = "emscripten", target_arch = "asmjs"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/asmjs-unknown-emscripten"
    )
)]
#![cfg_attr(
    all(target_os = "emscripten", target_arch = "wasm32"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/wasm32-unknown-emscripten"
    )
)]
#![cfg_attr(
    all(target_os = "linux", target_arch = "sparc64"),
    doc(
        html_root_url = "https://rust-lang.github.io/libc/sparc64-unknown-linux-gnu"
    )
)]
// Attributes needed when building as part of the standard library
#![cfg_attr(feature = "rustc-dep-of-std", feature(cfg_target_vendor))]
#![cfg_attr(feature = "rustc-dep-of-std", feature(link_cfg, repr_packed))]
#![cfg_attr(feature = "rustc-dep-of-std", feature(no_core))]
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
#![cfg_attr(feature = "rustc-dep-of-std", allow(warnings))]
#![cfg_attr(not(any(feature = "use_std", feature = "rustc-dep-of-std")), no_std)]

#[cfg(all(not(cross_platform_docs), feature = "use_std"))]
extern crate std as core;

#[cfg(feature = "rustc-dep-of-std")]
extern crate rustc_std_workspace_core as core;
#[cfg(feature = "rustc-dep-of-std")]
#[allow(unused_imports)]
use core::iter;
#[cfg(feature = "rustc-dep-of-std")]
#[allow(unused_imports)]
use core::option;

#[macro_use]
mod macros;

mod dox;

cfg_if! {
    if #[cfg(windows)] {
        mod windows;
        pub use windows::*;
    } else if #[cfg(target_os = "redox")] {
        mod redox;
        pub use redox::*;
    } else if #[cfg(target_os = "cloudabi")] {
        mod cloudabi;
        pub use cloudabi::*;
    } else if #[cfg(target_os = "fuchsia")] {
        mod fuchsia;
        pub use fuchsia::*;
    } else if #[cfg(target_os = "switch")] {
        mod switch;
        pub use switch::*;
    } else if #[cfg(unix)] {
        mod unix;
        pub use unix::*;
    } else if #[cfg(target_env = "sgx")] {
        mod sgx;
        pub use sgx::*;
    }  else {
        // non-supported targets: empty...
    }
}
<|endoftext|>


<commit_before>//! Compile-time assertions to ensure that invariants are met.
//!
//! # Usage
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! static_assertions = "0.2.3"
//! ```
//!
//! and this to your crate root:
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! # fn main() {}
//! ```
//!
//! # Assert Equal Size
//!
//! When performing operations such as pointer casts or dealing with [`usize`]
//! versus [`u64`] versus [`u32`], the size of your types matter. This is where
//! [`assert_eq_size`] comes into play. Types provided as arguments to
//! [`assert_eq_size`] are ensured to be the same size at compile-time. If the
//! types differ in size, the code will fail to compile.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! // Can be declared outside of a function if labeled
//! assert_eq_size!(bytes; (u8, u8), u16);
//!
//! // Fails to compile (same label):
//! // assert_eq_size!(bytes; u8, u8);
//!
//! fn main() {
//!     assert_eq_size!([u8; 4], (u16, u16), u32);
//!
//!     // Produces a compilation failure:
//!     // assert_eq_size!(u32, u8);
//! }
//! ```
//!
//! Similar to [`assert_eq_size`], there is [`assert_eq_size_val`]. Instead of
//! specifying types to compare, values' sizes can be directly compared against
//! each other.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! let x = 42u8;
//! let y = true;
//!
//! assert_eq_size_val!(x, y);
//! # }
//! ```
//! [`assert_eq_size_val`] doesn't consume its arguments and thus works for
//! non-[`Clone`]able values.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! struct Buffer([u8; 256]);
//!
//! let buf = Buffer([0; 256]);
//! let val = [0u64; 32];
//!
//! assert_eq_size_val!(buf, val);
//!
//! // `buf` and `val` can be used here
//! # }
//! ```
//!
//! Rather than dereference a pointer to achieve the same effect as
//! [`assert_eq_size_val`], there is also the option of [`assert_eq_size_ptr`].
//!
//! # Assert Constant Expression
//!
//! Constant expressions can be ensured to have certain properties via
//! [`const_assert`]. If the expression evaluates to `false`, the file will fail
//! to compile. This is synonymous to [`static_assert` in C++][static_assert].
//!
//! As a [limitation](#limitations), a unique label is required if the macro is
//! used outside of a function.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! const NUM: usize = 32;
//!
//! const_assert!(NUM * NUM == 1024);
//! # }
//! ```
//!
//! As a shorthand for `const_assert!(a == b)`, there's [`const_assert_eq`]:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! const TWO: usize = 2;
//! const_assert_eq!(two; TWO * TWO, TWO + TWO, 4);
//!
//! // Fails to compile (same label):
//! // const_assert_eq!(two; TWO, TWO);
//!
//! fn main() {
//!     const NUM: usize = 32;
//!     const_assert_eq!(NUM + NUM, 64);
//! }
//! ```
//!
//! # Assert Object Safety
//!
//! Sometimes changes are made to traits that prevent them from being used in
//! the context of an object. Such a case would be adding a generic method and
//! forgetting to add `where Self: Sized` after it. If left unnoticed, that
//! mistake will end up affecting crate users and break compatibility.
//!
//! [`assert_obj_safe`] is here to save you from those troubles:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! assert_obj_safe!(basic; Send, Sync, AsRef<str>);
//!
//! trait MySafeTrait {}
//!
//! trait MyUnsafeTrait {
//!     fn generic<T>();
//! }
//!
//! fn main() {
//!     assert_obj_safe!(MySafeTrait);
//!
//!     // Produces a compilation failure:
//!     // assert_obj_safe!(MyUnsafeTrait);
//! }
//! ```
//!
//! # Assert Trait `impl`
//!
//! To ensure types implement [`Send`], [`Sync`], and other traits, there's
//! [`assert_impl`]:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! assert_impl!(str; String, Send, Sync, From<&'static str>);
//! assert_impl!(vec; &'static [u8], Into<Vec<u8>>);
//!
//! fn main() {
//!     // Produces a compilation failure:
//!     // `*const u8` cannot be sent between threads safely
//!     // assert_impl!(*const u8, Send);
//! }
//! ```
//!
//! # Limitations
//!
//! Due to implementation details, the following can only be used normally from
//! within the context of a function:
//!
//! - [`assert_eq_size`]
//! - [`assert_obj_safe`]
//! - [`assert_impl`]
//! - [`const_assert`]
//! - [`const_assert_eq`]
//!
//! To use these macros in other contexts, a unique label must be provided.
//!
//! If you want to read up about this and provide feedback, see
//! [the related issue on GitHub][issue1].
//!
//! [issue1]: https://github.com/nvzqz/static-assertions-rs/issues/1
//! [crate]: https://crates.io/crates/static_assertions
//! [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
//! [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
//! [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//! [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html
//! [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html
//! [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html
//! [`assert_eq_size_val`]: macro.assert_eq_size_val.html
//! [`assert_eq_size_ptr`]: macro.assert_eq_size_ptr.html
//! [`assert_eq_size`]: macro.assert_eq_size.html
//! [`assert_obj_safe`]: macro.assert_obj_safe.html
//! [`assert_impl`]: macro.assert_impl.html
//! [`const_assert`]: macro.const_assert.html
//! [`const_assert_eq`]: macro.const_assert_eq.html

#![no_std]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts at compile-time that the types have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// struct Byte(u8);
///
/// assert_eq_size!(pair; (u16, u16), [u16; 2], [u8; 4]);
///
/// // Fails to compile (same label):
/// // assert_eq_size!(pair; u8, u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
///
///     // Produces a compilation failure:
///     // assert_eq_size!(Byte, u16);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+ $(,)*) => {
        #[allow(unknown_lints, forget_copy, unused_unsafe, useless_transmute)]
        unsafe {
            use $crate::_core::mem::{forget, transmute, uninitialized};
            $(forget::<$xs>(transmute(uninitialized::<$x>()));)+
        }
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_eq_size!($($xs)+); }
    };
}

/// Asserts at compile-time that the values pointed to have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// fn operation(x: &(u32, u32), y: &[u16; 4]) {
///     assert_eq_size_ptr!(x, y);
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! assert_eq_size_ptr {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        #[allow(unknown_lints, forget_copy, unused_unsafe, useless_transmute)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read($x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+
            mem::forget(copy);
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
///
/// // Fails to compile:
/// // assert_eq_size_val!(x, 0u32);
/// # }
/// ```
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        assert_eq_size_ptr!(&$x, $(&$xs),+);
    }
}

/// Asserts at compile-time that the constant expression evaluates to `true`.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// const_assert!(2 + 2 == 4);
///
/// const FIVE: usize = 5;
/// const_assert!(FIVE - FIVE == 0);
///
/// // Produces a compilation failure:
/// // const_assert!(1 >= 2);
/// # }
/// ```
#[macro_export]
macro_rules! const_assert {
    ($($xs:expr),+ $(,)*) => {
        #[allow(unknown_lints, eq_op)]
        let _ = [(); 0 - (!($($xs)&&+) as usize)];
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { const_assert!($($xs)+); }
    };
}

/// Asserts at compile-time that the constants are equal in value.
#[macro_export]
macro_rules! const_assert_eq {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        const_assert!($($x == $xs),+);
    };
    ($label:ident; $x:expr, $($xs:expr),+ $(,)*) => {
        const_assert!($label; $($x == $xs),+);
    };
}

/// Asserts at compile-time that the traits are object-safe.
///
/// This is useful for when changes are made to a trait that accidentally
/// prevent it from being used as an object.
#[macro_export]
macro_rules! assert_obj_safe {
    ($($xs:ty),+ $(,)*) => {
        $(let _: Option<&$xs> = None;)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_obj_safe!($($xs)+); }
    };
}

/// Asserts at compile-time that the type has the given fields.
///
/// This is useful for when types have odd fields as a result of `#[cfg]`.
#[macro_export]
macro_rules! assert_fields {
    ($t:path, $($f:ident),+) => {
        $(let $t { $f: _, .. };)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_fields!($($xs)+); }
    };
}

/// Asserts at compile-time that the type implements the given traits.
#[macro_export]
macro_rules! assert_impl {
    ($x:ty, $($t:path),+ $(,)*) => {
        $({
            fn assert_impl<T: ?Sized + $t>() {}
            assert_impl::<$x>();
        })+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_impl!($($xs)+); }
    };
}
<commit_msg>Remove unnecessary parentheses from const_assert<commit_after>//! Compile-time assertions to ensure that invariants are met.
//!
//! # Usage
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! static_assertions = "0.2.3"
//! ```
//!
//! and this to your crate root:
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! # fn main() {}
//! ```
//!
//! # Assert Equal Size
//!
//! When performing operations such as pointer casts or dealing with [`usize`]
//! versus [`u64`] versus [`u32`], the size of your types matter. This is where
//! [`assert_eq_size`] comes into play. Types provided as arguments to
//! [`assert_eq_size`] are ensured to be the same size at compile-time. If the
//! types differ in size, the code will fail to compile.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! // Can be declared outside of a function if labeled
//! assert_eq_size!(bytes; (u8, u8), u16);
//!
//! // Fails to compile (same label):
//! // assert_eq_size!(bytes; u8, u8);
//!
//! fn main() {
//!     assert_eq_size!([u8; 4], (u16, u16), u32);
//!
//!     // Produces a compilation failure:
//!     // assert_eq_size!(u32, u8);
//! }
//! ```
//!
//! Similar to [`assert_eq_size`], there is [`assert_eq_size_val`]. Instead of
//! specifying types to compare, values' sizes can be directly compared against
//! each other.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! let x = 42u8;
//! let y = true;
//!
//! assert_eq_size_val!(x, y);
//! # }
//! ```
//! [`assert_eq_size_val`] doesn't consume its arguments and thus works for
//! non-[`Clone`]able values.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! struct Buffer([u8; 256]);
//!
//! let buf = Buffer([0; 256]);
//! let val = [0u64; 32];
//!
//! assert_eq_size_val!(buf, val);
//!
//! // `buf` and `val` can be used here
//! # }
//! ```
//!
//! Rather than dereference a pointer to achieve the same effect as
//! [`assert_eq_size_val`], there is also the option of [`assert_eq_size_ptr`].
//!
//! # Assert Constant Expression
//!
//! Constant expressions can be ensured to have certain properties via
//! [`const_assert`]. If the expression evaluates to `false`, the file will fail
//! to compile. This is synonymous to [`static_assert` in C++][static_assert].
//!
//! As a [limitation](#limitations), a unique label is required if the macro is
//! used outside of a function.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! const NUM: usize = 32;
//!
//! const_assert!(NUM * NUM == 1024);
//! # }
//! ```
//!
//! As a shorthand for `const_assert!(a == b)`, there's [`const_assert_eq`]:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! const TWO: usize = 2;
//! const_assert_eq!(two; TWO * TWO, TWO + TWO, 4);
//!
//! // Fails to compile (same label):
//! // const_assert_eq!(two; TWO, TWO);
//!
//! fn main() {
//!     const NUM: usize = 32;
//!     const_assert_eq!(NUM + NUM, 64);
//! }
//! ```
//!
//! # Assert Object Safety
//!
//! Sometimes changes are made to traits that prevent them from being used in
//! the context of an object. Such a case would be adding a generic method and
//! forgetting to add `where Self: Sized` after it. If left unnoticed, that
//! mistake will end up affecting crate users and break compatibility.
//!
//! [`assert_obj_safe`] is here to save you from those troubles:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! assert_obj_safe!(basic; Send, Sync, AsRef<str>);
//!
//! trait MySafeTrait {}
//!
//! trait MyUnsafeTrait {
//!     fn generic<T>();
//! }
//!
//! fn main() {
//!     assert_obj_safe!(MySafeTrait);
//!
//!     // Produces a compilation failure:
//!     // assert_obj_safe!(MyUnsafeTrait);
//! }
//! ```
//!
//! # Assert Trait `impl`
//!
//! To ensure types implement [`Send`], [`Sync`], and other traits, there's
//! [`assert_impl`]:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! assert_impl!(str; String, Send, Sync, From<&'static str>);
//! assert_impl!(vec; &'static [u8], Into<Vec<u8>>);
//!
//! fn main() {
//!     // Produces a compilation failure:
//!     // `*const u8` cannot be sent between threads safely
//!     // assert_impl!(*const u8, Send);
//! }
//! ```
//!
//! # Limitations
//!
//! Due to implementation details, the following can only be used normally from
//! within the context of a function:
//!
//! - [`assert_eq_size`]
//! - [`assert_obj_safe`]
//! - [`assert_impl`]
//! - [`const_assert`]
//! - [`const_assert_eq`]
//!
//! To use these macros in other contexts, a unique label must be provided.
//!
//! If you want to read up about this and provide feedback, see
//! [the related issue on GitHub][issue1].
//!
//! [issue1]: https://github.com/nvzqz/static-assertions-rs/issues/1
//! [crate]: https://crates.io/crates/static_assertions
//! [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
//! [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
//! [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//! [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html
//! [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html
//! [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html
//! [`assert_eq_size_val`]: macro.assert_eq_size_val.html
//! [`assert_eq_size_ptr`]: macro.assert_eq_size_ptr.html
//! [`assert_eq_size`]: macro.assert_eq_size.html
//! [`assert_obj_safe`]: macro.assert_obj_safe.html
//! [`assert_impl`]: macro.assert_impl.html
//! [`const_assert`]: macro.const_assert.html
//! [`const_assert_eq`]: macro.const_assert_eq.html

#![no_std]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts at compile-time that the types have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// struct Byte(u8);
///
/// assert_eq_size!(pair; (u16, u16), [u16; 2], [u8; 4]);
///
/// // Fails to compile (same label):
/// // assert_eq_size!(pair; u8, u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
///
///     // Produces a compilation failure:
///     // assert_eq_size!(Byte, u16);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+ $(,)*) => {
        #[allow(unknown_lints, forget_copy, unused_unsafe, useless_transmute)]
        unsafe {
            use $crate::_core::mem::{forget, transmute, uninitialized};
            $(forget::<$xs>(transmute(uninitialized::<$x>()));)+
        }
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_eq_size!($($xs)+); }
    };
}

/// Asserts at compile-time that the values pointed to have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// fn operation(x: &(u32, u32), y: &[u16; 4]) {
///     assert_eq_size_ptr!(x, y);
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! assert_eq_size_ptr {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        #[allow(unknown_lints, forget_copy, unused_unsafe, useless_transmute)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read($x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+
            mem::forget(copy);
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
///
/// // Fails to compile:
/// // assert_eq_size_val!(x, 0u32);
/// # }
/// ```
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        assert_eq_size_ptr!(&$x, $(&$xs),+);
    }
}

/// Asserts at compile-time that the constant expression evaluates to `true`.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// const_assert!(2 + 2 == 4);
///
/// const FIVE: usize = 5;
/// const_assert!(FIVE - FIVE == 0);
///
/// // Produces a compilation failure:
/// // const_assert!(1 >= 2);
/// # }
/// ```
#[macro_export]
macro_rules! const_assert {
    ($($xs:expr),+ $(,)*) => {
        #[allow(unknown_lints, eq_op)]
        let _ = [(); 0 - !($($xs)&&+) as usize];
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { const_assert!($($xs)+); }
    };
}

/// Asserts at compile-time that the constants are equal in value.
#[macro_export]
macro_rules! const_assert_eq {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        const_assert!($($x == $xs),+);
    };
    ($label:ident; $x:expr, $($xs:expr),+ $(,)*) => {
        const_assert!($label; $($x == $xs),+);
    };
}

/// Asserts at compile-time that the traits are object-safe.
///
/// This is useful for when changes are made to a trait that accidentally
/// prevent it from being used as an object.
#[macro_export]
macro_rules! assert_obj_safe {
    ($($xs:ty),+ $(,)*) => {
        $(let _: Option<&$xs> = None;)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_obj_safe!($($xs)+); }
    };
}

/// Asserts at compile-time that the type has the given fields.
///
/// This is useful for when types have odd fields as a result of `#[cfg]`.
#[macro_export]
macro_rules! assert_fields {
    ($t:path, $($f:ident),+) => {
        $(let $t { $f: _, .. };)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_fields!($($xs)+); }
    };
}

/// Asserts at compile-time that the type implements the given traits.
#[macro_export]
macro_rules! assert_impl {
    ($x:ty, $($t:path),+ $(,)*) => {
        $({
            fn assert_impl<T: ?Sized + $t>() {}
            assert_impl::<$x>();
        })+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_impl!($($xs)+); }
    };
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use std::io::Read;

#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub struct JournalEntry {
    #[serde(rename = "__CURSOR")]
    pub cursor: String,
    #[serde(rename = "__REALTIME_TIMESTAMP")]
    pub realtime_timestamp: String,
    #[serde(rename = "__MONOTONIC_TIMESTAMP")]
    pub monotonic_timestamp: String,
    #[serde(rename = "_BOOT_ID")]
    pub boot_id: String,
    #[serde(rename = "_MACHINE_ID")]
    pub machine_id: String,
    #[serde(rename = "_HOSTNAME")]
    pub hostname: String,
    pub priority: Option<String>,
    #[serde(rename = "_UID")]
    pub uid: Option<String>,
    #[serde(rename = "_GID")]
    pub gid: Option<String>,
    #[serde(rename = "_SYSTEMD_SLICE")]
    pub systemd_slice: Option<String>,
    #[serde(rename = "_CAP_EFFECTIVE")]
    pub cap_effective: Option<String>,
    #[serde(rename = "_TRANSPORT")]
    pub transport: String,
    #[serde(rename = "_COMM")]
    pub command: Option<String>,
    #[serde(rename = "_EXE")]
    pub executable: Option<String>,
    #[serde(rename = "_SYSTEMD_CGROUP")]
    pub systemd_cgroup: Option<String>,
    #[serde(rename = "_SYSTEMD_UNIT")]
    pub systemd_unit: Option<String>,
    #[serde(rename = "_SYSTEMD_INVOCATION_ID")]
    pub systemd_invocation_id: Option<String>,
    #[serde(rename = "_SYSTEMD_OWNER_UID")]
    pub systemd_owner_uid: Option<String>,
    #[serde(rename = "_SYSTEMD_USER_SLICE")]
    pub systemd_user_slice: Option<String>,
    #[serde(rename = "_SYSTEMD_USER_UNIT")]
    pub systemd_user_unit: Option<String>,
    #[serde(rename = "_SYSTEMD_SESSION")]
    pub systemd_session: Option<String>,
    pub syslog_facility: Option<String>,
    pub syslog_identifier: Option<String>,
    #[serde(rename = "_CMDLINE")]
    pub command_line: Option<String>,
    #[serde(rename = "_AUDIT_LOGINUID")]
    pub audit_login_uid: Option<String>,
    pub message: String,
    pub code_file: Option<String>,
    pub code_line: Option<String>,
    pub code_function: Option<String>,
    pub unit: Option<String>,
    pub user_unit: Option<String>,
    pub userspace_usec: Option<String>,
    pub kernel_usec: Option<String>,
    pub message_id: Option<String>,
    pub result: Option<String>,
    pub user_id: Option<String>,
    pub seat_id: Option<String>,
    pub leader: Option<String>,
    pub journal_name: Option<String>,
    pub journal_path: Option<String>,
    pub current_use: Option<String>,
    pub current_use_pretty: Option<String>,
    pub max_use: Option<String>,
    pub max_use_pretty: Option<String>,
    pub disk_keep_free: Option<String>,
    pub disk_keep_free_pretty: Option<String>,
    pub disk_available: Option<String>,
    pub disk_available_pretty: Option<String>,
    pub available: Option<String>,
    pub available_pretty: Option<String>,
    pub limit: Option<String>,
    pub limit_pretty: Option<String>,
    pub session_id: Option<String>,
    pub syslog_pid: Option<String>,
    #[serde(rename = "_PID")]
    pub pid: Option<String>,
    #[serde(rename = "_AUDIT_SESSION")]
    pub audit_session: Option<String>,
    #[serde(rename = "_AUDIT_TYPE")]
    pub audit_type: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_NAME")]
    pub audit_field_name: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_APPARMOR")]
    pub audit_field_apparmor: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_OPERATION")]
    pub audit_field_operation: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_PROFILE")]
    pub audit_field_profile: Option<String>,
    #[serde(rename = "_AUDIT_ID")]
    pub audit_id: Option<String>,
    #[serde(rename = "_KERNEL_SUBSYSTEM")]
    pub kernel_subsystem: Option<String>,
    #[serde(rename = "_KERNEL_DEVICE")]
    pub kernel_device: Option<String>,
    #[serde(rename = "_UDEV_SYSNAME")]
    pub udev_sysname: Option<String>,
    #[serde(rename = "_UDEV_DEVNODE")]
    pub udev_devnode: Option<String>,
    #[serde(rename = "_UDEV_DEVLINK")]
    pub udev_devlink: Option<String>,
    #[serde(rename = "_SOURCE_REALTIME_TIMESTAMP")]
    pub source_realtime_timestamp: Option<String>,
    #[serde(rename = "_SOURCE_MONOTONIC_TIMESTAMP")]
    pub source_monotonic_timestamp: Option<String>,
}

pub struct JournalGateway {
    pub baseurl: url::Url,
    client: hyper::Client,
}

impl JournalGateway {
    pub fn new(baseurl: &url::Url) -> JournalGateway {
        JournalGateway {
            baseurl: baseurl.to_owned(),
            client: hyper::Client::new(),
        }
    }

    pub fn get_all_entries(&self) -> Vec<JournalEntry> {
        self.get_entries(None)
    }

    pub fn get_entries(&self, filters: Option<Vec<(String, String)>>) -> Vec<JournalEntry> {
        let mut url = self.baseurl.join("entries").expect("url join failed");
        if let Some(filters_unwrapped) = filters {
            url.query_pairs_mut().extend_pairs(filters_unwrapped);
        }

        let request = self.client
            .request(hyper::method::Method::Get, url.as_str())
            .header(hyper::header::Accept::json());

        let mut response = request.send().expect("request failure");
        let mut body = String::new();
        response
            .read_to_string(&mut body)
            .expect("body read failed");

        let mut res: Vec<JournalEntry> = vec![];
        for line in body.split("\n") {
            if line.len() > 0 {
                let deser_res = serde_json::from_str(&line);
                match deser_res {
                    Ok(entry) => res.push(entry),
                    Err(e) => println!("Error {}, skipping line: {}", e, line),
                }
            }
        }

        res
    }
}

#[cfg(test)]
mod tests {
    use url;
    use JournalGateway;

    #[test]
    fn get_entries() {

        // TODO make this into a self contained test

        let baseurl = url::Url::parse("http://192.168.33.19:19531")
            .expect("Error during parsing baseurl");
        let journal_gw = JournalGateway::new(&baseurl);
        let res = journal_gw.get_all_entries();
        for entry in res {
            println!("{}", entry.message);
        }
    }

    // TODO create another test with a filter, e.g.
    // let res = journal_gw.get_entries(Some(vec![("_COMM".to_string(), "cat".to_string())]));
}
<commit_msg>change constructor param to str instead of url to avoid extra required dependencies<commit_after>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use std::io::Read;

#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub struct JournalEntry {
    #[serde(rename = "__CURSOR")]
    pub cursor: String,
    #[serde(rename = "__REALTIME_TIMESTAMP")]
    pub realtime_timestamp: String,
    #[serde(rename = "__MONOTONIC_TIMESTAMP")]
    pub monotonic_timestamp: String,
    #[serde(rename = "_BOOT_ID")]
    pub boot_id: String,
    #[serde(rename = "_MACHINE_ID")]
    pub machine_id: String,
    #[serde(rename = "_HOSTNAME")]
    pub hostname: String,
    pub priority: Option<String>,
    #[serde(rename = "_UID")]
    pub uid: Option<String>,
    #[serde(rename = "_GID")]
    pub gid: Option<String>,
    #[serde(rename = "_SYSTEMD_SLICE")]
    pub systemd_slice: Option<String>,
    #[serde(rename = "_CAP_EFFECTIVE")]
    pub cap_effective: Option<String>,
    #[serde(rename = "_TRANSPORT")]
    pub transport: String,
    #[serde(rename = "_COMM")]
    pub command: Option<String>,
    #[serde(rename = "_EXE")]
    pub executable: Option<String>,
    #[serde(rename = "_SYSTEMD_CGROUP")]
    pub systemd_cgroup: Option<String>,
    #[serde(rename = "_SYSTEMD_UNIT")]
    pub systemd_unit: Option<String>,
    #[serde(rename = "_SYSTEMD_INVOCATION_ID")]
    pub systemd_invocation_id: Option<String>,
    #[serde(rename = "_SYSTEMD_OWNER_UID")]
    pub systemd_owner_uid: Option<String>,
    #[serde(rename = "_SYSTEMD_USER_SLICE")]
    pub systemd_user_slice: Option<String>,
    #[serde(rename = "_SYSTEMD_USER_UNIT")]
    pub systemd_user_unit: Option<String>,
    #[serde(rename = "_SYSTEMD_SESSION")]
    pub systemd_session: Option<String>,
    pub syslog_facility: Option<String>,
    pub syslog_identifier: Option<String>,
    #[serde(rename = "_CMDLINE")]
    pub command_line: Option<String>,
    #[serde(rename = "_AUDIT_LOGINUID")]
    pub audit_login_uid: Option<String>,
    pub message: String,
    pub code_file: Option<String>,
    pub code_line: Option<String>,
    pub code_function: Option<String>,
    pub unit: Option<String>,
    pub user_unit: Option<String>,
    pub userspace_usec: Option<String>,
    pub kernel_usec: Option<String>,
    pub message_id: Option<String>,
    pub result: Option<String>,
    pub user_id: Option<String>,
    pub seat_id: Option<String>,
    pub leader: Option<String>,
    pub journal_name: Option<String>,
    pub journal_path: Option<String>,
    pub current_use: Option<String>,
    pub current_use_pretty: Option<String>,
    pub max_use: Option<String>,
    pub max_use_pretty: Option<String>,
    pub disk_keep_free: Option<String>,
    pub disk_keep_free_pretty: Option<String>,
    pub disk_available: Option<String>,
    pub disk_available_pretty: Option<String>,
    pub available: Option<String>,
    pub available_pretty: Option<String>,
    pub limit: Option<String>,
    pub limit_pretty: Option<String>,
    pub session_id: Option<String>,
    pub syslog_pid: Option<String>,
    #[serde(rename = "_PID")]
    pub pid: Option<String>,
    #[serde(rename = "_AUDIT_SESSION")]
    pub audit_session: Option<String>,
    #[serde(rename = "_AUDIT_TYPE")]
    pub audit_type: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_NAME")]
    pub audit_field_name: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_APPARMOR")]
    pub audit_field_apparmor: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_OPERATION")]
    pub audit_field_operation: Option<String>,
    #[serde(rename = "_AUDIT_FIELD_PROFILE")]
    pub audit_field_profile: Option<String>,
    #[serde(rename = "_AUDIT_ID")]
    pub audit_id: Option<String>,
    #[serde(rename = "_KERNEL_SUBSYSTEM")]
    pub kernel_subsystem: Option<String>,
    #[serde(rename = "_KERNEL_DEVICE")]
    pub kernel_device: Option<String>,
    #[serde(rename = "_UDEV_SYSNAME")]
    pub udev_sysname: Option<String>,
    #[serde(rename = "_UDEV_DEVNODE")]
    pub udev_devnode: Option<String>,
    #[serde(rename = "_UDEV_DEVLINK")]
    pub udev_devlink: Option<String>,
    #[serde(rename = "_SOURCE_REALTIME_TIMESTAMP")]
    pub source_realtime_timestamp: Option<String>,
    #[serde(rename = "_SOURCE_MONOTONIC_TIMESTAMP")]
    pub source_monotonic_timestamp: Option<String>,
}

pub struct JournalGateway {
    pub baseurl: url::Url,
    client: hyper::Client,
}

impl JournalGateway {
    pub fn new(baseurl_str: &str) -> JournalGateway {
        let baseurl = url::Url::parse(baseurl_str).expect("Error during parsing baseurl");
        JournalGateway {
            baseurl: baseurl.to_owned(),
            client: hyper::Client::new(),
        }
    }

    pub fn get_all_entries(&self) -> Vec<JournalEntry> {
        self.get_entries(None)
    }

    pub fn get_entries(&self, filters: Option<Vec<(String, String)>>) -> Vec<JournalEntry> {
        let mut url = self.baseurl.join("entries").expect("url join failed");
        if let Some(filters_unwrapped) = filters {
            url.query_pairs_mut().extend_pairs(filters_unwrapped);
        }

        let request = self.client
            .request(hyper::method::Method::Get, url.as_str())
            .header(hyper::header::Accept::json());

        let mut response = request.send().expect("request failure");
        let mut body = String::new();
        response
            .read_to_string(&mut body)
            .expect("body read failed");

        let mut res: Vec<JournalEntry> = vec![];
        for line in body.split("\n") {
            if line.len() > 0 {
                let deser_res = serde_json::from_str(&line);
                match deser_res {
                    Ok(entry) => res.push(entry),
                    Err(e) => println!("Error {}, skipping line: {}", e, line),
                }
            }
        }

        res
    }
}

#[cfg(test)]
mod tests {
    use JournalGateway;

    #[test]
    fn get_entries() {

        // TODO make this into a self contained test

        let journal_gw = JournalGateway::new("http://192.168.33.19:19531");
        let res = journal_gw.get_all_entries();
        for entry in res {
            println!("{}", entry.message);
        }
    }

    // TODO create another test with a filter, e.g.
    // let res = journal_gw.get_entries(Some(vec![("_COMM".to_string(), "cat".to_string())]));
}
<|endoftext|>