<commit_before>#![crate_id = "regexp#0.1.0"]
#![crate_type = "lib"]
#![license = "UNLICENSE"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/regexp")]

#![allow(unused_imports)]
#![allow(dead_code)]

//! Regular expressions for Rust.

#![feature(phase)]

extern crate collections;
#[phase(syntax, link)]
extern crate log;

use std::fmt;
use std::str;
use parse::is_punct;

pub use regexp::{Regexp, Captures, SubCaptures, FindCaptures, FindMatches};
pub use regexp::{RegexpSplits, RegexpSplitsN};

mod compile;
mod parse;
mod regexp;
mod vm;

/// Error corresponds to something that can go wrong while parsing or compiling
/// a regular expression.
///
/// (Once an expression is compiled, it is not possible to produce an error
/// via searching, splitting or replacing.)
pub struct Error {
    pub pos: uint,
    pub kind: ErrorKind,
    pub msg: ~str,
}

/// Describes the type of the error returned.
#[deriving(Show)]
pub enum ErrorKind {
    Bug,
    BadSyntax,
}

impl fmt::Show for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{} error near position {}: {}",
            self.kind, self.pos, self.msg)
    }
}

/// Escapes all regular expression meta characters in `s` so that it may be
/// safely used in a regular expression as a literal string.
pub fn quote(s: &str) -> ~str {
    let mut quoted = str::with_capacity(s.len());
    for c in s.chars() {
        if is_punct(c) {
            quoted.push_char('\\')
        }
        quoted.push_char(c);
    }
    quoted
}

#[cfg(test)]
mod test {
    use super::compile;
    use super::parse;
    use super::regexp::{Regexp, NoExpand};
    use super::vm;

    #[test]
    fn other() {
        let r = Regexp::new(r"(\S+)\s+(?P<last>\S+)").unwrap();
        let text = "andrew gallant";
        debug!("Replaced: {}", r.replace_all(text, "$last,$wat $1"));

        // let r = Regexp::new("a+").unwrap();
        // let text = "aaaawhoa";
        // for m in r.captures_iter(text) {
            // debug!("Match: {} (pos: {})", m.at(0), m.pos(0));
        // }
    }

    fn run_manual(regexp: &str, text: &str) {
        debug!("\n--------------------------------");
        debug!("RE: {}", regexp);
        debug!("Text: {}", text);

        let re = match parse::parse(regexp) {
            Err(err) => fail!("{}", err),
            Ok(re) => re,
        };
        debug!("AST: {}", re);

        let (insts, cap_names) = compile::compile(re);
        debug!("Insts: {}", insts);
        debug!("Capture names: {}", cap_names);

        let matched = vm::run(insts.as_slice(), text);
        debug!("Matched: {}", matched);

        debug!("--------------------------------");
    }

    fn run(re: &str, text: &str) {
        let r = match Regexp::new(re) {
            Err(err) => fail!("{}", err),
            Ok(r) => r,
        };
        for (s, e) in r.find_iter(text) {
            debug!("Matched: {} ({})", (s, e), text.slice(s, e));
        }
        for cap in r.captures_iter(text) {
            debug!("Captures: {}", cap.iter().collect::<Vec<&str>>());
        }
        // let gs = r.captures(text).unwrap();
        // let all: Vec<&str> = gs.iter().collect();
        // debug!("All: {}, First: {}, Second: {}", all, gs.at(0), gs.at(1));
        // debug!("Named: {}", gs.name("sec"));

    }

    #[test]
    #[ignore]
    fn simple() {
        // run("(?i:and)rew", "aNdrew");
        // run("a+b+?", "abbbbb");
        // run("(?s:.+)", "abb\nbbb");
        // run("(a*)+", "aaa");
        // run("(?sm)(.*?)^ab", "\n\n\nab");
        // run("(?sm)ab$\n", "ab\n");
        // run("(a{2}){3}", "aaaaaa");
        // run("a{2,}", "aaaaaa");
        // run("[a-z0-9]+", "ab0cdef");
        // run("<([^>])+>", "hello there");
        // run("(a|bcdef|g|ab|c|d|e|efg|fg)*", "abcdefg");
        // run("[^[:^alnum:]]+", "abc0123");

        // run(r"[\D]+", "abc123abc");
        // run(r".*([a-z]\b)", "andrew gallant");
        // run(r"\**", "**");
        // run(r"[\A]+", "-]a^a-a");
        // run(r"[^\P{N}\P{Cherokee}]+", "aᏑⅡᏡⅥ");
        // run(r"[^\P{N}\P{Cherokee}]+", "aᏑⅡᏡⅥ");
        // run("(?i)[^a-z]+", "ANDREW");

        // run(r"dre", "andrew dr. dre yo");

        // let roman = ~"ⅡⅢⅳⅥ";
        // run(r"\pN(?P<sec>\pN)", roman);
        // run(r"\pN+", roman);

        let text = "abaabaccadaaae";
        let re = Regexp::new("a*").unwrap();
        // for (s, e) in re.find_iter(text) {
            // debug!("Find: ({}, {})", s, e);
        // }
        for s in re.splitn(text, 2) {
            debug!("Split: {}", s);
        }
    }

    #[test]
    // #[ignore]
    fn captures() {
        // run("(a)b", "ab");
        // run("(?sm)(.*)^\nab", "\n\n\nab");
        // run(r"(?P<wat>\d+)a(?P\d+)", "123a456");
    }
}
<commit_msg>Convenient is_match at crate level.<commit_after>#![crate_id = "regexp#0.1.0"]
#![crate_type = "lib"]
#![license = "UNLICENSE"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/regexp")]

#![allow(unused_imports)]
#![allow(dead_code)]

//! Regular expressions for Rust.

#![feature(phase)]

extern crate collections;
#[phase(syntax, link)]
extern crate log;

use std::fmt;
use std::str;
use parse::is_punct;

pub use regexp::{Regexp, Captures, SubCaptures, FindCaptures, FindMatches};
pub use regexp::{RegexpSplits, RegexpSplitsN};

mod compile;
mod parse;
mod regexp;
mod vm;

/// Error corresponds to something that can go wrong while parsing or compiling
/// a regular expression.
///
/// (Once an expression is compiled, it is not possible to produce an error
/// via searching, splitting or replacing.)
pub struct Error {
    pub pos: uint,
    pub kind: ErrorKind,
    pub msg: ~str,
}

/// Describes the type of the error returned.
#[deriving(Show)]
pub enum ErrorKind {
    Bug,
    BadSyntax,
}

impl fmt::Show for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{} error near position {}: {}",
            self.kind, self.pos, self.msg)
    }
}

/// Escapes all regular expression meta characters in `s` so that it may be
/// safely used in a regular expression as a literal string.
pub fn quote(s: &str) -> ~str {
    let mut quoted = str::with_capacity(s.len());
    for c in s.chars() {
        if is_punct(c) {
            quoted.push_char('\\')
        }
        quoted.push_char(c);
    }
    quoted
}

/// Tests if the given regular expression matches somewhere in the text given.
///
/// If there was a problem compiling the regular expression, an error is
/// returned.
pub fn is_match(regex: &str, text: &str) -> Result<bool, Error> {
    Regexp::new(regex).map(|r| r.is_match(text))
}

#[cfg(test)]
mod test {
    use super::compile;
    use super::parse;
    use super::regexp::{Regexp, NoExpand};
    use super::vm;

    #[test]
    fn other() {
        let r = Regexp::new(r"(\S+)\s+(?P<last>\S+)\s*").unwrap();
        let text = "andrew gallant    kaitlyn brady";
        debug!("Replaced: {}", r.replace_all(text, "$last,$wat $1 "));

        // let r = Regexp::new("a+").unwrap();
        // let text = "aaaawhoa";
        // for m in r.captures_iter(text) {
            // debug!("Match: {} (pos: {})", m.at(0), m.pos(0));
        // }
    }

    fn run_manual(regexp: &str, text: &str) {
        debug!("\n--------------------------------");
        debug!("RE: {}", regexp);
        debug!("Text: {}", text);

        let re = match parse::parse(regexp) {
            Err(err) => fail!("{}", err),
            Ok(re) => re,
        };
        debug!("AST: {}", re);

        let (insts, cap_names) = compile::compile(re);
        debug!("Insts: {}", insts);
        debug!("Capture names: {}", cap_names);

        let matched = vm::run(insts.as_slice(), text);
        debug!("Matched: {}", matched);

        debug!("--------------------------------");
    }

    fn run(re: &str, text: &str) {
        let r = match Regexp::new(re) {
            Err(err) => fail!("{}", err),
            Ok(r) => r,
        };
        for (s, e) in r.find_iter(text) {
            debug!("Matched: {} ({})", (s, e), text.slice(s, e));
        }
        for cap in r.captures_iter(text) {
            debug!("Captures: {}", cap.iter().collect::<Vec<&str>>());
        }
        // let gs = r.captures(text).unwrap();
        // let all: Vec<&str> = gs.iter().collect();
        // debug!("All: {}, First: {}, Second: {}", all, gs.at(0), gs.at(1));
        // debug!("Named: {}", gs.name("sec"));

    }

    #[test]
    #[ignore]
    fn simple() {
        // run("(?i:and)rew", "aNdrew");
        // run("a+b+?", "abbbbb");
        // run("(?s:.+)", "abb\nbbb");
        // run("(a*)+", "aaa");
        // run("(?sm)(.*?)^ab", "\n\n\nab");
        // run("(?sm)ab$\n", "ab\n");
        // run("(a{2}){3}", "aaaaaa");
        // run("a{2,}", "aaaaaa");
        // run("[a-z0-9]+", "ab0cdef");
        // run("<([^>])+>", "hello there");
        // run("(a|bcdef|g|ab|c|d|e|efg|fg)*", "abcdefg");
        // run("[^[:^alnum:]]+", "abc0123");

        // run(r"[\D]+", "abc123abc");
        // run(r".*([a-z]\b)", "andrew gallant");
        // run(r"\**", "**");
        // run(r"[\A]+", "-]a^a-a");
        // run(r"[^\P{N}\P{Cherokee}]+", "aᏑⅡᏡⅥ");
        // run(r"[^\P{N}\P{Cherokee}]+", "aᏑⅡᏡⅥ");
        // run("(?i)[^a-z]+", "ANDREW");

        // run(r"dre", "andrew dr. dre yo");

        // let roman = ~"ⅡⅢⅳⅥ";
        // run(r"\pN(?P<sec>\pN)", roman);
        // run(r"\pN+", roman);

        let text = "abaabaccadaaae";
        let re = Regexp::new("a*").unwrap();
        // for (s, e) in re.find_iter(text) {
            // debug!("Find: ({}, {})", s, e);
        // }
        for s in re.splitn(text, 2) {
            debug!("Split: {}", s);
        }
    }

    #[test]
    // #[ignore]
    fn captures() {
        // run("(a)b", "ab");
        // run("(?sm)(.*)^\nab", "\n\n\nab");
        // run(r"(?P<wat>\d+)a(?P\d+)", "123a456");
    }
}
<|endoftext|>


<commit_before>//! Custom memory allocators and utilities for using them.
//!
//! # Examples
//! ```rust
//! #![feature(placement_in_syntax)]
//!
//! use std::io;
//! use allocators::{Allocator, Scoped, BlockOwner, FreeList, Proxy};
//!
//! #[derive(Debug)]
//! struct Bomb(u8);
//!
//! impl Drop for Bomb {
//!     fn drop(&mut self) {
//!         println!("Boom! {}", self.0);
//!     }
//! }
//! // new scoped allocator with 4 kilobytes of memory.
//! let alloc = Scoped::new(4 * 1024).unwrap();
//!
//! alloc.scope(|inner| {
//!     let mut bombs = Vec::new();
//!     // allocate makes the value on the stack first.
//!     for i in 0..100 { bombs.push(inner.allocate(Bomb(i)).unwrap())}
//!     // there's also in-place allocation!
//!     let bomb_101 = in inner.make_place().unwrap() { Bomb(101) };
//!     // watch the bombs go off!
//! });
//!
//!
//! // You can make allocators backed by other allocators.
//! {
//!     let secondary_alloc = FreeList::new_from(&alloc, 128, 8).unwrap();
//!     let mut val = secondary_alloc.allocate(0i32).unwrap();
//!     *val = 1;
//! }
//!
//! ```

#![feature(
    alloc,
    coerce_unsized,
    drop_in_place,
    heap_api,
    placement_new_protocol,
    placement_in_syntax,
    raw,
    unsize,
)]

use std::any::Any;
use std::borrow::{Borrow, BorrowMut};
use std::error::Error;
use std::fmt;
use std::marker::{PhantomData, Unsize};
use std::mem;
use std::ops::Place as StdPlace;
use std::ops::{CoerceUnsized, Deref, DerefMut, InPlace, Placer};

use alloc::heap;

extern crate alloc;

pub mod composable;
pub mod freelist;
pub mod scoped;

pub use composable::*;
pub use freelist::FreeList;
pub use scoped::Scoped;

/// A custom memory allocator.
pub unsafe trait Allocator {
    /// Attempts to allocate the value supplied to it.
    ///
    /// # Examples
    /// ```rust
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     allocator.allocate([0; 1000]).ok().unwrap()
    /// }
    /// ```
    #[inline]
    fn allocate<T>(&self, val: T) -> Result<Allocated<T, Self>, (AllocatorError, T)>
        where Self: Sized
    {
        match self.make_place() {
            Ok(place) => {
                Ok(in place { val })
            }
            Err(err) => {
                Err((err, val))
            }
        }
    }

    /// Attempts to create a place to allocate into.
    /// For the general purpose, calling `allocate` on the allocator is enough.
    /// However, when you know the value you are allocating is too large
    /// to be constructed on the stack, you should use in-place allocation.
    ///
    /// # Examples
    /// ```rust
    /// #![feature(placement_in_syntax)]
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     // if 1000 bytes were enough to smash the stack, this would still work.
    ///     in allocator.make_place().unwrap() { [0; 1000] }
    /// }
    /// ```
    fn make_place<T>(&self) -> Result<Place<T, Self>, AllocatorError>
        where Self: Sized
    {
        let (size, align) = (mem::size_of::<T>(), mem::align_of::<T>());
        match unsafe { self.allocate_raw(size, align) } {
            Ok(block) => {
                Ok(Place {
                    allocator: self,
                    block: block,
                    _marker: PhantomData,
                })
            }
            Err(e) => Err(e),
        }
    }

    /// Attempt to allocate a block of memory.
    ///
    /// Returns either a block of memory allocated
    /// or an Error. If `size` is equal to 0, the block returned must
    /// be created by `Block::empty()`
    ///
    /// # Safety
    /// Never use the block's pointer outside of the lifetime of the allocator.
    /// It must be deallocated with the same allocator as it was allocated with.
    /// It is undefined behavior to provide a non power-of-two align.
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError>;

    /// Reallocate a block of memory.
    ///
    /// This either returns a new, possibly moved block with the requested size,
    /// or the old block back.
    /// The new block will have the same alignment as the old.
    ///
    /// # Safety
    /// If given an empty block, it must return it back instead of allocating the new size,
    /// since the alignment is unknown.
    ///
    /// If the requested size is 0, it must deallocate the old block and return an empty one.
    unsafe fn reallocate_raw<'a>(&'a self, block: Block<'a>, new_size: usize) -> Result<Block<'a>, (AllocatorError, Block<'a>)>;

    /// Deallocate the memory referred to by this block.
    ///
    /// # Safety
    /// This block must have been allocated by this allocator.
    unsafe fn deallocate_raw(&self, block: Block);
}

/// An allocator that knows which blocks have been issued by it.
pub trait BlockOwner: Allocator {
    /// Whether this allocator owns this allocated value.
    fn owns<'a, T, A: Allocator>(&self, val: &Allocated<'a, T, A>) -> bool {
        self.owns_block(&Block::new(val.item as *mut u8, val.size, val.align))
    }

    /// Whether this allocator owns the block passed to it.
    fn owns_block(&self, block: &Block) -> bool;

    /// Joins this allocator with a fallback allocator.
    // TODO: Maybe not the right place for this?
    // Right now I've been more focused on shaking out the
    // specifics of allocation than crafting a fluent API.
    fn with_fallback<O: BlockOwner>(self, other: O) -> Fallback<Self, O>
        where Self: Sized
    {
        Fallback::new(self, other)
    }
}

/// A block of memory created by an allocator.
pub struct Block<'a> {
    ptr: *mut u8,
    size: usize,
    align: usize,
    _marker: PhantomData<&'a [u8]>,
}

impl<'a> Block<'a> {
    /// Create a new block from the supplied parts.
    /// The pointer cannot be null.
    pub fn new(ptr: *mut u8, size: usize, align: usize) -> Self {
        Block {
            ptr: ptr,
            size: size,
            align: align,
            _marker: PhantomData,
        }
    }

    /// Creates an empty block.
    pub fn empty() -> Self {
        Block {
            ptr: heap::EMPTY as *mut u8,
            size: 0,
            align: 0,
            _marker: PhantomData,
        }
    }

    /// Get the pointer from this block.
    pub fn ptr(&self) -> *mut u8 {
        self.ptr
    }
    /// Get the size of this block.
    pub fn size(&self) -> usize {
        self.size
    }
    /// Get the align of this block.
    pub fn align(&self) -> usize {
        self.align
    }
    /// Whether this block is empty.
    pub fn is_empty(&self) -> bool {
        self.size == 0
    }
}

/// Errors that can occur while creating an allocator
/// or allocating from it.
#[derive(Debug, Eq, PartialEq)]
pub enum AllocatorError {
    /// The allocator failed to allocate the amount of memory requested of it.
    OutOfMemory,
    /// The allocator does not support the requested alignment.
    UnsupportedAlignment,
    /// An allocator-specific error message.
    AllocatorSpecific(String),
}

impl fmt::Display for AllocatorError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.description())
    }
}

impl Error for AllocatorError {
    fn description(&self) -> &str {
        use AllocatorError::*;

        match *self {
            OutOfMemory => {
                "Allocator out of memory."
            }
            UnsupportedAlignment => {
                "Attempted to allocate with unsupported alignment."
            }
            AllocatorSpecific(ref reason) => {
                reason
            }
        }
    }
}

/// Allocator stub that just forwards to heap allocation.
/// It is recommended to use the `HEAP` constant instead
/// of creating a new instance of this, to benefit from
/// the static lifetime that it provides.
#[derive(Debug)]
pub struct HeapAllocator;

// A constant for allocators to use the heap as a root.
// Values allocated with this are effectively `Box`es.
pub const HEAP: &'static HeapAllocator = &HeapAllocator;

unsafe impl Allocator for HeapAllocator {
    #[inline]
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError> {
        if size != 0 {
            let ptr = heap::allocate(size, align);
            if !ptr.is_null() {
                Ok(Block::new(ptr, size, align))
            } else {
                Err(AllocatorError::OutOfMemory)
            }
        } else {
            Ok(Block::empty())
        }
    }

    #[inline]
    unsafe fn reallocate_raw<'a>(&'a self, block: Block<'a>, new_size: usize) -> Result<Block<'a>, (AllocatorError, Block<'a>)> {
        if new_size == 0 {
            self.deallocate_raw(block);
            Ok(Block::empty())
        } else if block.is_empty() {
            Err((AllocatorError::UnsupportedAlignment, block))
        } else {
            let new_ptr = heap::reallocate(block.ptr(), block.size(), new_size, block.align());

            if new_ptr.is_null() {
                Err((AllocatorError::OutOfMemory, block))
            } else {
                Ok(Block::new(new_ptr, new_size, block.align()))
            }
        }
    }

    #[inline]
    unsafe fn deallocate_raw(&self, block: Block) {
        if !block.is_empty() {
            heap::deallocate(block.ptr(), block.size(), block.align())
        }
    }
}

/// An item allocated by a custom allocator.
pub struct Allocated<'a, T: 'a + ?Sized, A: 'a + Allocator> {
    item: *mut T,
    size: usize,
    align: usize,
    allocator: &'a A,
}

impl<'a, T, A: Allocator> Allocated<'a, T, A> {
    /// Consumes this allocated value, yielding the value it manages.
    pub fn take(self) -> T {
        let val = unsafe { ::std::ptr::read(self.item) };
        let block = Block::new(self.item as *mut u8, self.size, self.align);
        unsafe { self.allocator.deallocate_raw(block) };
        mem::forget(self);
        val
    }
}

impl<'a, T: ?Sized, A: Allocator> Deref for Allocated<'a, T, A> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.item }
    }
}

impl<'a, T: ?Sized, A: Allocator> DerefMut for Allocated<'a, T, A> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.item }
    }
}

// Allocated can store trait objects!
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Allocated<'a, U, A>> for Allocated<'a, T, A> {}

impl<'a, A: Allocator> Allocated<'a, Any, A> {
    /// Attempts to downcast this `Allocated` to a concrete type.
    pub fn downcast<T: Any>(self) -> Result<Allocated<'a, T, A>, Allocated<'a, Any, A>> {
        use std::raw::TraitObject;
        if self.is::<T>() {
            let obj: TraitObject = unsafe { mem::transmute::<*mut Any, TraitObject>(self.item) };
            let new_allocated = Allocated {
                item: obj.data as *mut T,
                size: self.size,
                align: self.align,
                allocator: self.allocator,
            };
            mem::forget(self);
            Ok(new_allocated)
        } else {
            Err(self)
        }
    }
}

impl<'a, T: ?Sized, A: Allocator> Borrow<T> for Allocated<'a, T, A> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<'a, T: ?Sized, A: Allocator> BorrowMut<T> for Allocated<'a, T, A> {
    fn borrow_mut(&mut self) -> &mut T {
        &mut **self
    }
}

impl<'a, T: ?Sized, A: Allocator> Drop for Allocated<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        use std::intrinsics::drop_in_place;
        unsafe {
            drop_in_place(self.item);
            self.allocator.deallocate_raw(Block::new(self.item as *mut u8, self.size, self.align));
        }

    }
}

/// A place for allocating into.
/// This is only used for in-place allocation,
/// e.g. `let val = in (alloc.make_place().unwrap()) { EXPR }`
pub struct Place<'a, T: 'a, A: 'a + Allocator> {
    allocator: &'a A,
    block: Block<'a>,
    _marker: PhantomData<T>,
}

impl<'a, T: 'a, A: 'a + Allocator> Placer<T> for Place<'a, T, A> {
    type Place = Self;
    fn make_place(self) -> Self {
        self
    }
}

impl<'a, T: 'a, A: 'a + Allocator> InPlace<T> for Place<'a, T, A> {
    type Owner = Allocated<'a, T, A>;
    unsafe fn finalize(self) -> Self::Owner {
        let allocated = Allocated {
            item: self.block.ptr() as *mut T,
            size: self.block.size(),
            align: self.block.align(),
            allocator: self.allocator,
        };

        mem::forget(self);
        allocated
    }
}

impl<'a, T: 'a, A: 'a + Allocator> StdPlace<T> for Place<'a, T, A> {
    fn pointer(&mut self) -> *mut T {
        self.block.ptr() as *mut T
    }
}

impl<'a, T: 'a, A: 'a + Allocator> Drop for Place<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        // almost identical to Allocated::Drop, but we don't drop
        // the value in place. If the finalize
        // method was never called, the expression
        // to create the value failed and the memory at the
        // pointer is still uninitialized, which we don't want to drop.
        unsafe {
            self.allocator.deallocate_raw(mem::replace(&mut self.block, Block::empty()));
        }

    }
}

// aligns a pointer forward to the next value aligned with `align`.
#[inline]
fn align_forward(ptr: *mut u8, align: usize) -> *mut u8 {
    ((ptr as usize + align - 1) & !(align - 1)) as *mut u8
}

#[cfg(test)]
mod tests {

    use std::any::Any;

    use super::*;

    #[test]
    fn heap_lifetime() {
        let my_int;
        {
            my_int = HEAP.allocate(0i32).unwrap();
        }

        assert_eq!(*my_int, 0);
    }
    #[test]
    fn heap_in_place() {
        let big = in HEAP.make_place().unwrap() { [0u8; 8_000_000] };
        assert_eq!(big.len(), 8_000_000);
    }

    #[test]
    fn unsizing() {
        #[derive(Debug)]
        struct Bomb;
        impl Drop for Bomb {
            fn drop(&mut self) {
                println!("Boom")
            }
        }

        let my_foo: Allocated<Any, _> = HEAP.allocate(Bomb).unwrap();
        let _: Allocated<Bomb, _> = my_foo.downcast().ok().unwrap();
    }

    #[test]
    fn take_out() {
        let _: [u8; 1024] = HEAP.allocate([0; 1024]).ok().unwrap().take();
    }
}
<commit_msg>Lots of allocator-related changes. Fixes #12<commit_after>//! Custom memory allocators and utilities for using them.
//!
//! # Examples
//! ```rust
//! #![feature(placement_in_syntax)]
//!
//! use std::io;
//! use allocators::{Allocator, Scoped, BlockOwner, FreeList, Proxy};
//!
//! #[derive(Debug)]
//! struct Bomb(u8);
//!
//! impl Drop for Bomb {
//!     fn drop(&mut self) {
//!         println!("Boom! {}", self.0);
//!     }
//! }
//! // new scoped allocator with 4 kilobytes of memory.
//! let alloc = Scoped::new(4 * 1024).unwrap();
//!
//! alloc.scope(|inner| {
//!     let mut bombs = Vec::new();
//!     // allocate makes the value on the stack first.
//!     for i in 0..100 { bombs.push(inner.allocate(Bomb(i)).unwrap())}
//!     // there's also in-place allocation!
//!     let bomb_101 = in inner.make_place().unwrap() { Bomb(101) };
//!     // watch the bombs go off!
//! });
//!
//!
//! // You can make allocators backed by other allocators.
//! {
//!     let secondary_alloc = FreeList::new_from(&alloc, 128, 8).unwrap();
//!     let mut val = secondary_alloc.allocate(0i32).unwrap();
//!     *val = 1;
//! }
//!
//! ```

#![feature(
    alloc,
    coerce_unsized,
    drop_in_place,
    heap_api,
    placement_new_protocol,
    placement_in_syntax,
    raw,
    unique,
    unsize,
)]

use std::error::Error;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ptr::Unique;

use alloc::heap;

extern crate alloc;

mod boxed;
pub mod composable;
pub mod freelist;
pub mod scoped;

pub use boxed::{AllocBox, Place};
pub use composable::*;
pub use freelist::FreeList;
pub use scoped::Scoped;

/// A custom memory allocator.
pub unsafe trait Allocator {
    /// Attempts to allocate the value supplied to it.
    ///
    /// # Examples
    /// ```rust
    /// use allocators::{Allocator, AllocBox};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> AllocBox<[u8; 1000], A> {
    ///     allocator.allocate([0; 1000]).ok().unwrap()
    /// }
    /// ```
    #[inline]
    fn allocate<T>(&self, val: T) -> Result<AllocBox<T, Self>, (AllocatorError, T)>
        where Self: Sized
    {
        match self.make_place() {
            Ok(place) => {
                Ok(in place { val })
            }
            Err(err) => {
                Err((err, val))
            }
        }
    }

    /// Attempts to create a place to allocate into.
    /// For the general purpose, calling `allocate` on the allocator is enough.
    /// However, when you know the value you are allocating is too large
    /// to be constructed on the stack, you should use in-place allocation.
    ///
    /// # Examples
    /// ```rust
    /// #![feature(placement_in_syntax)]
    /// use allocators::{Allocator, AllocBox};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> AllocBox<[u8; 1000], A> {
    ///     // if 1000 bytes were enough to smash the stack, this would still work.
    ///     in allocator.make_place().unwrap() { [0; 1000] }
    /// }
    /// ```
    fn make_place<T>(&self) -> Result<Place<T, Self>, AllocatorError>
        where Self: Sized
    {
        boxed::make_place(self)
    }

    /// Attempt to allocate a block of memory.
    ///
    /// Returns either a block of memory allocated
    /// or an Error. If `size` is equal to 0, the block returned must
    /// be created by `Block::empty()`
    ///
    /// # Safety
    /// Never use the block's pointer outside of the lifetime of the allocator.
    /// It must be deallocated with the same allocator as it was allocated with.
    /// It is undefined behavior to provide a non power-of-two align.
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError>;

    /// Reallocate a block of memory.
    ///
    /// This either returns a new, possibly moved block with the requested size,
    /// or the old block back.
    /// The new block will have the same alignment as the old.
    ///
    /// # Safety
    /// If given an empty block, it must return it back instead of allocating the new size,
    /// since the alignment is unknown.
    ///
    /// If the requested size is 0, it must deallocate the old block and return an empty one.
    unsafe fn reallocate_raw<'a>(&'a self, block: Block<'a>, new_size: usize) -> Result<Block<'a>, (AllocatorError, Block<'a>)>;

    /// Deallocate the memory referred to by this block.
    ///
    /// # Safety
    /// This block must have been allocated by this allocator.
    unsafe fn deallocate_raw(&self, block: Block);
}

/// An allocator that knows which blocks have been issued by it.
pub trait BlockOwner: Allocator {
    /// Whether this allocator owns this allocated value.
    fn owns<'a, T, A: Allocator>(&self, val: &AllocBox<'a, T, A>) -> bool {
        self.owns_block(& unsafe { val.as_block() })
    }

    /// Whether this allocator owns the block passed to it.
    fn owns_block(&self, block: &Block) -> bool;

    /// Joins this allocator with a fallback allocator.
    // TODO: Maybe not the right place for this?
    // Right now I've been more focused on shaking out the
    // specifics of allocation than crafting a fluent API.
    fn with_fallback<O: BlockOwner>(self, other: O) -> Fallback<Self, O>
        where Self: Sized
    {
        Fallback::new(self, other)
    }
}

/// A block of memory created by an allocator.
pub struct Block<'a> {
    ptr: Unique<u8>,
    size: usize,
    align: usize,
    _marker: PhantomData<&'a [u8]>,
}

impl<'a> Block<'a> {
    /// Create a new block from the supplied parts.
    /// The pointer cannot be null.
    ///
    /// # Panics
    /// Panics if the pointer passed is null.
    pub fn new(ptr: *mut u8, size: usize, align: usize) -> Self {
        assert!(!ptr.is_null());
        Block {
            ptr: unsafe { Unique::new(ptr) },
            size: size,
            align: align,
            _marker: PhantomData,
        }
    }

    /// Creates an empty block.
    pub fn empty() -> Self {
        Block {
            ptr: unsafe { Unique::new(heap::EMPTY as *mut u8) },
            size: 0,
            align: 0,
            _marker: PhantomData,
        }
    }

    /// Get the pointer from this block.
    pub fn ptr(&self) -> *mut u8 {
        *self.ptr
    }
    /// Get the size of this block.
    pub fn size(&self) -> usize {
        self.size
    }
    /// Get the align of this block.
    pub fn align(&self) -> usize {
        self.align
    }
    /// Whether this block is empty.
    pub fn is_empty(&self) -> bool {
        self.size == 0
    }
}

/// Errors that can occur while creating an allocator
/// or allocating from it.
#[derive(Debug, Eq, PartialEq)]
pub enum AllocatorError {
    /// The allocator failed to allocate the amount of memory requested of it.
    OutOfMemory,
    /// The allocator does not support the requested alignment.
    UnsupportedAlignment,
    /// An allocator-specific error message.
    AllocatorSpecific(String),
}

impl fmt::Display for AllocatorError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.description())
    }
}

impl Error for AllocatorError {
    fn description(&self) -> &str {
        use AllocatorError::*;

        match *self {
            OutOfMemory => {
                "Allocator out of memory."
            }
            UnsupportedAlignment => {
                "Attempted to allocate with unsupported alignment."
            }
            AllocatorSpecific(ref reason) => {
                reason
            }
        }
    }
}

/// Allocator stub that just forwards to heap allocation.
/// It is recommended to use the `HEAP` constant instead
/// of creating a new instance of this, to benefit from
/// the static lifetime that it provides.
#[derive(Debug)]
pub struct HeapAllocator;

// A constant for allocators to use the heap as a root.
// Values allocated with this are effectively `Box`es.
pub const HEAP: &'static HeapAllocator = &HeapAllocator;

unsafe impl Allocator for HeapAllocator {
    #[inline]
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError> {
        if size != 0 {
            let ptr = heap::allocate(size, align);
            if !ptr.is_null() {
                Ok(Block::new(ptr, size, align))
            } else {
                Err(AllocatorError::OutOfMemory)
            }
        } else {
            Ok(Block::empty())
        }
    }

    #[inline]
    unsafe fn reallocate_raw<'a>(&'a self, block: Block<'a>, new_size: usize) -> Result<Block<'a>, (AllocatorError, Block<'a>)> {
        if new_size == 0 {
            self.deallocate_raw(block);
            Ok(Block::empty())
        } else if block.is_empty() {
            Err((AllocatorError::UnsupportedAlignment, block))
        } else {
            let new_ptr = heap::reallocate(block.ptr(), block.size(), new_size, block.align());

            if new_ptr.is_null() {
                Err((AllocatorError::OutOfMemory, block))
            } else {
                Ok(Block::new(new_ptr, new_size, block.align()))
            }
        }
    }

    #[inline]
    unsafe fn deallocate_raw(&self, block: Block) {
        if !block.is_empty() {
            heap::deallocate(block.ptr(), block.size(), block.align())
        }
    }
}

// aligns a pointer forward to the next value aligned with `align`.
#[inline]
fn align_forward(ptr: *mut u8, align: usize) -> *mut u8 {
    ((ptr as usize + align - 1) & !(align - 1)) as *mut u8
}

#[cfg(test)]
mod tests {

    use std::any::Any;

    use super::*;

    #[test]
    fn heap_lifetime() {
        let my_int;
        {
            my_int = HEAP.allocate(0i32).unwrap();
        }

        assert_eq!(*my_int, 0);
    }
    #[test]
    fn heap_in_place() {
        let big = in HEAP.make_place().unwrap() { [0u8; 8_000_000] };
        assert_eq!(big.len(), 8_000_000);
    }

    #[test]
    fn unsizing() {
        #[derive(Debug)]
        struct Bomb;
        impl Drop for Bomb {
            fn drop(&mut self) {
                println!("Boom")
            }
        }

        let my_foo: AllocBox<Any, _> = HEAP.allocate(Bomb).unwrap();
        let _: AllocBox<Bomb, _> = my_foo.downcast().ok().unwrap();
    }

    #[test]
    fn take_out() {
        let _: [u8; 1024] = HEAP.allocate([0; 1024]).ok().unwrap().take();
    }
}
<|endoftext|>


<commit_before>//! # `object`
//!
//! The `object` crate provides a unified interface to working with object files
//! across platforms.
//!
//! See the [`File` struct](./struct.File.html) for details.

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

extern crate goblin;

use std::fmt;
use std::io::Cursor;

mod elf;
pub use elf::*;

mod macho;
pub use macho::*;

/// An object file.
#[derive(Debug)]
pub struct File<'a> {
    inner: FileInternal<'a>,
}

#[derive(Debug)]
enum FileInternal<'a> {
    Elf(ElfFile<'a>),
    MachO(MachOFile<'a>),
}

/// An iterator of the sections of a `File`.
#[derive(Debug)]
pub struct SectionIterator<'a, 'b> {
    inner: SectionIteratorInternal<'a, 'b>,
}

// we wrap our enums in a struct so that they are kept private.
#[derive(Debug)]
enum SectionIteratorInternal<'a, 'b> {
    Elf(ElfSectionIterator<'a>),
    MachO(MachOSectionIterator<'a, 'b>),
}

/// A Section of a File
pub struct Section<'a> {
    inner: SectionInternal<'a>,
}

enum SectionInternal<'a> {
    Elf(ElfSection<'a>),
    MachO(MachOSection<'a>),
}

/// The kind of a sections.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionKind {
    /// The section kind is unknown.
    Unknown,
    /// An executable code section.
    Text,
    /// A data section.
    Data,
    /// A read only data section.
    ReadOnlyData,
    /// An uninitialized data section.
    UninitializedData,
    /// Some other type of text or data section.
    Other,
}

/// A symbol table entry.
#[derive(Debug)]
pub struct Symbol<'a> {
    kind: SymbolKind,
    section: usize,
    section_kind: Option<SectionKind>,
    global: bool,
    name: &'a [u8],
    address: u64,
    size: u64,
}

/// The kind of a symbol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
    /// The symbol kind is unknown.
    Unknown,
    /// The symbol is for executable code.
    Text,
    /// The symbol is for a data object.
    Data,
    /// The symbol is for a section.
    Section,
    /// The symbol is the name of a file. It precedes symbols within that file.
    File,
    /// The symbol is for an uninitialized common block.
    Common,
    /// The symbol is for a thread local storage entity.
    Tls,
}

impl<'a> File<'a> {
    /// Parse the raw object file data.
    pub fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
        let mut cursor = Cursor::new(data);
        let inner = match goblin::peek(&mut cursor).map_err(|_| "Could not parse file magic")? {
            goblin::Hint::Elf(_) => FileInternal::Elf(ElfFile::parse(data)?),
            goblin::Hint::Mach(_) => FileInternal::MachO(MachOFile::parse(data)?),
            _ => return Err("Unknown file magic"),
        };
        Ok(File { inner })
    }

    /// Get the contents of the section named `section_name`, if such
    /// a section exists.
    pub fn get_section(&self, section_name: &str) -> Option<&'a [u8]> {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.get_section(section_name),
            FileInternal::MachO(ref macho) => macho.get_section(section_name),
        }
    }

    /// Get an Iterator over the sections in the file.
    pub fn get_sections(&self) -> SectionIterator {
        match self.inner {
            FileInternal::Elf(ref elf) => SectionIterator {
                inner: SectionIteratorInternal::Elf(elf.get_sections()),
            },
            FileInternal::MachO(ref macho) => SectionIterator {
                inner: SectionIteratorInternal::MachO(macho.get_sections()),
            },
        }
    }

    /// Get a `Vec` of the symbols defined in the file.
    pub fn get_symbols(&self) -> Vec<Symbol<'a>> {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.get_symbols(),
            FileInternal::MachO(ref macho) => macho.get_symbols(),
        }
    }

    /// Return true if the file is little endian, false if it is big endian.
    pub fn is_little_endian(&self) -> bool {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.is_little_endian(),
            FileInternal::MachO(ref macho) => macho.is_little_endian(),
        }
    }
}

impl<'a, 'b> Iterator for SectionIterator<'a, 'b> {
    type Item = Section<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match &mut self.inner {
            &mut SectionIteratorInternal::Elf(ref mut elf) => elf.next().map(|x| {
                Section {
                    inner: SectionInternal::Elf(x),
                }
            }),
            &mut SectionIteratorInternal::MachO(ref mut macho) => macho.next().map(|x| {
                Section {
                    inner: SectionInternal::MachO(x),
                }
            }),
        }
    }
}

impl<'a> fmt::Debug for Section<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // It's painful to do much better than this
        f.debug_struct("Section")
            .field("name", &self.name().unwrap_or("<invalid name>"))
            .field("address", &self.address())
            .field("size", &self.data().len())
            .finish()
    }
}

impl<'a> Section<'a> {
    /// returns the address of the section
    pub fn address(&self) -> u64 {
        match &self.inner {
            &SectionInternal::Elf(ref elf) => elf.address(),
            &SectionInternal::MachO(ref macho) => macho.address(),
        }
    }

    /// returns a reference to contents of the section
    pub fn data(&self) -> &'a [u8] {
        match &self.inner {
            &SectionInternal::Elf(ref elf) => elf.data(),
            &SectionInternal::MachO(ref macho) => macho.data(),
        }
    }

    /// returns the name of the section
    pub fn name(&self) -> Option<&str> {
        match &self.inner {
            &SectionInternal::Elf(ref elf) => elf.name(),
            &SectionInternal::MachO(ref macho) => macho.name(),
        }
    }
}

impl<'a> Symbol<'a> {
    /// Return the kind of this symbol.
    #[inline]
    pub fn kind(&self) -> SymbolKind {
        self.kind
    }

    /// Returns the section kind for the symbol, or `None` if the symbol is undefnined.
    #[inline]
    pub fn section_kind(&self) -> Option<SectionKind> {
        self.section_kind
    }

    /// Return true if the symbol is undefined.
    #[inline]
    pub fn is_undefined(&self) -> bool {
        self.section_kind.is_none()
    }

    /// Return true if the symbol is global.
    #[inline]
    pub fn is_global(&self) -> bool {
        self.global
    }

    /// Return true if the symbol is local.
    #[inline]
    pub fn is_local(&self) -> bool {
        !self.global
    }

    /// The name of the symbol.
    #[inline]
    pub fn name(&self) -> &'a [u8] {
        self.name
    }

    /// The address of the symbol. May be zero if the address is unknown.
    #[inline]
    pub fn address(&self) -> u64 {
        self.address
    }

    /// The size of the symbol. May be zero if the size is unknown.
    #[inline]
    pub fn size(&self) -> u64 {
        self.size
    }
}

#[doc(hidden)]
#[deprecated]
pub trait Object {}
<commit_msg>Fix doc typo<commit_after>//! # `object`
//!
//! The `object` crate provides a unified interface to working with object files
//! across platforms.
//!
//! See the [`File` struct](./struct.File.html) for details.

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

extern crate goblin;

use std::fmt;
use std::io::Cursor;

mod elf;
pub use elf::*;

mod macho;
pub use macho::*;

/// An object file.
#[derive(Debug)]
pub struct File<'a> {
    inner: FileInternal<'a>,
}

#[derive(Debug)]
enum FileInternal<'a> {
    Elf(ElfFile<'a>),
    MachO(MachOFile<'a>),
}

/// An iterator of the sections of a `File`.
#[derive(Debug)]
pub struct SectionIterator<'a, 'b> {
    inner: SectionIteratorInternal<'a, 'b>,
}

// we wrap our enums in a struct so that they are kept private.
#[derive(Debug)]
enum SectionIteratorInternal<'a, 'b> {
    Elf(ElfSectionIterator<'a>),
    MachO(MachOSectionIterator<'a, 'b>),
}

/// A Section of a File
pub struct Section<'a> {
    inner: SectionInternal<'a>,
}

enum SectionInternal<'a> {
    Elf(ElfSection<'a>),
    MachO(MachOSection<'a>),
}

/// The kind of a section.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionKind {
    /// The section kind is unknown.
    Unknown,
    /// An executable code section.
    Text,
    /// A data section.
    Data,
    /// A read only data section.
    ReadOnlyData,
    /// An uninitialized data section.
    UninitializedData,
    /// Some other type of text or data section.
    Other,
}

/// A symbol table entry.
#[derive(Debug)]
pub struct Symbol<'a> {
    kind: SymbolKind,
    section: usize,
    section_kind: Option<SectionKind>,
    global: bool,
    name: &'a [u8],
    address: u64,
    size: u64,
}

/// The kind of a symbol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
    /// The symbol kind is unknown.
    Unknown,
    /// The symbol is for executable code.
    Text,
    /// The symbol is for a data object.
    Data,
    /// The symbol is for a section.
    Section,
    /// The symbol is the name of a file. It precedes symbols within that file.
    File,
    /// The symbol is for an uninitialized common block.
    Common,
    /// The symbol is for a thread local storage entity.
    Tls,
}

impl<'a> File<'a> {
    /// Parse the raw object file data.
    pub fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
        let mut cursor = Cursor::new(data);
        let inner = match goblin::peek(&mut cursor).map_err(|_| "Could not parse file magic")? {
            goblin::Hint::Elf(_) => FileInternal::Elf(ElfFile::parse(data)?),
            goblin::Hint::Mach(_) => FileInternal::MachO(MachOFile::parse(data)?),
            _ => return Err("Unknown file magic"),
        };
        Ok(File { inner })
    }

    /// Get the contents of the section named `section_name`, if such
    /// a section exists.
    pub fn get_section(&self, section_name: &str) -> Option<&'a [u8]> {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.get_section(section_name),
            FileInternal::MachO(ref macho) => macho.get_section(section_name),
        }
    }

    /// Get an Iterator over the sections in the file.
    pub fn get_sections(&self) -> SectionIterator {
        match self.inner {
            FileInternal::Elf(ref elf) => SectionIterator {
                inner: SectionIteratorInternal::Elf(elf.get_sections()),
            },
            FileInternal::MachO(ref macho) => SectionIterator {
                inner: SectionIteratorInternal::MachO(macho.get_sections()),
            },
        }
    }

    /// Get a `Vec` of the symbols defined in the file.
    pub fn get_symbols(&self) -> Vec<Symbol<'a>> {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.get_symbols(),
            FileInternal::MachO(ref macho) => macho.get_symbols(),
        }
    }

    /// Return true if the file is little endian, false if it is big endian.
    pub fn is_little_endian(&self) -> bool {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.is_little_endian(),
            FileInternal::MachO(ref macho) => macho.is_little_endian(),
        }
    }
}

impl<'a, 'b> Iterator for SectionIterator<'a, 'b> {
    type Item = Section<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match &mut self.inner {
            &mut SectionIteratorInternal::Elf(ref mut elf) => elf.next().map(|x| {
                Section {
                    inner: SectionInternal::Elf(x),
                }
            }),
            &mut SectionIteratorInternal::MachO(ref mut macho) => macho.next().map(|x| {
                Section {
                    inner: SectionInternal::MachO(x),
                }
            }),
        }
    }
}

impl<'a> fmt::Debug for Section<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // It's painful to do much better than this
        f.debug_struct("Section")
            .field("name", &self.name().unwrap_or("<invalid name>"))
            .field("address", &self.address())
            .field("size", &self.data().len())
            .finish()
    }
}

impl<'a> Section<'a> {
    /// returns the address of the section
    pub fn address(&self) -> u64 {
        match &self.inner {
            &SectionInternal::Elf(ref elf) => elf.address(),
            &SectionInternal::MachO(ref macho) => macho.address(),
        }
    }

    /// returns a reference to contents of the section
    pub fn data(&self) -> &'a [u8] {
        match &self.inner {
            &SectionInternal::Elf(ref elf) => elf.data(),
            &SectionInternal::MachO(ref macho) => macho.data(),
        }
    }

    /// returns the name of the section
    pub fn name(&self) -> Option<&str> {
        match &self.inner {
            &SectionInternal::Elf(ref elf) => elf.name(),
            &SectionInternal::MachO(ref macho) => macho.name(),
        }
    }
}

impl<'a> Symbol<'a> {
    /// Return the kind of this symbol.
    #[inline]
    pub fn kind(&self) -> SymbolKind {
        self.kind
    }

    /// Returns the section kind for the symbol, or `None` if the symbol is undefnined.
    #[inline]
    pub fn section_kind(&self) -> Option<SectionKind> {
        self.section_kind
    }

    /// Return true if the symbol is undefined.
    #[inline]
    pub fn is_undefined(&self) -> bool {
        self.section_kind.is_none()
    }

    /// Return true if the symbol is global.
    #[inline]
    pub fn is_global(&self) -> bool {
        self.global
    }

    /// Return true if the symbol is local.
    #[inline]
    pub fn is_local(&self) -> bool {
        !self.global
    }

    /// The name of the symbol.
    #[inline]
    pub fn name(&self) -> &'a [u8] {
        self.name
    }

    /// The address of the symbol. May be zero if the address is unknown.
    #[inline]
    pub fn address(&self) -> u64 {
        self.address
    }

    /// The size of the symbol. May be zero if the size is unknown.
    #[inline]
    pub fn size(&self) -> u64 {
        self.size
    }
}

#[doc(hidden)]
#[deprecated]
pub trait Object {}
<|endoftext|>


<commit_before>/* Copyright 2015 Jordan Miner
 *
 * 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.
 */

use std::borrow::Cow;
use std::collections::HashMap;
use std::rc::Rc;

mod idl;
mod decode;

pub use idl::Lexer;
pub use idl::parse_idl;
pub use decode::decode;

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a, 'b> {
	Null,
	Boolean(bool),
	Int(i32),
	Long(i64),
	Float(f32),
	Double(f64),
	Bytes(Cow<'b, [u8]>),
	String(Cow<'b, str>),
	Record(Rc<RecordSchema<'a>>, Vec<Value<'a, 'b>>),
	Enum(Rc<EnumSchema<'a>>, i32),
	Array(Vec<Value<'a, 'b>>),
	Map(HashMap<Cow<'a, str>, Value<'a, 'b>>),
	Fixed(Rc<FixedSchema<'a>>, Cow<'b, [u8]>),

}

#[derive(Debug, Clone, PartialEq)]
pub struct Field<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
	pub ty: Schema<'a>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct RecordSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
	pub fields: Vec<Field<'a>>,
	pub field_indexes: HashMap<Cow<'a, str>, usize>,
}

fn create_field_indexes<'a>(fields: &Vec<Field<'a>>) -> HashMap<Cow<'a, str>, usize> {
    fields.iter().enumerate().fold(HashMap::new(), |mut map, (i, f)| {
        map.insert(f.name.clone(), i);
        map
    })
}

impl<'a> RecordSchema<'a> {
    pub fn new(name: Cow<'a, str>, doc: Option<Cow<'a, str>>, fields: Vec<Field<'a>>)
    -> RecordSchema<'a> {
        let indexes = create_field_indexes(&fields);
        RecordSchema {
            name: name,
            doc: doc,
            fields: fields,
            field_indexes: indexes,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct EnumSymbol<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct EnumSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
	pub symbols: Vec<EnumSymbol<'a>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct FixedSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
	pub size: usize,
}

impl<'a> FixedSchema<'a> {
    pub fn new(name: Cow<'a, str>, doc: Option<Cow<'a, str>>, size: usize)
    -> FixedSchema<'a> {
        FixedSchema {
            name: name,
            doc: doc,
            size: size,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Schema<'a> {
	Null,
	Boolean,
	Int,
	Long,
	Float,
	Double,
	Bytes,
	String,
	Record(Rc<RecordSchema<'a>>),
	Error(Rc<RecordSchema<'a>>),
	Enum(Rc<EnumSchema<'a>>),
	Array {
		items: Box<Schema<'a>>,
	},
	Map {
		values: Box<Schema<'a>>,
	},
	Union {
		tys: Vec<Schema<'a>>,
	},
	Fixed(Rc<FixedSchema<'a>>),
}

//impl<'a> Schema<'a> {
//    pub fn to_static(&self) -> Schema<'static> {
//    }
//}

#[derive(Debug, Clone, PartialEq)]
pub struct Message<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Protocol<'a> {
    pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub tys: Vec<Schema<'a>>,
    pub messages: Vec<Message<'a>>,
}
<commit_msg>Fix a lifetime parameter<commit_after>/* Copyright 2015 Jordan Miner
 *
 * 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.
 */

use std::borrow::Cow;
use std::collections::HashMap;
use std::rc::Rc;

mod idl;
mod decode;

pub use idl::Lexer;
pub use idl::parse_idl;
pub use decode::decode;

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a, 'b> {
	Null,
	Boolean(bool),
	Int(i32),
	Long(i64),
	Float(f32),
	Double(f64),
	Bytes(Cow<'b, [u8]>),
	String(Cow<'b, str>),
	Record(Rc<RecordSchema<'a>>, Vec<Value<'a, 'b>>),
	Enum(Rc<EnumSchema<'a>>, i32),
	Array(Vec<Value<'a, 'b>>),
	Map(HashMap<Cow<'b, str>, Value<'a, 'b>>),
	Fixed(Rc<FixedSchema<'a>>, Cow<'b, [u8]>),

}

#[derive(Debug, Clone, PartialEq)]
pub struct Field<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
	pub ty: Schema<'a>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct RecordSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
	pub fields: Vec<Field<'a>>,
	pub field_indexes: HashMap<Cow<'a, str>, usize>,
}

fn create_field_indexes<'a>(fields: &Vec<Field<'a>>) -> HashMap<Cow<'a, str>, usize> {
    fields.iter().enumerate().fold(HashMap::new(), |mut map, (i, f)| {
        map.insert(f.name.clone(), i);
        map
    })
}

impl<'a> RecordSchema<'a> {
    pub fn new(name: Cow<'a, str>, doc: Option<Cow<'a, str>>, fields: Vec<Field<'a>>)
    -> RecordSchema<'a> {
        let indexes = create_field_indexes(&fields);
        RecordSchema {
            name: name,
            doc: doc,
            fields: fields,
            field_indexes: indexes,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct EnumSymbol<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct EnumSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
	pub symbols: Vec<EnumSymbol<'a>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct FixedSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
	pub size: usize,
}

impl<'a> FixedSchema<'a> {
    pub fn new(name: Cow<'a, str>, doc: Option<Cow<'a, str>>, size: usize)
    -> FixedSchema<'a> {
        FixedSchema {
            name: name,
            doc: doc,
            size: size,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Schema<'a> {
	Null,
	Boolean,
	Int,
	Long,
	Float,
	Double,
	Bytes,
	String,
	Record(Rc<RecordSchema<'a>>),
	Error(Rc<RecordSchema<'a>>),
	Enum(Rc<EnumSchema<'a>>),
	Array {
		items: Box<Schema<'a>>,
	},
	Map {
		values: Box<Schema<'a>>,
	},
	Union {
		tys: Vec<Schema<'a>>,
	},
	Fixed(Rc<FixedSchema<'a>>),
}

//impl<'a> Schema<'a> {
//    pub fn to_static(&self) -> Schema<'static> {
//    }
//}

#[derive(Debug, Clone, PartialEq)]
pub struct Message<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Protocol<'a> {
    pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub tys: Vec<Schema<'a>>,
    pub messages: Vec<Message<'a>>,
}
<|endoftext|>


<commit_before>// Copyright (c) 2018, Ben Boeckel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//     * Neither the name of this project nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//! Linux keyring bindings for Rust
//!
//! This crate provides a high-level API for interacting with the Linux keys subsystem.

#![warn(missing_docs)]

mod api;
mod constants;
mod keytype;

pub mod keytypes;

pub use self::api::*;
pub use self::constants::*;
pub use self::keytype::*;

pub use keyutils_raw::{DefaultKeyring, KeyPermissions, KeyringSerial, TimeoutSeconds};

#[cfg(test)]
mod tests;
<commit_msg>clippy: ignore warning about case spellings<commit_after>// Copyright (c) 2018, Ben Boeckel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//     * Neither the name of this project nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//! Linux keyring bindings for Rust
//!
//! This crate provides a high-level API for interacting with the Linux keys subsystem.

#![warn(missing_docs)]
#![allow(clippy::upper_case_acronyms)]

mod api;
mod constants;
mod keytype;

pub mod keytypes;

pub use self::api::*;
pub use self::constants::*;
pub use self::keytype::*;

pub use keyutils_raw::{DefaultKeyring, KeyPermissions, KeyringSerial, TimeoutSeconds};

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>#![feature(io, core)]
#![cfg_attr(test, deny(warnings))]

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use conduit::{Request, Method};
use middleware::Middleware;
use std::borrow::Cow;
use std::error::Error;
use std::io;
use time::{Tm, strptime, ParseError};

type Response = Result<conduit::Response, Box<Error+Send>>;

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            Method::Get | Method::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.remove("Content-Type");
                    res.headers.remove("Content-Length");
                    res.body = Box::new(io::empty());
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(none_match, res);
    });

    success
}

fn etag_matches<S: Str>(none_match: S, res: &conduit::Response) -> bool {
    res.headers.get("ETag").map(|etag| {
        res_header_val(etag).as_slice() == none_match.as_slice()
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.get("Last-Modified").and_then(|last_modified| {
        parse_http_date(res_header_val(last_modified).as_slice()).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> Cow<'a, str> {
    if header.len() == 1 {
        Cow::Borrowed(header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> Cow<'a, str> {
    if header.len() == 1 {
        Cow::Borrowed(header[0].as_slice())
    } else {
        Cow::Owned(header.concat())
    }
}

fn parse_http_date<S: Str>(string: S) -> Result<Tm, ()> {
    let string = string.as_slice();

    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use std::collections::HashMap;
    use std::error::Error;
    use std::io::Cursor;
    use time;
    use time::Tm;
    use conduit;
    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning {
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::Get, "/");
            $(req.header($header, $value.to_string().as_slice());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z").unwrap().to_string();
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        ) as &mut conduit::Request));
    }

    fn expect_304(response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let mut body = String::new();
        response.body.read_to_string(&mut body).ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body.as_slice(), "");
    }

    fn expect_200(response: Result<Response, Box<Error+Send>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (u32, &'static str), response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let mut body = String::new();
        response.body.read_to_string(&mut body).ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body.as_slice(), "hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (u32, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Error+Send>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: Box::new(Cursor::new(self.body.to_string().into_bytes())),
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<commit_msg>Update to rust master<commit_after>#![feature(core)]
#![cfg_attr(test, deny(warnings))]

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use conduit::{Request, Method};
use middleware::Middleware;
use std::borrow::Cow;
use std::error::Error;
use std::io;
use time::{Tm, strptime, ParseError};

type Response = Result<conduit::Response, Box<Error+Send>>;

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            Method::Get | Method::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.remove("Content-Type");
                    res.headers.remove("Content-Length");
                    res.body = Box::new(io::empty());
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(none_match, res);
    });

    success
}

fn etag_matches<S: Str>(none_match: S, res: &conduit::Response) -> bool {
    res.headers.get("ETag").map(|etag| {
        res_header_val(etag).as_slice() == none_match.as_slice()
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.get("Last-Modified").and_then(|last_modified| {
        parse_http_date(res_header_val(last_modified).as_slice()).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> Cow<'a, str> {
    if header.len() == 1 {
        Cow::Borrowed(header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> Cow<'a, str> {
    if header.len() == 1 {
        Cow::Borrowed(header[0].as_slice())
    } else {
        Cow::Owned(header.concat())
    }
}

fn parse_http_date<S: Str>(string: S) -> Result<Tm, ()> {
    let string = string.as_slice();

    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use std::collections::HashMap;
    use std::error::Error;
    use std::io::Cursor;
    use time;
    use time::Tm;
    use conduit;
    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning {
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::Get, "/");
            $(req.header($header, $value.to_string().as_slice());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z").unwrap().to_string();
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        ) as &mut conduit::Request));
    }

    fn expect_304(response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let mut body = String::new();
        response.body.read_to_string(&mut body).ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body.as_slice(), "");
    }

    fn expect_200(response: Result<Response, Box<Error+Send>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (u32, &'static str), response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let mut body = String::new();
        response.body.read_to_string(&mut body).ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body.as_slice(), "hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (u32, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Error+Send>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: Box::new(Cursor::new(self.body.to_string().into_bytes())),
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![crate_name = "klogger"]
#![crate_type = "lib"]

use core::fmt;

#[macro_use]
pub mod macros;

extern crate log;
extern crate termcodes;

#[cfg(target_arch = "x86_64")]
extern crate x86;

#[cfg(target_arch = "x86_64")]
#[path = "arch/x86.rs"]
mod arch;

use log::{Level, Metadata, Record, SetLoggerError};
use termcodes::color;

static mut LOGGER: KLogger = KLogger { start_tsc: 0 };

pub struct Writer;

impl Writer {
    /// Obtain a logger for the specified module.
    pub fn get_module(module: &str) -> Writer {
        use core::fmt::Write;
        let mut ret = Writer;
        write!(&mut ret, "[{}] ", module).expect("Writer");
        ret
    }

    pub fn get() -> Writer {
        Writer
    }
}

impl ::core::ops::Drop for Writer {
    /// Release the logger.
    fn drop(&mut self) {
        use core::fmt::Write;
        write!(self, "\n").expect("Newline");
    }
}

impl fmt::Write for Writer {
    /// Write stuff to serial out.
    fn write_str(&mut self, s: &str) -> fmt::Result {
        unsafe {
            arch::puts(s);
        }
        Ok(())
    }
}

pub struct WriterNoDrop;

impl WriterNoDrop {
    pub fn get() -> WriterNoDrop {
        WriterNoDrop
    }
}

impl fmt::Write for WriterNoDrop {
    /// Write stuff to serial out.
    fn write_str(&mut self, s: &str) -> fmt::Result {
        unsafe {
            arch::puts(s);
        }
        Ok(())
    }
}

struct KLogger {
    start_tsc: u64,
}

impl log::Log for KLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= Level::Trace
    }

    fn log(&self, record: &Record) {
        if self.enabled(record.metadata()) {
            let cur = unsafe { x86::time::rdtsc() };

            let color = match record.level() {
                Level::Error => color::AnsiValue(202),
                Level::Warn => color::AnsiValue(167),
                Level::Info => color::AnsiValue(136),
                Level::Debug => color::AnsiValue(64),
                Level::Trace => color::AnsiValue(32),
            };

            sprintln!(
                "{}{:>10}{} [{}{:5}{}] - {}: {}{}{}",
                color::Fg(color::LightYellow),
                cur - self.start_tsc,
                color::Fg(color::Reset),
                color::Fg(color),
                record.level(),
                color::Fg(color::Reset),
                record.target(),
                color::Fg(color::LightWhite),
                record.args(),
                color::Fg(color::Reset),
            );
        }
    }

    fn flush(&self) {}
}

pub fn init(level: Level) -> Result<(), SetLoggerError> {
    unsafe {
        (&mut LOGGER).start_tsc = x86::time::rdtsc();
        log::set_logger(&LOGGER).map(|()| log::set_max_level(level.to_level_filter()))
    }
}
<commit_msg>Ongoing effort to try to get the tsc frequency on different platforms...<commit_after>#![no_std]
#![crate_name = "klogger"]
#![crate_type = "lib"]
#![feature(use_extern_macros)]

use core::fmt;

#[macro_use]
pub mod macros;

extern crate log;
extern crate termcodes;

#[cfg(target_arch = "x86_64")]
extern crate x86;
use x86::cpuid::cpuid;

#[cfg(target_arch = "x86_64")]
#[path = "arch/x86.rs"]
mod arch;

use log::{Level, Metadata, Record, SetLoggerError};
use termcodes::color;

static mut LOGGER: KLogger = KLogger {
    has_tsc: false,
    has_invariant_tsc: false,

    tsc_start: 0,
    tsc_frequency: 1,
};

pub struct Writer;

impl Writer {
    /// Obtain a logger for the specified module.
    pub fn get_module(module: &str) -> Writer {
        use core::fmt::Write;
        let mut ret = Writer;
        write!(&mut ret, "[{}] ", module).expect("Writer");
        ret
    }

    pub fn get() -> Writer {
        Writer
    }
}

impl ::core::ops::Drop for Writer {
    /// Release the logger.
    fn drop(&mut self) {
        use core::fmt::Write;
        write!(self, "\n").expect("Newline");
    }
}

impl fmt::Write for Writer {
    /// Write stuff to serial out.
    fn write_str(&mut self, s: &str) -> fmt::Result {
        unsafe {
            arch::puts(s);
        }
        Ok(())
    }
}

pub struct WriterNoDrop;

impl WriterNoDrop {
    pub fn get() -> WriterNoDrop {
        WriterNoDrop
    }
}

impl fmt::Write for WriterNoDrop {
    /// Write stuff to serial out.
    fn write_str(&mut self, s: &str) -> fmt::Result {
        unsafe {
            arch::puts(s);
        }
        Ok(())
    }
}

#[derive(Debug)]
struct KLogger {
    has_tsc: bool,
    has_invariant_tsc: bool,
    tsc_start: u64,
    /// Frequency in Hz
    tsc_frequency: u64,
}

impl KLogger {
    /// Time in nano seconds since KLogger init.
    fn elapsed_ns(&self) -> u64 {
        if self.has_tsc {
            let cur = unsafe { x86::time::rdtsc() };
            let elapsed = cur - self.tsc_start;
            elapsed / core::cmp::max(1, self.tsc_frequency / 1_000_000_000)
        } else {
            0
        }
    }
}

impl log::Log for KLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= Level::Trace
    }

    fn log(&self, record: &Record) {
        if self.enabled(record.metadata()) {
            let color = match record.level() {
                Level::Error => color::AnsiValue(202),
                Level::Warn => color::AnsiValue(167),
                Level::Info => color::AnsiValue(136),
                Level::Debug => color::AnsiValue(64),
                Level::Trace => color::AnsiValue(32),
            };

            sprintln!(
                "{}{:>10}{} [{}{:5}{}] - {}: {}{}{}",
                color::Fg(color::LightYellow),
                self.elapsed_ns(),
                color::Fg(color::Reset),
                color::Fg(color),
                record.level(),
                color::Fg(color::Reset),
                record.target(),
                color::Fg(color::LightWhite),
                record.args(),
                color::Fg(color::Reset),
            );
        }
    }

    fn flush(&self) {}
}

pub fn init(level: Level) -> Result<(), SetLoggerError> {
    let cpuid = x86::cpuid::CpuId::new();

    unsafe {
        (&mut LOGGER).has_tsc = cpuid
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_tsc());
        (&mut LOGGER).has_invariant_tsc = cpuid
            .get_extended_function_info()
            .map_or(false, |efinfo| efinfo.has_invariant_tsc());
        if LOGGER.has_tsc {
            (&mut LOGGER).tsc_start = x86::time::rdtsc();
        }
        let hypervisor_base = cpuid!(0x40000000, 0);
        let is_kvm = hypervisor_base.eax == 0x40000001
            && hypervisor_base.ebx == 0x4b4d564b
            && hypervisor_base.ecx == 0x564b4d56
            && hypervisor_base.edx == 0x4d;

        if cpuid.get_tsc_info().is_some() {
            // Nominal TSC frequency = ( CPUID.15H.ECX[31:0] * CPUID.15H.EBX[31:0] ) ÷ CPUID.15H.EAX[31:0]
            (&mut LOGGER).tsc_frequency = cpuid
                .get_tsc_info()
                .map_or(1, |tinfo| tinfo.tsc_frequency());
        } else if cpuid.get_processor_frequency_info().is_some() {
            (&mut LOGGER).tsc_frequency = cpuid
                .get_processor_frequency_info()
                .map_or(2, |pinfo| pinfo.processor_max_frequency() as u64 * 1000000);
        } else if is_kvm {
            // vm aware tsc frequency retrieval: https://lwn.net/Articles/301888/
            // # EAX: (Virtual) TSC frequency in kHz.
            // # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
            // # ECX, EDX: RESERVED (Per above, reserved fields are set to zero).
            let virt_tinfo = cpuid!(0x40000010, 0);
            (&mut LOGGER).tsc_frequency = virt_tinfo.eax as u64 * 1000;
        } else {
            (&mut LOGGER).tsc_frequency = 1;
        }

        // Another way that segfaults in KVM:
        // The scalable bus frequency is encoded in the bit field MSR_PLATFORM_INFO[15:8]
        // and the nominal TSC frequency can be determined by multiplying this number
        // by a bus speed of 100 MHz.
        //(&mut LOGGER).tsc_frequency =
        //    ((x86::msr::rdmsr(x86::msr::MSR_PLATFORM_INFO) >> 8) & 0xff) * 1000000;

        log::set_logger(&LOGGER).map(|()| log::set_max_level(level.to_level_filter()))
    }
}
<|endoftext|>