<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Untyped root container for a Cap'n Proto value.

use any_pointer;
use private::arena::{BuilderArenaImpl, ReaderArenaImpl, BuilderArena, ReaderArena};
use private::layout;
use traits::{FromPointerReader, FromPointerBuilder, SetPointerBuilder};
use {OutputSegments, Result, Word};

/// Options controlling how data is read.
#[derive(Clone, Copy, Debug)]
pub struct ReaderOptions {

    /// Limits how many total words of data are allowed to be traversed. Traversal is counted when
    /// a new struct or list builder is obtained, e.g. from a get() accessor. This means that calling
    /// the getter for the same sub-struct multiple times will cause it to be double-counted. Once
    /// the traversal limit is reached, an error will be reported.
    ///
    /// This limit exists for security reasons. It is possible for an attacker to construct a message
    /// in which multiple pointers point at the same location. This is technically invalid, but hard
    /// to detect. Using such a message, an attacker could cause a message which is small on the wire
    /// to appear much larger when actually traversed, possibly exhausting server resources leading to
    /// denial-of-service.
    ///
    /// It makes sense to set a traversal limit that is much larger than the underlying message.
    /// Together with sensible coding practices (e.g. trying to avoid calling sub-object getters
    /// multiple times, which is expensive anyway), this should provide adequate protection without
    /// inconvenience.
    pub traversal_limit_in_words: u64,

    /// Limits how deeply nested a message structure can be, e.g. structs containing other structs or
    /// lists of structs.
    ///
    /// Like the traversal limit, this limit exists for security reasons. Since it is common to use
    /// recursive code to traverse recursive data structures, an attacker could easily cause a stack
    /// overflow by sending a very-depply-nested (or even cyclic) message, without the message even
    /// being very large. The default limit of 64 is probably low enough to prevent any chance of
    /// stack overflow, yet high enough that it is never a problem in practice.
    pub nesting_limit: i32,
}

pub const DEFAULT_READER_OPTIONS: ReaderOptions =
    ReaderOptions { traversal_limit_in_words: 8 * 1024 * 1024, nesting_limit: 64 };

impl Default for ReaderOptions {
    fn default() -> ReaderOptions {
        DEFAULT_READER_OPTIONS
    }
}

impl ReaderOptions {
    pub fn new() -> ReaderOptions { DEFAULT_READER_OPTIONS }

    pub fn nesting_limit<'a>(&'a mut self, value: i32) -> &'a mut ReaderOptions {
        self.nesting_limit = value;
        return self;
    }

    pub fn traversal_limit_in_words<'a>(&'a mut self, value: u64) -> &'a mut ReaderOptions {
        self.traversal_limit_in_words = value;
        return self;
    }
}

/// An object that manages the buffers underlying a Cap'n Proto message reader.
pub trait ReaderSegments {
    fn get_segment<'a>(&'a self, id: u32) -> Option<&'a [Word]>;
}

/// An array of segments.
pub struct SegmentArray<'a> {
    segments: &'a [&'a [Word]],
}

impl <'a> SegmentArray<'a> {
    pub fn new(segments: &'a [&'a [Word]]) -> SegmentArray<'a> {
        SegmentArray { segments: segments }
    }
}

impl <'b> ReaderSegments for SegmentArray<'b> {
    fn get_segment<'a>(&'a self, id: u32) -> Option<&'a [Word]> {
        self.segments.get(id as usize).map(|slice| *slice)
    }
}

/// A container used to read a message.
pub struct Reader<S> where S: ReaderSegments {
    arena: ReaderArenaImpl<S>,
    nesting_limit: i32,
}

impl <S> Reader<S> where S: ReaderSegments {
    pub fn new(segments: S, options: ReaderOptions) -> Self {
        Reader {
            arena: ReaderArenaImpl::new(segments, options),
            nesting_limit: options.nesting_limit,
        }
    }

    fn get_root_internal<'a>(&'a self) -> Result<any_pointer::Reader<'a>> {
        let (segment_start, _seg_len) = try!(self.arena.get_segment(0));
        let pointer_reader = try!(layout::PointerReader::get_root(
            &self.arena, 0, segment_start, self.nesting_limit));
        Ok(any_pointer::Reader::new(pointer_reader))
    }

    /// Gets the root of the message, interpreting it as the given type.
    pub fn get_root<'a, T: FromPointerReader<'a>>(&'a self) -> Result<T> {
        try!(self.get_root_internal()).get_as()
    }

    pub fn into_segments(self) -> S {
        self.arena.into_segments()
    }
}

/// An object that allocates memory for a Cap'n Proto message as it is being built.
pub unsafe trait Allocator {
    /// Allocates memory for a new segment, returning a pointer to the start of the segment
    /// and a u32 indicating the length of the segment.
    ///
    /// UNSAFETY ALERT: The callee is responsible for ensuring that the returned memory is valid
    /// for the lifetime of the object and doesn't overlap with other allocated memory.
    fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32);

    fn pre_drop(&mut self, _segment0_currently_allocated: u32) {}
}

/* TODO(version 0.9): update to a more user-friendly trait here?
pub trait Allocator {
    /// Allocates memory for a new segment.
    fn allocate_segment(&mut self, minimum_size: u32) -> Result<()>;

    fn get_segment<'a>(&'a self, id: u32) -> &'a [Word];
    fn get_segment_mut<'a>(&'a mut self, id: u32) -> &'a mut [Word];

    fn pre_drop(&mut self, _segment0_currently_allocated: u32) {}
}
*/

/// A container used to build a message.
pub struct Builder<A> where A: Allocator {
    arena: BuilderArenaImpl<A>,
    cap_table: Vec<Option<Box<::private::capability::ClientHook>>>,
}

// TODO(version 0.9): Consider removing this unsafe impl somwhow.
//   As soon as a message::Builder has caps in its table, it is not
//   in fact safe to send to other threads. Perhaps we should remove
//   the Builder::cap_table field, requiring imbue_mut() to be called
//   manually when the situation calls for it.
unsafe impl <A> Send for Builder<A> where A: Send + Allocator {}

fn _assert_kinds() {
    fn _assert_send<T: Send>() {}
    fn _assert_reader<S: ReaderSegments + Send>() {
        _assert_send::<Reader<S>>();
    }
//    fn _assert_builder<A: Allocator + Send>() {
//        _assert_send::<Builder<A>>();
//    }
}

impl <A> Builder<A> where A: Allocator {
    pub fn new(allocator: A) -> Self {
        Builder {
            arena: BuilderArenaImpl::new(allocator),
            cap_table: Vec::new(),
        }
    }

    fn get_root_internal<'a>(&'a mut self) -> any_pointer::Builder<'a> {
        use ::traits::ImbueMut;
        if self.arena.len() == 0 {
            self.arena.allocate_segment(1).expect("allocate root pointer");
            self.arena.allocate(0, 1).expect("allocate root pointer");
        }
        let (seg_start, _seg_len) = self.arena.get_segment_mut(0);
        let location: *mut Word = seg_start;
        let Builder { ref mut arena, ref mut cap_table } = *self;

        let mut result = any_pointer::Builder::new(
            layout::PointerBuilder::get_root(arena, 0, location));
        result.imbue_mut(cap_table);
        result
    }

    /// Initializes the root as a value of the given type.
    pub fn init_root<'a, T: FromPointerBuilder<'a>>(&'a mut self) -> T {
        let root = self.get_root_internal();
        root.init_as()
    }

    /// Gets the root, interpreting it as the given type.
    pub fn get_root<'a, T: FromPointerBuilder<'a>>(&'a mut self) -> Result<T> {
        let root = self.get_root_internal();
        root.get_as()
    }

    pub fn get_root_as_reader<'a, T: FromPointerReader<'a>>(&'a self) -> Result<T> {
        if self.arena.len() == 0 {
            any_pointer::Reader::new(layout::PointerReader::new_default()).get_as()
        } else {
            use ::traits::Imbue;
            let (segment_start, _segment_len) = try!(self.arena.get_segment(0));
            let pointer_reader = try!(layout::PointerReader::get_root(
                self.arena.as_reader(), 0, segment_start, 0x7fffffff));
            let mut root = any_pointer::Reader::new(pointer_reader);
            root.imbue(&self.cap_table);
            root.get_as()
        }
    }

    /// Sets the root to a deep copy of the given value.
    pub fn set_root<To, From: SetPointerBuilder<To>>(&mut self, value: From) -> Result<()> {
        let root = self.get_root_internal();
        root.set_as(value)
    }

    pub fn get_segments_for_output<'a>(&'a self) -> OutputSegments<'a> {
        self.arena.get_segments_for_output()
    }
}

#[derive(Debug)]
pub struct HeapAllocator {
    owned_memory: Vec<Vec<Word>>,
    next_size: u32,
    allocation_strategy: AllocationStrategy,
}

#[derive(Clone, Copy, Debug)]
pub enum AllocationStrategy {
    FixedSize,
    GrowHeuristically
}

pub const SUGGESTED_FIRST_SEGMENT_WORDS: u32 = 1024;
pub const SUGGESTED_ALLOCATION_STRATEGY: AllocationStrategy = AllocationStrategy::GrowHeuristically;

impl HeapAllocator {
    pub fn new() -> HeapAllocator {
        HeapAllocator { owned_memory: Vec::new(),
                        next_size: SUGGESTED_FIRST_SEGMENT_WORDS,
                        allocation_strategy: SUGGESTED_ALLOCATION_STRATEGY }
    }

    pub fn first_segment_words(mut self, value: u32) -> HeapAllocator {
        self.next_size = value;
        self
    }

    pub fn allocation_strategy(mut self, value : AllocationStrategy) -> HeapAllocator {
        self.allocation_strategy = value;
        self
    }
}

unsafe impl Allocator for HeapAllocator {
    fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32) {
        let size = ::std::cmp::max(minimum_size, self.next_size);
        let mut new_words = Word::allocate_zeroed_vec(size as usize);
        let ptr = new_words.as_mut_ptr();
        self.owned_memory.push(new_words);

        match self.allocation_strategy {
            AllocationStrategy::GrowHeuristically => { self.next_size += size; }
            _ => { }
        }
        (ptr, size as u32)
    }
}

impl Builder<HeapAllocator> {
    pub fn new_default() -> Builder<HeapAllocator> {
        Builder::new(HeapAllocator::new())
    }
}

#[derive(Debug)]
pub struct ScratchSpace<'a> {
    slice: &'a mut [Word],
    in_use: bool,
}

impl <'a> ScratchSpace<'a> {
    pub fn new(slice: &'a mut [Word]) -> ScratchSpace<'a> {
        ScratchSpace { slice: slice, in_use: false }
    }
}

pub struct ScratchSpaceHeapAllocator<'a, 'b: 'a> {
    scratch_space: &'a mut ScratchSpace<'b>,
    allocator: HeapAllocator,
}

impl <'a, 'b: 'a> ScratchSpaceHeapAllocator<'a, 'b> {
    pub fn new(scratch_space: &'a mut ScratchSpace<'b>) -> ScratchSpaceHeapAllocator<'a, 'b> {
        ScratchSpaceHeapAllocator { scratch_space: scratch_space,
                                    allocator: HeapAllocator::new()}
    }

    pub fn second_segment_words(mut self, value: u32) -> ScratchSpaceHeapAllocator<'a, 'b> {
        ScratchSpaceHeapAllocator { scratch_space: self.scratch_space,
                                    allocator: self.allocator.first_segment_words(value) }

    }

    pub fn allocation_strategy(mut self, value: AllocationStrategy) -> ScratchSpaceHeapAllocator<'a, 'b> {
        ScratchSpaceHeapAllocator { scratch_space: self.scratch_space,
                                    allocator: self.allocator.allocation_strategy(value) }
    }

}

unsafe impl <'a, 'b: 'a> Allocator for ScratchSpaceHeapAllocator<'a, 'b> {
    fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32) {
        if !self.scratch_space.in_use {
            self.scratch_space.in_use = true;
            (self.scratch_space.slice.as_mut_ptr(), self.scratch_space.slice.len() as u32)
        } else {
            self.allocator.allocate_segment(minimum_size)
        }
    }

    fn pre_drop(&mut self, segment0_currently_allocated: u32) {
        let ptr = self.scratch_space.slice.as_mut_ptr();
        unsafe {
            ::std::ptr::write_bytes(ptr, 0u8, segment0_currently_allocated as usize);
        }
        self.scratch_space.in_use = false;
    }
}

<commit_msg>uncomment Send assertion for message::Builder<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Untyped root container for a Cap'n Proto value.

use any_pointer;
use private::arena::{BuilderArenaImpl, ReaderArenaImpl, BuilderArena, ReaderArena};
use private::layout;
use traits::{FromPointerReader, FromPointerBuilder, SetPointerBuilder};
use {OutputSegments, Result, Word};

/// Options controlling how data is read.
#[derive(Clone, Copy, Debug)]
pub struct ReaderOptions {

    /// Limits how many total words of data are allowed to be traversed. Traversal is counted when
    /// a new struct or list builder is obtained, e.g. from a get() accessor. This means that calling
    /// the getter for the same sub-struct multiple times will cause it to be double-counted. Once
    /// the traversal limit is reached, an error will be reported.
    ///
    /// This limit exists for security reasons. It is possible for an attacker to construct a message
    /// in which multiple pointers point at the same location. This is technically invalid, but hard
    /// to detect. Using such a message, an attacker could cause a message which is small on the wire
    /// to appear much larger when actually traversed, possibly exhausting server resources leading to
    /// denial-of-service.
    ///
    /// It makes sense to set a traversal limit that is much larger than the underlying message.
    /// Together with sensible coding practices (e.g. trying to avoid calling sub-object getters
    /// multiple times, which is expensive anyway), this should provide adequate protection without
    /// inconvenience.
    pub traversal_limit_in_words: u64,

    /// Limits how deeply nested a message structure can be, e.g. structs containing other structs or
    /// lists of structs.
    ///
    /// Like the traversal limit, this limit exists for security reasons. Since it is common to use
    /// recursive code to traverse recursive data structures, an attacker could easily cause a stack
    /// overflow by sending a very-depply-nested (or even cyclic) message, without the message even
    /// being very large. The default limit of 64 is probably low enough to prevent any chance of
    /// stack overflow, yet high enough that it is never a problem in practice.
    pub nesting_limit: i32,
}

pub const DEFAULT_READER_OPTIONS: ReaderOptions =
    ReaderOptions { traversal_limit_in_words: 8 * 1024 * 1024, nesting_limit: 64 };

impl Default for ReaderOptions {
    fn default() -> ReaderOptions {
        DEFAULT_READER_OPTIONS
    }
}

impl ReaderOptions {
    pub fn new() -> ReaderOptions { DEFAULT_READER_OPTIONS }

    pub fn nesting_limit<'a>(&'a mut self, value: i32) -> &'a mut ReaderOptions {
        self.nesting_limit = value;
        return self;
    }

    pub fn traversal_limit_in_words<'a>(&'a mut self, value: u64) -> &'a mut ReaderOptions {
        self.traversal_limit_in_words = value;
        return self;
    }
}

/// An object that manages the buffers underlying a Cap'n Proto message reader.
pub trait ReaderSegments {
    fn get_segment<'a>(&'a self, id: u32) -> Option<&'a [Word]>;
}

/// An array of segments.
pub struct SegmentArray<'a> {
    segments: &'a [&'a [Word]],
}

impl <'a> SegmentArray<'a> {
    pub fn new(segments: &'a [&'a [Word]]) -> SegmentArray<'a> {
        SegmentArray { segments: segments }
    }
}

impl <'b> ReaderSegments for SegmentArray<'b> {
    fn get_segment<'a>(&'a self, id: u32) -> Option<&'a [Word]> {
        self.segments.get(id as usize).map(|slice| *slice)
    }
}

/// A container used to read a message.
pub struct Reader<S> where S: ReaderSegments {
    arena: ReaderArenaImpl<S>,
    nesting_limit: i32,
}

impl <S> Reader<S> where S: ReaderSegments {
    pub fn new(segments: S, options: ReaderOptions) -> Self {
        Reader {
            arena: ReaderArenaImpl::new(segments, options),
            nesting_limit: options.nesting_limit,
        }
    }

    fn get_root_internal<'a>(&'a self) -> Result<any_pointer::Reader<'a>> {
        let (segment_start, _seg_len) = try!(self.arena.get_segment(0));
        let pointer_reader = try!(layout::PointerReader::get_root(
            &self.arena, 0, segment_start, self.nesting_limit));
        Ok(any_pointer::Reader::new(pointer_reader))
    }

    /// Gets the root of the message, interpreting it as the given type.
    pub fn get_root<'a, T: FromPointerReader<'a>>(&'a self) -> Result<T> {
        try!(self.get_root_internal()).get_as()
    }

    pub fn into_segments(self) -> S {
        self.arena.into_segments()
    }
}

/// An object that allocates memory for a Cap'n Proto message as it is being built.
pub unsafe trait Allocator {
    /// Allocates memory for a new segment, returning a pointer to the start of the segment
    /// and a u32 indicating the length of the segment.
    ///
    /// UNSAFETY ALERT: The callee is responsible for ensuring that the returned memory is valid
    /// for the lifetime of the object and doesn't overlap with other allocated memory.
    fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32);

    fn pre_drop(&mut self, _segment0_currently_allocated: u32) {}
}

/* TODO(version 0.9): update to a more user-friendly trait here?
pub trait Allocator {
    /// Allocates memory for a new segment.
    fn allocate_segment(&mut self, minimum_size: u32) -> Result<()>;

    fn get_segment<'a>(&'a self, id: u32) -> &'a [Word];
    fn get_segment_mut<'a>(&'a mut self, id: u32) -> &'a mut [Word];

    fn pre_drop(&mut self, _segment0_currently_allocated: u32) {}
}
*/

/// A container used to build a message.
pub struct Builder<A> where A: Allocator {
    arena: BuilderArenaImpl<A>,
    cap_table: Vec<Option<Box<::private::capability::ClientHook>>>,
}

// TODO(version 0.9): Consider removing this unsafe impl somwhow.
//   As soon as a message::Builder has caps in its table, it is not
//   in fact safe to send to other threads. Perhaps we should remove
//   the Builder::cap_table field, requiring imbue_mut() to be called
//   manually when the situation calls for it.
unsafe impl <A> Send for Builder<A> where A: Send + Allocator {}

fn _assert_kinds() {
    fn _assert_send<T: Send>() {}
    fn _assert_reader<S: ReaderSegments + Send>() {
        _assert_send::<Reader<S>>();
    }
    fn _assert_builder<A: Allocator + Send>() {
        _assert_send::<Builder<A>>();
    }
}

impl <A> Builder<A> where A: Allocator {
    pub fn new(allocator: A) -> Self {
        Builder {
            arena: BuilderArenaImpl::new(allocator),
            cap_table: Vec::new(),
        }
    }

    fn get_root_internal<'a>(&'a mut self) -> any_pointer::Builder<'a> {
        use ::traits::ImbueMut;
        if self.arena.len() == 0 {
            self.arena.allocate_segment(1).expect("allocate root pointer");
            self.arena.allocate(0, 1).expect("allocate root pointer");
        }
        let (seg_start, _seg_len) = self.arena.get_segment_mut(0);
        let location: *mut Word = seg_start;
        let Builder { ref mut arena, ref mut cap_table } = *self;

        let mut result = any_pointer::Builder::new(
            layout::PointerBuilder::get_root(arena, 0, location));
        result.imbue_mut(cap_table);
        result
    }

    /// Initializes the root as a value of the given type.
    pub fn init_root<'a, T: FromPointerBuilder<'a>>(&'a mut self) -> T {
        let root = self.get_root_internal();
        root.init_as()
    }

    /// Gets the root, interpreting it as the given type.
    pub fn get_root<'a, T: FromPointerBuilder<'a>>(&'a mut self) -> Result<T> {
        let root = self.get_root_internal();
        root.get_as()
    }

    pub fn get_root_as_reader<'a, T: FromPointerReader<'a>>(&'a self) -> Result<T> {
        if self.arena.len() == 0 {
            any_pointer::Reader::new(layout::PointerReader::new_default()).get_as()
        } else {
            use ::traits::Imbue;
            let (segment_start, _segment_len) = try!(self.arena.get_segment(0));
            let pointer_reader = try!(layout::PointerReader::get_root(
                self.arena.as_reader(), 0, segment_start, 0x7fffffff));
            let mut root = any_pointer::Reader::new(pointer_reader);
            root.imbue(&self.cap_table);
            root.get_as()
        }
    }

    /// Sets the root to a deep copy of the given value.
    pub fn set_root<To, From: SetPointerBuilder<To>>(&mut self, value: From) -> Result<()> {
        let root = self.get_root_internal();
        root.set_as(value)
    }

    pub fn get_segments_for_output<'a>(&'a self) -> OutputSegments<'a> {
        self.arena.get_segments_for_output()
    }
}

#[derive(Debug)]
pub struct HeapAllocator {
    owned_memory: Vec<Vec<Word>>,
    next_size: u32,
    allocation_strategy: AllocationStrategy,
}

#[derive(Clone, Copy, Debug)]
pub enum AllocationStrategy {
    FixedSize,
    GrowHeuristically
}

pub const SUGGESTED_FIRST_SEGMENT_WORDS: u32 = 1024;
pub const SUGGESTED_ALLOCATION_STRATEGY: AllocationStrategy = AllocationStrategy::GrowHeuristically;

impl HeapAllocator {
    pub fn new() -> HeapAllocator {
        HeapAllocator { owned_memory: Vec::new(),
                        next_size: SUGGESTED_FIRST_SEGMENT_WORDS,
                        allocation_strategy: SUGGESTED_ALLOCATION_STRATEGY }
    }

    pub fn first_segment_words(mut self, value: u32) -> HeapAllocator {
        self.next_size = value;
        self
    }

    pub fn allocation_strategy(mut self, value : AllocationStrategy) -> HeapAllocator {
        self.allocation_strategy = value;
        self
    }
}

unsafe impl Allocator for HeapAllocator {
    fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32) {
        let size = ::std::cmp::max(minimum_size, self.next_size);
        let mut new_words = Word::allocate_zeroed_vec(size as usize);
        let ptr = new_words.as_mut_ptr();
        self.owned_memory.push(new_words);

        match self.allocation_strategy {
            AllocationStrategy::GrowHeuristically => { self.next_size += size; }
            _ => { }
        }
        (ptr, size as u32)
    }
}

impl Builder<HeapAllocator> {
    pub fn new_default() -> Builder<HeapAllocator> {
        Builder::new(HeapAllocator::new())
    }
}

#[derive(Debug)]
pub struct ScratchSpace<'a> {
    slice: &'a mut [Word],
    in_use: bool,
}

impl <'a> ScratchSpace<'a> {
    pub fn new(slice: &'a mut [Word]) -> ScratchSpace<'a> {
        ScratchSpace { slice: slice, in_use: false }
    }
}

pub struct ScratchSpaceHeapAllocator<'a, 'b: 'a> {
    scratch_space: &'a mut ScratchSpace<'b>,
    allocator: HeapAllocator,
}

impl <'a, 'b: 'a> ScratchSpaceHeapAllocator<'a, 'b> {
    pub fn new(scratch_space: &'a mut ScratchSpace<'b>) -> ScratchSpaceHeapAllocator<'a, 'b> {
        ScratchSpaceHeapAllocator { scratch_space: scratch_space,
                                    allocator: HeapAllocator::new()}
    }

    pub fn second_segment_words(mut self, value: u32) -> ScratchSpaceHeapAllocator<'a, 'b> {
        ScratchSpaceHeapAllocator { scratch_space: self.scratch_space,
                                    allocator: self.allocator.first_segment_words(value) }

    }

    pub fn allocation_strategy(mut self, value: AllocationStrategy) -> ScratchSpaceHeapAllocator<'a, 'b> {
        ScratchSpaceHeapAllocator { scratch_space: self.scratch_space,
                                    allocator: self.allocator.allocation_strategy(value) }
    }

}

unsafe impl <'a, 'b: 'a> Allocator for ScratchSpaceHeapAllocator<'a, 'b> {
    fn allocate_segment(&mut self, minimum_size: u32) -> (*mut Word, u32) {
        if !self.scratch_space.in_use {
            self.scratch_space.in_use = true;
            (self.scratch_space.slice.as_mut_ptr(), self.scratch_space.slice.len() as u32)
        } else {
            self.allocator.allocate_segment(minimum_size)
        }
    }

    fn pre_drop(&mut self, segment0_currently_allocated: u32) {
        let ptr = self.scratch_space.slice.as_mut_ptr();
        unsafe {
            ::std::ptr::write_bytes(ptr, 0u8, segment0_currently_allocated as usize);
        }
        self.scratch_space.in_use = false;
    }
}

<|endoftext|>


<commit_before>use goblin::archive::*;
use scroll::Pread;
use std::path::Path;
use std::fs::File;

#[test]
fn parse_file_header() {
    let file_header: [u8; SIZEOF_HEADER] = [0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38,
                                            0x32, 0x34, 0x34, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x60, 0x0a];
    let buffer = &file_header[..];
    match buffer.pread::<MemberHeader>(0) {
        Err(e) => panic!("could not read the buffer: {:?}", e),
        Ok(file_header2) => {
            let file_header = MemberHeader {
                identifier: [0x2f,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,],
                timestamp: [48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32],
                owner_id: [48, 32, 32, 32, 32, 32],
                group_id: [48, 32, 32, 32, 32, 32],
                mode: [48, 32, 32, 32, 32, 32, 32, 32],
                file_size: [56, 50, 52, 52, 32, 32, 32, 32, 32, 32],
                terminator: [96, 10] };
            assert_eq!(file_header, file_header2)
        }
    }
}

#[test]
fn parse_archive() {
    let crt1a: Vec<u8> = include!("../etc/crt1a.rs");
    const START: &str = "_start";
    match Archive::parse(&crt1a) {
        Ok(archive) => {
            assert_eq!(archive.member_of_symbol(START), Some("crt1.o"));
            if let Some(member) = archive.get("crt1.o") {
                assert_eq!(member.offset, 194);
                assert_eq!(member.size(), 1928)
            } else {
                panic!("could not get crt1.o");
            }
        },
        Err(err) => panic!("could not parse archive: {:?}", err),
    };
}

#[test]
fn parse_self() {
    use std::fs;
    use std::io::Read;
    let mut path = Path::new("target").join("debug").join("libgoblin.rlib");
    // https://github.com/m4b/goblin/issues/63
    if fs::metadata(&path).is_err() {
        path = Path::new("target").join("release").join("libgoblin.rlib");
    }
    let buffer = {
        let mut fd = File::open(path).expect("can open file; did you run cargo build first?");
        let mut v = Vec::new();
        fd.read_to_end(&mut v).expect("read file");
        v
    };

    let archive = Archive::parse(&buffer).expect("parse rlib");

    // check that the archive has a useful symbol table by counting the total number of symbols
    let symbol_count: usize = archive.summarize().into_iter()
        .map(|(_member_name, _member_index, ref symbols)| symbols.len())
        .sum();
    assert!(symbol_count > 500);

    let goblin_object_name = archive.members()
        .into_iter()
        .find(|member| {
            println!("member: {:?}", member);
            member.ends_with("goblin-archive.o")    // < 1.18
                || (member.starts_with("goblin") && member.ends_with("0.o")) // >= 1.18 && < 1.22
                || (member.starts_with("goblin") && member.ends_with("rust-cgu.o")) // = 1.22
                || (member.starts_with("goblin") && member.ends_with("rcgu.o")) // >= nightly 1.23
        })
        .expect("goblin-<hash>.0.o not found");

    let bytes = archive.extract(goblin_object_name, &buffer).expect("extract goblin object");
    match goblin::Object::parse(&bytes).expect("parse object") {
        goblin::Object::Elf(elf) => {
            assert!(elf.entry == 0);
        }
        goblin::Object::Mach(goblin::mach::Mach::Binary(macho)) => {
            assert_eq!(macho.header.filetype, goblin::mach::header::MH_OBJECT);
            assert_eq!(macho.entry, 0);
        }
        other => {
            panic!("unexpected Object::parse result: {:?}", other);
        }
    }
}
<commit_msg>Use env::current_exe to get build artifact path correctly<commit_after>use std::env;
use std::path::PathBuf;
use std::fs;

use goblin::archive::*;
use scroll::Pread;

#[test]
fn parse_file_header() {
    let file_header: [u8; SIZEOF_HEADER] = [0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38,
                                            0x32, 0x34, 0x34, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x60, 0x0a];
    let buffer = &file_header[..];
    match buffer.pread::<MemberHeader>(0) {
        Err(e) => panic!("could not read the buffer: {:?}", e),
        Ok(file_header2) => {
            let file_header = MemberHeader {
                identifier: [0x2f,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,],
                timestamp: [48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32],
                owner_id: [48, 32, 32, 32, 32, 32],
                group_id: [48, 32, 32, 32, 32, 32],
                mode: [48, 32, 32, 32, 32, 32, 32, 32],
                file_size: [56, 50, 52, 52, 32, 32, 32, 32, 32, 32],
                terminator: [96, 10] };
            assert_eq!(file_header, file_header2)
        }
    }
}

#[test]
fn parse_archive() {
    let crt1a: Vec<u8> = include!("../etc/crt1a.rs");
    const START: &str = "_start";
    match Archive::parse(&crt1a) {
        Ok(archive) => {
            assert_eq!(archive.member_of_symbol(START), Some("crt1.o"));
            if let Some(member) = archive.get("crt1.o") {
                assert_eq!(member.offset, 194);
                assert_eq!(member.size(), 1928)
            } else {
                panic!("could not get crt1.o");
            }
        },
        Err(err) => panic!("could not parse archive: {:?}", err),
    };
}

fn get_libgoblin_rlib() -> PathBuf {
    // this test lies in `target/<target-triple>/<profile>/deps/`
    let me = env::current_exe().unwrap();
    // back to `<profile>` folder
    let artifact_dir = me.ancestors().nth(2).unwrap();
    artifact_dir.join("libgoblin.rlib")
}

// Cannot run this on Windows because *.rlib type on Windows is unknown
#[cfg(not(windows))]
#[test]
fn parse_self() {
    let path = get_libgoblin_rlib();
    let buffer = fs::read(path).expect("run `cargo build` first?");

    let archive = Archive::parse(&buffer).expect("parse rlib");

    // check that the archive has a useful symbol table by counting the total number of symbols
    let symbol_count: usize = archive.summarize().into_iter()
        .map(|(_member_name, _member_index, ref symbols)| symbols.len())
        .sum();
    assert!(symbol_count > 500);

    let goblin_object_name = archive.members()
        .into_iter()
        .find(|member| {
            println!("member: {:?}", member);
            member.ends_with("goblin-archive.o")    // < 1.18
                || (member.starts_with("goblin") && member.ends_with("0.o")) // >= 1.18 && < 1.22
                || (member.starts_with("goblin") && member.ends_with("rust-cgu.o")) // = 1.22
                || (member.starts_with("goblin") && member.ends_with("rcgu.o")) // >= nightly 1.23
        })
        .expect("goblin-<hash>.0.o not found");

    let bytes = archive.extract(goblin_object_name, &buffer).expect("extract goblin object");
    match goblin::Object::parse(&bytes).expect("parse object") {
        goblin::Object::Elf(elf) => {
            assert!(elf.entry == 0);
        }
        goblin::Object::Mach(goblin::mach::Mach::Binary(macho)) => {
            assert_eq!(macho.header.filetype, goblin::mach::header::MH_OBJECT);
            assert_eq!(macho.entry, 0);
        }
        other => {
            panic!("unexpected Object::parse result: {:?}", other);
        }
    }
}
<|endoftext|>


<commit_before>extern crate bencode;

use self::bencode::{FromBencode, Bencode, NumFromBencodeError, StringFromBencodeError};
use self::bencode::util::ByteString;
use std::fs::File;
use std::io::Read;
use std::{convert, io};

macro_rules! get_field_with_default {
    ($m:expr, $field:expr, $default:expr) => (
        match $m.get(&ByteString::from_str($field)) {
            Some(a) => try!(FromBencode::from_bencode(a)),
            None => $default
        };
    )
}

macro_rules! get_field {
    ($m:expr, $field:expr) => (
        get_field_with_default!($m, $field, return Err(MetainfoError::DoesntContain($field)))
    )
}

#[derive(PartialEq, Debug)]
struct Metainfo {
    announce: String,
    info: Info,
    created_by: String,
}

impl FromBencode for Metainfo {
    type Err = MetainfoError;

    fn from_bencode(bencode: &bencode::Bencode) -> Result<Metainfo, MetainfoError> {
        match bencode {
            &Bencode::Dict(ref m) => {
                let metainfo = Metainfo{
                    announce: get_field!(m, "announce"),
                    info: get_field!(m, "info"),
                    created_by: get_field_with_default!(m, "created by", "".to_string()),
                };
                Ok(metainfo)
            }
            _ => Err(MetainfoError::NotADict)
        }
    }
}

#[derive(PartialEq, Debug)]
struct Info {
    piece_length: u32,
    name: String,
}

impl FromBencode for Info {
    type Err = MetainfoError;

    fn from_bencode(bencode: &bencode::Bencode) -> Result<Info, MetainfoError> {
        match bencode {
            &Bencode::Dict(ref m) => {
                let info = Info{
                    piece_length: get_field!(m, "piece length"),
                    name: get_field!(m, "name"),
                };
                Ok(info)
            }
            _ => Err(MetainfoError::NotADict)
        }
    }
}

#[derive(Debug)]
enum MetainfoError {
    IoError(io::Error),
    DecodingError(bencode::streaming::Error),
    NotADict,
    DoesntContain(&'static str),
    NotANumber(NumFromBencodeError),
    NotAString(StringFromBencodeError),
}

impl convert::From<io::Error> for MetainfoError {
    fn from(err: io::Error) -> MetainfoError {
        MetainfoError::IoError(err)
    }
}

impl convert::From<bencode::streaming::Error> for MetainfoError {
    fn from(err: bencode::streaming::Error) -> MetainfoError {
        MetainfoError::DecodingError(err)
    }
}

impl convert::From<NumFromBencodeError> for MetainfoError {
    fn from(err: NumFromBencodeError) -> MetainfoError {
        MetainfoError::NotANumber(err)
    }
}

impl convert::From<StringFromBencodeError> for MetainfoError {
    fn from(err: StringFromBencodeError) -> MetainfoError {
        MetainfoError::NotAString(err)
    }
}

pub fn run() {
    let result = parse_torrent_file("test_data/flagfromserver.torrent");
    match result {
        Ok(s)  => println!("Yay, it worked: {:?}", s),
        Err(e) => println!("Oops, it failed: {:?}", e)
    }
}

fn parse_torrent_file(filename: &str) -> Result<Metainfo, MetainfoError> {
    // read the torrent file into a byte vector
    let mut f = try!(File::open(filename));
    let mut v = Vec::new();
    try!(f.read_to_end(&mut v));

    // decode the byte vector into a struct
    let bencode = try!(bencode::from_vec(v));
    let result = try!(FromBencode::from_bencode(&bencode));

    Ok(result)
}
<commit_msg>Added pieces and length decoding to Info.<commit_after>extern crate bencode;

use self::bencode::{FromBencode, Bencode, NumFromBencodeError, StringFromBencodeError};
use self::bencode::util::ByteString;
use std::fs::File;
use std::io::Read;
use std::{convert, io};

macro_rules! get_field_with_default {
    ($m:expr, $field:expr, $default:expr) => (
        match $m.get(&ByteString::from_str($field)) {
            Some(a) => try!(FromBencode::from_bencode(a)),
            None => $default
        };
    )
}

macro_rules! get_field {
    ($m:expr, $field:expr) => (
        get_field_with_default!($m, $field, return Err(MetainfoError::DoesntContain($field)))
    )
}

#[derive(PartialEq, Debug)]
struct Metainfo {
    announce: String,
    info: Info,
    created_by: String,
}

impl FromBencode for Metainfo {
    type Err = MetainfoError;

    fn from_bencode(bencode: &bencode::Bencode) -> Result<Metainfo, MetainfoError> {
        match bencode {
            &Bencode::Dict(ref m) => {
                let metainfo = Metainfo{
                    announce: get_field!(m, "announce"),
                    info: get_field!(m, "info"),
                    created_by: get_field_with_default!(m, "created by", "".to_string()),
                };
                Ok(metainfo)
            }
            _ => Err(MetainfoError::NotADict)
        }
    }
}

#[derive(PartialEq, Debug)]
struct Info {
    piece_length: u32,
    pieces: Vec<u8>,
    name: String,
    length: u32,
}

impl FromBencode for Info {
    type Err = MetainfoError;

    fn from_bencode(bencode: &bencode::Bencode) -> Result<Info, MetainfoError> {
        match bencode {
            &Bencode::Dict(ref m) => {
                let pieces = match m.get(&ByteString::from_str("pieces")) {
                    Some(a) => {
                        match a {
                            &Bencode::ByteString(ref v) => v.clone(),
                            _ => return Err(MetainfoError::NotAByteString)
                        }
                    },
                    None => return Err(MetainfoError::DoesntContain("pieces"))
                };

                let info = Info{
                    piece_length: get_field!(m, "piece length"),
                    pieces: pieces,
                    name: get_field!(m, "name"),
                    length: get_field!(m, "length"),
                };
                Ok(info)
            }
            _ => Err(MetainfoError::NotADict)
        }
    }
}

#[derive(Debug)]
enum MetainfoError {
    IoError(io::Error),
    DecodingError(bencode::streaming::Error),
    NotADict,
    NotAByteString,
    DoesntContain(&'static str),
    NotANumber(NumFromBencodeError),
    NotAString(StringFromBencodeError),
}

impl convert::From<io::Error> for MetainfoError {
    fn from(err: io::Error) -> MetainfoError {
        MetainfoError::IoError(err)
    }
}

impl convert::From<bencode::streaming::Error> for MetainfoError {
    fn from(err: bencode::streaming::Error) -> MetainfoError {
        MetainfoError::DecodingError(err)
    }
}

impl convert::From<NumFromBencodeError> for MetainfoError {
    fn from(err: NumFromBencodeError) -> MetainfoError {
        MetainfoError::NotANumber(err)
    }
}

impl convert::From<StringFromBencodeError> for MetainfoError {
    fn from(err: StringFromBencodeError) -> MetainfoError {
        MetainfoError::NotAString(err)
    }
}

pub fn run() {
    let result = parse_torrent_file("test_data/flagfromserver.torrent");
    match result {
        Ok(s)  => println!("Yay, it worked: {:?}", s),
        Err(e) => println!("Oops, it failed: {:?}", e)
    }
}

fn parse_torrent_file(filename: &str) -> Result<Metainfo, MetainfoError> {
    // read the torrent file into a byte vector
    let mut f = try!(File::open(filename));
    let mut v = Vec::new();
    try!(f.read_to_end(&mut v));

    // decode the byte vector into a struct
    let bencode = try!(bencode::from_vec(v));
    let result = try!(FromBencode::from_bencode(&bencode));

    Ok(result)
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is natural number, position is (a, b).
/// Represents all directional pairs that has not same element for `a` and `b`.
pub struct NeqPair<T = Data>(PhantomData<T>);

impl<T> Construct for NeqPair<T> {
    fn new() -> NeqPair<T> { NeqPair(PhantomData) }
}

impl Count<usize> for NeqPair<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize { dim * (dim - 1) }
}

impl<T, U> Count<U> for NeqPair<Of<T>>
    where
        T: Construct + Count<U, N = usize>
{
    type N = usize;
    fn count(&self, dim: &U) -> usize {
        let of: T = Construct::new();
        let data: NeqPair<Data> = Construct::new();
        data.count(&of.count(dim))
    }
}

impl Zero<usize, (usize, usize)> for NeqPair<Data> {
    fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) }
}

impl<T, U, V>
Zero<U, (V, V)> for NeqPair<Of<T>>
    where
        T: Construct + Zero<U, V>
{
    fn zero(&self, dim: &U) -> (V, V) {
        let of: T = Construct::new();
        (of.zero(dim), of.zero(dim))
    }
}

impl ToIndex<usize, (usize, usize)>
for NeqPair<Data> {
    fn to_index(&self, dim: &usize, &(a, b): &(usize, usize)) -> usize {
        use Pair;

        let pair: Pair<Data> = Construct::new();
        if a < b {
            pair.to_index(dim, &(a, b)) * 2
        } else {
            pair.to_index(dim, &(b, a)) * 2 + 1
        }
    }
}

impl<T, U, V>
ToIndex<U, (V, V)> for NeqPair<Of<T>>
    where
        T: Construct + ToIndex<U, V> + Count<U, N = usize>
{
    fn to_index(
        &self,
        dim: &U,
        &(ref min, ref max): &(V, V)
    ) -> usize {
        let of: T = Construct::new();
        let data: NeqPair<Data> = Construct::new();
        let min = of.to_index(dim, min);
        let max = of.to_index(dim, max);
        data.to_index(&self.count(dim), &(min, max))
    }
}

impl ToPos<usize, (usize, usize)> for NeqPair<Data> {
    fn to_pos(&self, dim: &usize, index: usize, pos: &mut (usize, usize)) {
        use Pair;

        let pair: Pair<Data> = Construct::new();
        if index % 2 == 0 {
            pair.to_pos(dim, index / 2, pos);
        } else {
            pair.to_pos(dim, (index - 1) / 2, pos);
            let tmp = pos.1;
            pos.1 = pos.0;
            pos.0 = tmp;
        }
    }
}

impl<T, U, V>
ToPos<U, (V, V)> for NeqPair<Of<T>>
    where
        T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        &mut (ref mut min, ref mut max): &mut (V, V)
    ) {
        let of: T = Construct::new();
        let data: NeqPair<Data> = Construct::new();
        let count = of.count(dim);
        let mut pair = (0, 0);
        data.to_pos(&count, index, &mut pair);
        let (pair_min, pair_max) = pair;
        of.to_pos(dim, pair_min, min);
        of.to_pos(dim, pair_max, max);
    }
}

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

    #[test]
    fn features() {
        is_complete::<NeqPair, usize, (usize, usize)>();
        is_complete::<NeqPair<Of<NeqPair>>, usize,
            ((usize, usize), (usize, usize))>();
    }

    #[test]
    fn data() {
        let x: NeqPair = Construct::new();
        let ref dim = 4;
        assert_eq!(x.count(dim), 12);
        assert_eq!(x.to_index(dim, &(0, 1)), 0);
        assert_eq!(x.to_index(dim, &(1, 0)), 1);
        assert_eq!(x.to_index(dim, &(0, 2)), 2);
        assert_eq!(x.to_index(dim, &(2, 0)), 3);
        assert_eq!(x.to_index(dim, &(1, 2)), 4);
        assert_eq!(x.to_index(dim, &(2, 1)), 5);
        assert_eq!(x.to_index(dim, &(0, 3)), 6);
        let mut new_pos = (0, 0);
        x.to_pos(dim, 6, &mut new_pos);
        assert_eq!(new_pos, (0, 3));
        x.to_pos(dim, 5, &mut new_pos);
        assert_eq!(new_pos, (2, 1));
    }

    #[test]
    fn of() {
        let x: NeqPair<Of<DimensionN>> = Construct::new();
        let ref dim = vec![2, 2];
        assert_eq!(x.count(dim), 12);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 0])), 0);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![0, 1])), 2);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![0, 1])), 4);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 1])), 6);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![1, 1])), 8);
        assert_eq!(x.to_index(dim, &(vec![0, 1], vec![1, 1])), 10);
        let mut pos = (Vec::new(), Vec::new());
        for i in 0..6 {
            x.to_pos(dim, i, &mut pos);
            // println!("{} {}", &min[], &max[]);
        }
        x.to_pos(dim, 10, &mut pos);
        assert_eq!(&pos.0, &[0, 1]);
        assert_eq!(&pos.1, &[1, 1]);
    }
}
<commit_msg>Impl `Count<BigUint>` for `NeqPair`<commit_after>use std::marker::PhantomData;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is natural number, position is (a, b).
/// Represents all directional pairs that has not same element for `a` and `b`.
pub struct NeqPair<T = Data>(PhantomData<T>);

impl<T> Construct for NeqPair<T> {
    fn new() -> NeqPair<T> { NeqPair(PhantomData) }
}

impl Count<usize> for NeqPair<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize { dim * (dim - 1) }
}

impl Count<BigUint> for NeqPair<Data> {
    type N = BigUint;
    fn count(&self, dim: &BigUint) -> BigUint {
        let _1: BigUint = 1usize.into();
        dim * (dim - _1)
    }
}

impl<T, U> Count<U> for NeqPair<Of<T>>
    where
        T: Construct + Count<U>,
        NeqPair: Count<<T as Count<U>>::N, N = <T as Count<U>>::N>
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &U) -> Self::N {
        let of: T = Construct::new();
        let data: NeqPair<Data> = Construct::new();
        data.count(&of.count(dim))
    }
}

impl Zero<usize, (usize, usize)> for NeqPair<Data> {
    fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) }
}

impl<T, U, V>
Zero<U, (V, V)> for NeqPair<Of<T>>
    where
        T: Construct + Zero<U, V>
{
    fn zero(&self, dim: &U) -> (V, V) {
        let of: T = Construct::new();
        (of.zero(dim), of.zero(dim))
    }
}

impl ToIndex<usize, (usize, usize)>
for NeqPair<Data> {
    fn to_index(&self, dim: &usize, &(a, b): &(usize, usize)) -> usize {
        use Pair;

        let pair: Pair<Data> = Construct::new();
        if a < b {
            pair.to_index(dim, &(a, b)) * 2
        } else {
            pair.to_index(dim, &(b, a)) * 2 + 1
        }
    }
}

impl<T, U, V>
ToIndex<U, (V, V)> for NeqPair<Of<T>>
    where
        T: Construct + ToIndex<U, V> + Count<U, N = usize>
{
    fn to_index(
        &self,
        dim: &U,
        &(ref min, ref max): &(V, V)
    ) -> usize {
        let of: T = Construct::new();
        let data: NeqPair<Data> = Construct::new();
        let min = of.to_index(dim, min);
        let max = of.to_index(dim, max);
        data.to_index(&self.count(dim), &(min, max))
    }
}

impl ToPos<usize, (usize, usize)> for NeqPair<Data> {
    fn to_pos(&self, dim: &usize, index: usize, pos: &mut (usize, usize)) {
        use Pair;

        let pair: Pair<Data> = Construct::new();
        if index % 2 == 0 {
            pair.to_pos(dim, index / 2, pos);
        } else {
            pair.to_pos(dim, (index - 1) / 2, pos);
            let tmp = pos.1;
            pos.1 = pos.0;
            pos.0 = tmp;
        }
    }
}

impl<T, U, V>
ToPos<U, (V, V)> for NeqPair<Of<T>>
    where
        T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        &mut (ref mut min, ref mut max): &mut (V, V)
    ) {
        let of: T = Construct::new();
        let data: NeqPair<Data> = Construct::new();
        let count = of.count(dim);
        let mut pair = (0, 0);
        data.to_pos(&count, index, &mut pair);
        let (pair_min, pair_max) = pair;
        of.to_pos(dim, pair_min, min);
        of.to_pos(dim, pair_max, max);
    }
}

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

    #[test]
    fn features() {
        is_complete::<NeqPair, usize, (usize, usize)>();
        is_complete::<NeqPair<Of<NeqPair>>, usize,
            ((usize, usize), (usize, usize))>();
    }

    #[test]
    fn data() {
        let x: NeqPair = Construct::new();
        let ref dim = 4;
        assert_eq!(x.count(dim), 12);
        assert_eq!(x.to_index(dim, &(0, 1)), 0);
        assert_eq!(x.to_index(dim, &(1, 0)), 1);
        assert_eq!(x.to_index(dim, &(0, 2)), 2);
        assert_eq!(x.to_index(dim, &(2, 0)), 3);
        assert_eq!(x.to_index(dim, &(1, 2)), 4);
        assert_eq!(x.to_index(dim, &(2, 1)), 5);
        assert_eq!(x.to_index(dim, &(0, 3)), 6);
        let mut new_pos = (0, 0);
        x.to_pos(dim, 6, &mut new_pos);
        assert_eq!(new_pos, (0, 3));
        x.to_pos(dim, 5, &mut new_pos);
        assert_eq!(new_pos, (2, 1));
    }

    #[test]
    fn of() {
        let x: NeqPair<Of<DimensionN>> = Construct::new();
        let ref dim = vec![2, 2];
        assert_eq!(x.count(dim), 12);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 0])), 0);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![0, 1])), 2);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![0, 1])), 4);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 1])), 6);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![1, 1])), 8);
        assert_eq!(x.to_index(dim, &(vec![0, 1], vec![1, 1])), 10);
        let mut pos = (Vec::new(), Vec::new());
        for i in 0..6 {
            x.to_pos(dim, i, &mut pos);
            // println!("{} {}", &min[], &max[]);
        }
        x.to_pos(dim, 10, &mut pos);
        assert_eq!(&pos.0, &[0, 1]);
        assert_eq!(&pos.1, &[1, 1]);
    }
}
<|endoftext|>


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

extern crate rocksdb;
extern crate libc;

mod util;

use libc::{size_t};

use rocksdb::{DB, DBVector, Error, IteratorMode, Options, WriteBatch};
use util::DBPath;

#[test]
fn test_db_vector() {
    use std::mem;
    let len: size_t = 4;
    let data: *mut u8 = unsafe { mem::transmute(libc::calloc(len, mem::size_of::<u8>())) };
    let v = unsafe { DBVector::from_c(data, len) };
    let ctrl = [0u8, 0, 0, 0];
    assert_eq!(&*v, &ctrl[..]);
}

#[test]
fn external() {
    let path = DBPath::new("_rust_rocksdb_externaltest");

    {
        let db = DB::open_default(&path).unwrap();

        let p = db.put(b"k1", b"v1111");
        assert!(p.is_ok());

        let r: Result<Option<DBVector>, Error> = db.get(b"k1");

        assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
        assert!(db.delete(b"k1").is_ok());
        assert!(db.get(b"k1").unwrap().is_none());
    }
}

#[test]
fn errors_do_stuff() {
    let path = DBPath::new("_rust_rocksdb_error");
    let _db = DB::open_default(&path).unwrap();
    let opts = Options::default();
    // The DB will still be open when we try to destroy it and the lock should fail.
    match DB::destroy(&opts, &path) {
        Err(s) => {
            let message = s.to_string();
            assert!(message.find("IO error:").is_some());
            assert!(message.find("_rust_rocksdb_error").is_some());
            assert!(message.find("/LOCK:").is_some());
        }
        Ok(_) => panic!("should fail"),
    }
}

#[test]
fn writebatch_works() {
    let path = DBPath::new("_rust_rocksdb_writebacktest");
    {
        let db = DB::open_default(&path).unwrap();
        {
            // test put
            let mut batch = WriteBatch::default();
            assert!(db.get(b"k1").unwrap().is_none());
            assert_eq!(batch.len(), 0);
            assert!(batch.is_empty());
            let _ = batch.put(b"k1", b"v1111");
            assert_eq!(batch.len(), 1);
            assert!(!batch.is_empty());
            assert!(db.get(b"k1").unwrap().is_none());
            let p = db.write(batch);
            assert!(p.is_ok());
            let r: Result<Option<DBVector>, Error> = db.get(b"k1");
            assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
        }
        {
            // test delete
            let mut batch = WriteBatch::default();
            let _ = batch.delete(b"k1");
            assert_eq!(batch.len(), 1);
            assert!(!batch.is_empty());
            let p = db.write(batch);
            assert!(p.is_ok());
            assert!(db.get(b"k1").unwrap().is_none());
        }
        {
            // test size_in_bytes
            let mut batch = WriteBatch::default();
            let before = batch.size_in_bytes();
            let _ = batch.put(b"k1", b"v1234567890");
            let after = batch.size_in_bytes();
            assert!(before + 10 <= after);
        }
    }
}

#[test]
fn iterator_test() {
    let path = DBPath::new("_rust_rocksdb_iteratortest");
    {
        let data = [(b"k1", b"v1111"), (b"k2", b"v2222"), (b"k3", b"v3333")];
        let db = DB::open_default(&path).unwrap();

        for (key, value) in &data {
            assert!(db.put(key, value).is_ok());
        }

        let iter = db.iterator(IteratorMode::Start);

        for (idx, (db_key, db_value)) in iter.enumerate() {
            let (key, value) = data[idx];
            assert_eq!((&key[..], &value[..]), (db_key.as_ref(), db_value.as_ref()));
        }
    }
}

#[test]
fn snapshot_test() {
    let path = DBPath::new("_rust_rocksdb_snapshottest");
    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let snap = db.snapshot();
        let r: Result<Option<DBVector>, Error> = snap.get(b"k1");
        assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");

        assert!(db.put(b"k2", b"v2222").is_ok());

        assert!(db.get(b"k2").unwrap().is_some());
        assert!(snap.get(b"k2").unwrap().is_none());
    }
}

#[test]
fn set_option_test() {
    let path = DBPath::new("_rust_rocksdb_set_optionstest");
    {
        let db = DB::open_default(&path).unwrap();
        // set an option to valid values
        assert!(db
            .set_options(&[("disable_auto_compactions", "true")])
            .is_ok());
        assert!(db
            .set_options(&[("disable_auto_compactions", "false")])
            .is_ok());
        // invalid names/values should result in an error
        assert!(db
            .set_options(&[("disable_auto_compactions", "INVALID_VALUE")])
            .is_err());
        assert!(db
            .set_options(&[("INVALID_NAME", "INVALID_VALUE")])
            .is_err());
        // option names/values must not contain NULLs
        assert!(db
            .set_options(&[("disable_auto_compactions", "true\0")])
            .is_err());
        assert!(db
            .set_options(&[("disable_auto_compactions\0", "true")])
            .is_err());
        // empty options are not allowed
        assert!(db.set_options(&[]).is_err());
        // multiple options can be set in a single API call
        let multiple_options = [
            ("paranoid_file_checks", "true"),
            ("report_bg_io_stats", "true"),
        ];
        db.set_options(&multiple_options).unwrap();
    }
}
<commit_msg>Removing unnecessary let bindings in tests...<commit_after>// Copyright 2019 Tyler Neely
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate rocksdb;
extern crate libc;

mod util;

use libc::{size_t};

use rocksdb::{DB, DBVector, Error, IteratorMode, Options, WriteBatch};
use util::DBPath;

#[test]
fn test_db_vector() {
    use std::mem;
    let len: size_t = 4;
    let data: *mut u8 = unsafe { mem::transmute(libc::calloc(len, mem::size_of::<u8>())) };
    let v = unsafe { DBVector::from_c(data, len) };
    let ctrl = [0u8, 0, 0, 0];
    assert_eq!(&*v, &ctrl[..]);
}

#[test]
fn external() {
    let path = DBPath::new("_rust_rocksdb_externaltest");

    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let r: Result<Option<DBVector>, Error> = db.get(b"k1");

        assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
        assert!(db.delete(b"k1").is_ok());
        assert!(db.get(b"k1").unwrap().is_none());
    }
}

#[test]
fn errors_do_stuff() {
    let path = DBPath::new("_rust_rocksdb_error");
    let _db = DB::open_default(&path).unwrap();
    let opts = Options::default();
    // The DB will still be open when we try to destroy it and the lock should fail.
    match DB::destroy(&opts, &path) {
        Err(s) => {
            let message = s.to_string();
            assert!(message.find("IO error:").is_some());
            assert!(message.find("_rust_rocksdb_error").is_some());
            assert!(message.find("/LOCK:").is_some());
        }
        Ok(_) => panic!("should fail"),
    }
}

#[test]
fn writebatch_works() {
    let path = DBPath::new("_rust_rocksdb_writebacktest");
    {
        let db = DB::open_default(&path).unwrap();
        {
            // test put
            let mut batch = WriteBatch::default();
            assert!(db.get(b"k1").unwrap().is_none());
            assert_eq!(batch.len(), 0);
            assert!(batch.is_empty());
            let _ = batch.put(b"k1", b"v1111");
            assert_eq!(batch.len(), 1);
            assert!(!batch.is_empty());
            assert!(db.get(b"k1").unwrap().is_none());
            assert!(db.write(batch).is_ok());
            let r: Result<Option<DBVector>, Error> = db.get(b"k1");
            assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
        }
        {
            // test delete
            let mut batch = WriteBatch::default();
            let _ = batch.delete(b"k1");
            assert_eq!(batch.len(), 1);
            assert!(!batch.is_empty());
            assert!(db.write(batch).is_ok());
            assert!(db.get(b"k1").unwrap().is_none());
        }
        {
            // test size_in_bytes
            let mut batch = WriteBatch::default();
            let before = batch.size_in_bytes();
            let _ = batch.put(b"k1", b"v1234567890");
            let after = batch.size_in_bytes();
            assert!(before + 10 <= after);
        }
    }
}

#[test]
fn iterator_test() {
    let path = DBPath::new("_rust_rocksdb_iteratortest");
    {
        let data = [(b"k1", b"v1111"), (b"k2", b"v2222"), (b"k3", b"v3333")];
        let db = DB::open_default(&path).unwrap();

        for (key, value) in &data {
            assert!(db.put(key, value).is_ok());
        }

        let iter = db.iterator(IteratorMode::Start);

        for (idx, (db_key, db_value)) in iter.enumerate() {
            let (key, value) = data[idx];
            assert_eq!((&key[..], &value[..]), (db_key.as_ref(), db_value.as_ref()));
        }
    }
}

#[test]
fn snapshot_test() {
    let path = DBPath::new("_rust_rocksdb_snapshottest");
    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let snap = db.snapshot();
        assert!(snap.get(b"k1").unwrap().unwrap().to_utf8().unwrap() == "v1111");

        assert!(db.put(b"k2", b"v2222").is_ok());

        assert!(db.get(b"k2").unwrap().is_some());
        assert!(snap.get(b"k2").unwrap().is_none());
    }
}

#[test]
fn set_option_test() {
    let path = DBPath::new("_rust_rocksdb_set_optionstest");
    {
        let db = DB::open_default(&path).unwrap();
        // set an option to valid values
        assert!(db
            .set_options(&[("disable_auto_compactions", "true")])
            .is_ok());
        assert!(db
            .set_options(&[("disable_auto_compactions", "false")])
            .is_ok());
        // invalid names/values should result in an error
        assert!(db
            .set_options(&[("disable_auto_compactions", "INVALID_VALUE")])
            .is_err());
        assert!(db
            .set_options(&[("INVALID_NAME", "INVALID_VALUE")])
            .is_err());
        // option names/values must not contain NULLs
        assert!(db
            .set_options(&[("disable_auto_compactions", "true\0")])
            .is_err());
        assert!(db
            .set_options(&[("disable_auto_compactions\0", "true")])
            .is_err());
        // empty options are not allowed
        assert!(db.set_options(&[]).is_err());
        // multiple options can be set in a single API call
        let multiple_options = [
            ("paranoid_file_checks", "true"),
            ("report_bg_io_stats", "true"),
        ];
        db.set_options(&multiple_options).unwrap();
    }
}
<|endoftext|>


<commit_before>// ---------------------------------------------------------------------------------------
// Ruthenium, an ack-like searcher, (c) 2015 Georg Brandl.
// Licensed under the MIT license.
// ---------------------------------------------------------------------------------------

use std::usize;

use clap::{App, AppSettings, Arg};

#[derive(Clone)]
pub struct Colors {
    pub reset: String,
    pub path: String,
    pub lineno: String,
    pub span: String,
    pub punct: String,
}

impl Colors {
    fn empty() -> Colors {
        Colors {
            reset: "".into(),
            path: "".into(),
            lineno: "".into(),
            span: "".into(),
            punct: "".into(),
        }
    }

    fn from(path: &str, lineno: &str, span: &str, punct: &str) -> Colors {
        Colors {
            reset: "\x1b[0m".into(),
            path: format!("\x1b[{}m", path),
            lineno: format!("\x1b[{}m", lineno),
            span: format!("\x1b[{}m", span),
            punct: format!("\x1b[{}m", punct),
        }
    }
}

#[derive(Clone)]
pub enum Casing {
    Default,
    Smart,
    Insensitive,
}

#[derive(Clone)]
pub struct Opts {
    // file related options
    pub path: String,
    pub depth: usize,
    pub follow_links: bool,
    pub do_binaries: bool,
    pub do_hidden: bool,
    // ignore file related options
    pub check_ignores: bool,
    // pattern related options
    pub pattern: String,
    pub casing: Casing,
    pub literal: bool,
    // display related options
    pub colors: Option<Colors>,
    pub only_files: Option<bool>,
    pub only_count: bool,
    pub show_break: bool,
    pub show_heading: bool,
    pub ackmate_format: bool,
    pub vimgrep_format: bool,
    pub max_count: usize,
    pub before: usize,
    pub after: usize,
}

macro_rules! flag {
    ($n:ident -$f:ident) => {
        Arg::with_name(stringify!($n)).short(stringify!($f))
    };
    ($n:ident -$f:ident --$l:expr) => {
        Arg::with_name(stringify!($n)).short(stringify!($f)).long($l)
    };
    ($n:ident / --$l:expr) => {
        Arg::with_name(stringify!($n)).long($l)
    };
}

impl Opts {
    pub fn from_cmdline() -> Opts {
        let version = format!("v{}", crate_version!());
        let app = App::new("Ruthenium")
            .version(&version)
            .usage("ru [options] PATTERN [PATH]")
            .about("Recursively search for a pattern, like ack")
            .setting(AppSettings::UnifiedHelpMessage)
            .setting(AppSettings::ArgRequiredElseHelp)
            .arg(Arg::with_name("pattern").required(true).index(1))
            .arg(Arg::with_name("path").index(2))
            .arg(flag!(all -a --"all-types"))
            .arg(flag!(depth / --"depth").takes_value(true))
            .arg(flag!(literal -Q --"literal"))
            .arg(flag!(fixedstrings -F --"fixed-strings"))
            .arg(flag!(alltext -t --"all-text").conflicts_with("all"))
            .arg(flag!(unrestricted -u --"unrestricted").conflicts_with("all"))
            .arg(flag!(searchbinary / --"search-binary"))
            .arg(flag!(searchhidden / --"hidden"))
            .arg(flag!(fileswith -l --"files-with-matches"))
            .arg(flag!(fileswithout -L --"files-without-matches").conflicts_with("fileswith"))
            .arg(flag!(count -c --"count").conflicts_with("fileswith"))
            .arg(flag!(follow -f --"follow"))
            .arg(flag!(nofollow / --"nofollow").conflicts_with("follow"))
            .arg(flag!(nocolor / --"nocolor"))
            .arg(flag!(colorlineno / --"color-line-number").takes_value(true))
            .arg(flag!(colorspan / --"color-match").takes_value(true))
            .arg(flag!(colorpath / --"color-path").takes_value(true))
            .arg(flag!(colorpunct / --"color-punct").takes_value(true))
            .arg(flag!(casesens -s --"case-sensitive").conflicts_with("caseinsens"))
            .arg(flag!(casesmart -S --"smart-case").conflicts_with("casesens"))
            .arg(flag!(caseinsens -i --"ignore-case").conflicts_with("casesmart"))
            .arg(flag!(group / --"group"))
            .arg(flag!(nogroup / --"nogroup").conflicts_with("gorup"))
            .arg(flag!(heading -H --"heading"))
            .arg(flag!(noheading / --"noheading").conflicts_with("heading"))
            .arg(flag!(break / --"break"))
            .arg(flag!(nobreak / --"nobreak").conflicts_with("break"))
            .arg(flag!(ackmate / --"ackmate"))
            .arg(flag!(vimgrep / --"vimgrep"))
            .arg(flag!(maxcount -m --"max-count").takes_value(true))
            .arg(flag!(before -B --"before").takes_value(true))
            .arg(flag!(after -A --"after").takes_value(true))
            .arg(flag!(context -C --"context").takes_value(true))
            ;
        let m = app.get_matches();

        let depth = m.value_of("depth").and_then(|v| v.parse::<usize>().ok())
                                       .map(|v| v + 1) // 0 == immediate children
                                       .unwrap_or(usize::MAX);

        let mut binaries = m.is_present("searchbinary");
        let mut hidden = m.is_present("searchhidden");
        let mut ignores = true;
        if m.is_present("all") {
            binaries = true;
            ignores = false;
        } else if m.is_present("alltext") {
            ignores = false;
        } else if m.is_present("unrestricted") {
            binaries = true;
            hidden = true;
            ignores = false;
        }

        let mut casing = Casing::Smart;
        if m.is_present("caseinsens") {
            casing = Casing::Insensitive;
        } else if m.is_present("casesens") {
            casing = Casing::Default;
        }
        let mut literal = m.is_present("literal");
        if m.is_present("fixedstrings") {
            literal = true;
        }

        let colors = if m.is_present("nocolor") {
            Colors::empty()
        } else {
            Colors::from(
                m.value_of("colorpath").unwrap_or("35"),
                m.value_of("colorlineno").unwrap_or("32"),
                m.value_of("colorspan").unwrap_or("4"),
                m.value_of("colorpunct").unwrap_or("36"),
            )
        };
        let mut heading = true;
        let mut showbreak = true;
        if m.is_present("noheading") {
            heading = false;
        }
        if m.is_present("nobreak") {
            showbreak = false;
        }
        if m.is_present("nogroup") {
            heading = false;
            showbreak = false;
        }
        let maxcount = m.value_of("maxcount").and_then(|v| v.parse().ok())
                                             .unwrap_or(usize::MAX);
        let mut before = m.value_of("before").and_then(|v| v.parse().ok())
                                             .unwrap_or(0);
        let mut after = m.value_of("after").and_then(|v| v.parse().ok())
                                           .unwrap_or(0);
        if m.is_present("context") {
            before = m.value_of("context").unwrap().parse().ok().unwrap_or(0);
            after = before;
        }

        Opts {
            // file related
            path: m.value_of("path").unwrap_or(".").into(),
            depth: depth,
            follow_links: m.is_present("follow"),
            do_binaries: binaries,
            do_hidden: hidden,
            // ignore file related
            check_ignores: ignores,
            // pattern related
            pattern: m.value_of("pattern").unwrap().into(),
            casing: casing,
            literal: literal,
            // display related
            colors: Some(colors),
            only_files: if m.is_present("fileswith") {
                Some(true)
            } else if m.is_present("fileswithout") {
                Some(false)
            } else { None },
            only_count: m.is_present("count"),
            show_break: showbreak,
            show_heading: heading,
            ackmate_format: m.is_present("ackmate"),
            vimgrep_format: m.is_present("vimgrep"),
            max_count: maxcount,
            before: before,
            after: after,
        }
    }
}
<commit_msg>Follow links by default.<commit_after>// ---------------------------------------------------------------------------------------
// Ruthenium, an ack-like searcher, (c) 2015 Georg Brandl.
// Licensed under the MIT license.
// ---------------------------------------------------------------------------------------

use std::usize;

use clap::{App, AppSettings, Arg};

#[derive(Clone)]
pub struct Colors {
    pub reset: String,
    pub path: String,
    pub lineno: String,
    pub span: String,
    pub punct: String,
}

impl Colors {
    fn empty() -> Colors {
        Colors {
            reset: "".into(),
            path: "".into(),
            lineno: "".into(),
            span: "".into(),
            punct: "".into(),
        }
    }

    fn from(path: &str, lineno: &str, span: &str, punct: &str) -> Colors {
        Colors {
            reset: "\x1b[0m".into(),
            path: format!("\x1b[{}m", path),
            lineno: format!("\x1b[{}m", lineno),
            span: format!("\x1b[{}m", span),
            punct: format!("\x1b[{}m", punct),
        }
    }
}

#[derive(Clone)]
pub enum Casing {
    Default,
    Smart,
    Insensitive,
}

#[derive(Clone)]
pub struct Opts {
    // file related options
    pub path: String,
    pub depth: usize,
    pub follow_links: bool,
    pub do_binaries: bool,
    pub do_hidden: bool,
    // ignore file related options
    pub check_ignores: bool,
    // pattern related options
    pub pattern: String,
    pub casing: Casing,
    pub literal: bool,
    // display related options
    pub colors: Option<Colors>,
    pub only_files: Option<bool>,
    pub only_count: bool,
    pub show_break: bool,
    pub show_heading: bool,
    pub ackmate_format: bool,
    pub vimgrep_format: bool,
    pub max_count: usize,
    pub before: usize,
    pub after: usize,
}

macro_rules! flag {
    ($n:ident -$f:ident) => {
        Arg::with_name(stringify!($n)).short(stringify!($f))
    };
    ($n:ident -$f:ident --$l:expr) => {
        Arg::with_name(stringify!($n)).short(stringify!($f)).long($l)
    };
    ($n:ident / --$l:expr) => {
        Arg::with_name(stringify!($n)).long($l)
    };
}

impl Opts {
    pub fn from_cmdline() -> Opts {
        let version = format!("v{}", crate_version!());
        let app = App::new("Ruthenium")
            .version(&version)
            .usage("ru [options] PATTERN [PATH]")
            .about("Recursively search for a pattern, like ack")
            .setting(AppSettings::UnifiedHelpMessage)
            .setting(AppSettings::ArgRequiredElseHelp)
            .arg(Arg::with_name("pattern").required(true).index(1))
            .arg(Arg::with_name("path").index(2))
            .arg(flag!(all -a --"all-types"))
            .arg(flag!(depth / --"depth").takes_value(true))
            .arg(flag!(literal -Q --"literal"))
            .arg(flag!(fixedstrings -F --"fixed-strings"))
            .arg(flag!(alltext -t --"all-text").conflicts_with("all"))
            .arg(flag!(unrestricted -u --"unrestricted").conflicts_with("all"))
            .arg(flag!(searchbinary / --"search-binary"))
            .arg(flag!(searchhidden / --"hidden"))
            .arg(flag!(fileswith -l --"files-with-matches"))
            .arg(flag!(fileswithout -L --"files-without-matches").conflicts_with("fileswith"))
            .arg(flag!(count -c --"count").conflicts_with("fileswith"))
            .arg(flag!(follow -f --"follow"))
            .arg(flag!(nofollow / --"nofollow").conflicts_with("follow"))
            .arg(flag!(nocolor / --"nocolor"))
            .arg(flag!(colorlineno / --"color-line-number").takes_value(true))
            .arg(flag!(colorspan / --"color-match").takes_value(true))
            .arg(flag!(colorpath / --"color-path").takes_value(true))
            .arg(flag!(colorpunct / --"color-punct").takes_value(true))
            .arg(flag!(casesens -s --"case-sensitive").conflicts_with("caseinsens"))
            .arg(flag!(casesmart -S --"smart-case").conflicts_with("casesens"))
            .arg(flag!(caseinsens -i --"ignore-case").conflicts_with("casesmart"))
            .arg(flag!(group / --"group"))
            .arg(flag!(nogroup / --"nogroup").conflicts_with("gorup"))
            .arg(flag!(heading -H --"heading"))
            .arg(flag!(noheading / --"noheading").conflicts_with("heading"))
            .arg(flag!(break / --"break"))
            .arg(flag!(nobreak / --"nobreak").conflicts_with("break"))
            .arg(flag!(ackmate / --"ackmate"))
            .arg(flag!(vimgrep / --"vimgrep"))
            .arg(flag!(maxcount -m --"max-count").takes_value(true))
            .arg(flag!(before -B --"before").takes_value(true))
            .arg(flag!(after -A --"after").takes_value(true))
            .arg(flag!(context -C --"context").takes_value(true))
            ;
        let m = app.get_matches();

        let depth = m.value_of("depth").and_then(|v| v.parse::<usize>().ok())
                                       .map(|v| v + 1) // 0 == immediate children
                                       .unwrap_or(usize::MAX);

        let mut binaries = m.is_present("searchbinary");
        let mut hidden = m.is_present("searchhidden");
        let mut ignores = true;
        if m.is_present("all") {
            binaries = true;
            ignores = false;
        } else if m.is_present("alltext") {
            ignores = false;
        } else if m.is_present("unrestricted") {
            binaries = true;
            hidden = true;
            ignores = false;
        }

        let mut casing = Casing::Smart;
        if m.is_present("caseinsens") {
            casing = Casing::Insensitive;
        } else if m.is_present("casesens") {
            casing = Casing::Default;
        }
        let mut literal = m.is_present("literal");
        if m.is_present("fixedstrings") {
            literal = true;
        }

        let colors = if m.is_present("nocolor") {
            Colors::empty()
        } else {
            Colors::from(
                m.value_of("colorpath").unwrap_or("35"),
                m.value_of("colorlineno").unwrap_or("32"),
                m.value_of("colorspan").unwrap_or("4"),
                m.value_of("colorpunct").unwrap_or("36"),
            )
        };
        let mut heading = true;
        let mut showbreak = true;
        if m.is_present("noheading") {
            heading = false;
        }
        if m.is_present("nobreak") {
            showbreak = false;
        }
        if m.is_present("nogroup") {
            heading = false;
            showbreak = false;
        }
        let maxcount = m.value_of("maxcount").and_then(|v| v.parse().ok())
                                             .unwrap_or(usize::MAX);
        let mut before = m.value_of("before").and_then(|v| v.parse().ok())
                                             .unwrap_or(0);
        let mut after = m.value_of("after").and_then(|v| v.parse().ok())
                                           .unwrap_or(0);
        if m.is_present("context") {
            before = m.value_of("context").unwrap().parse().ok().unwrap_or(0);
            after = before;
        }

        Opts {
            // file related
            path: m.value_of("path").unwrap_or(".").into(),
            depth: depth,
            follow_links: !m.is_present("nofollow"),
            do_binaries: binaries,
            do_hidden: hidden,
            // ignore file related
            check_ignores: ignores,
            // pattern related
            pattern: m.value_of("pattern").unwrap().into(),
            casing: casing,
            literal: literal,
            // display related
            colors: Some(colors),
            only_files: if m.is_present("fileswith") {
                Some(true)
            } else if m.is_present("fileswithout") {
                Some(false)
            } else { None },
            only_count: m.is_present("count"),
            show_break: showbreak,
            show_heading: heading,
            ackmate_format: m.is_present("ackmate"),
            vimgrep_format: m.is_present("vimgrep"),
            max_count: maxcount,
            before: before,
            after: after,
        }
    }
}
<|endoftext|>


<commit_before>use conduit::{Request, Response};
use conduit_router::RequestParams;
use conduit_json_parser;
use pg::{PostgresConnection, PostgresRow};
use pg::error::PgDbError;

use app::RequestApp;
use db::Connection;
use git;
use user::{RequestUser, User};
use util::{RequestUtils, CargoResult, Require, internal, ChainError};
use util::errors::{NotFound, CargoError};

pub struct Package {
    pub id: i32,
    pub name: String,
}

#[deriving(Encodable)]
pub struct EncodablePackage {
    pub id: String,
    pub name: String,
}

impl Package {
    fn from_row(row: &PostgresRow) -> Package {
        Package {
            id: row.get("id"),
            name: row.get("name"),
        }
    }

    pub fn find_by_name(conn: &Connection, name: &str) -> CargoResult<Package> {
        let stmt = try!(conn.prepare("SELECT * FROM packages \
                                      WHERE name = $1 LIMIT 1"));
        match try!(stmt.query([&name])).next() {
            Some(row) => Ok(Package::from_row(&row)),
            None => Err(NotFound.box_error()),
        }
    }

    pub fn valid_name(name: &str) -> bool {
        if name.len() == 0 { return false }
        name.chars().all(|c| c.is_alphanumeric() || c == '_' || c == '-')
    }

    fn encodable(self) -> EncodablePackage {
        let Package { name, .. } = self;
        EncodablePackage { id: name.clone(), name: name }
    }
}

pub fn setup(conn: &PostgresConnection) {
    conn.execute("DROP TABLE IF EXISTS packages", []).unwrap();
    conn.execute("CREATE TABLE packages (
                    id              SERIAL PRIMARY KEY,
                    name            VARCHAR NOT NULL
                  )", []).unwrap();

    conn.execute("ALTER TABLE packages ADD CONSTRAINT \
                  unique_name UNIQUE (name)", []).unwrap();
    conn.execute("INSERT INTO packages (name) VALUES ($1)",
                 [&"Test"]).unwrap();
    conn.execute("INSERT INTO packages (name) VALUES ($1)",
                 [&"Test2"]).unwrap();
}

pub fn index(req: &mut Request) -> CargoResult<Response> {
    let limit = 10i64;
    let offset = 0i64;
    let conn = req.app().db();
    let stmt = try!(conn.prepare("SELECT * FROM packages LIMIT $1 OFFSET $2"));

    let mut pkgs = Vec::new();
    for row in try!(stmt.query([&limit, &offset])) {
        pkgs.push(Package::from_row(&row).encodable());
    }

    let stmt = try!(conn.prepare("SELECT COUNT(*) FROM packages"));
    let row = try!(stmt.query([])).next().unwrap();
    let total = row.get(0u);

    #[deriving(Encodable)]
    struct R { packages: Vec<EncodablePackage>, meta: Meta }
    #[deriving(Encodable)]
    struct Meta { total: i64, page: i64 }

    Ok(req.json(&R {
        packages: pkgs,
        meta: Meta { total: total, page: offset / limit }
    }))
}

pub fn show(req: &mut Request) -> CargoResult<Response> {
    let name = req.params()["package_id"];
    let pkg = try!(Package::find_by_name(&req.app().db(), name.as_slice()));

    #[deriving(Encodable)]
    struct R { package: EncodablePackage }
    Ok(req.json(&R { package: pkg.encodable() }))
}

#[deriving(Decodable)]
pub struct UpdateRequest { package: UpdatePackage }

#[deriving(Decodable)]
pub struct UpdatePackage {
    name: String,
}

pub fn update(req: &mut Request) -> CargoResult<Response> {
    try!(req.user());
    let conn = req.app().db();
    let name = req.params()["package_id"];
    let pkg = try!(Package::find_by_name(&conn, name.as_slice()));

    let update = conduit_json_parser::json_params::<UpdateRequest>(req).unwrap();
    // TODO: this should do something
    println!("new name: {}", update.package.name);

    #[deriving(Encodable)]
    struct R { package: EncodablePackage }
    Ok(req.json(&R { package: pkg.encodable() }))
}

#[deriving(Decodable, Clone)]
pub struct NewRequest { package: NewPackage }

#[deriving(Decodable, Encodable, Clone)]
pub struct NewPackage {
    pub name: String,
    pub version: String,
    pub other: String,
    pub dependencies: Vec<String>,
}

pub fn new(req: &mut Request) -> CargoResult<Response> {
    let app = req.app();
    let db = app.db();
    let mut tx = try!(db.transaction());
    tx.set_rollback();
    let _user = {
        let header = try!(req.headers().find("X-Cargo-Auth").require(|| {
            internal("missing X-Cargo-Auth header")
        }));
        try!(User::find_by_api_token(&tx, header.get(0).as_slice()))
    };

    let new = conduit_json_parser::json_params::<NewRequest>(req).unwrap();
    let mut new = new.clone();
    new.package.name = new.package.name.as_slice().chars()
                          .map(|c| c.to_lowercase()).collect();
    let name = new.package.name.as_slice();
    if !Package::valid_name(name.as_slice()) {
        return Err(internal(format!("invalid crate name: `{}`", name)))
    }
    match tx.execute("INSERT INTO packages (name) VALUES ($1)", [&name]) {
        Ok(..) => {}
        Err(PgDbError(ref e))
            if e.constraint.as_ref().map(|a| a.as_slice())
                == Some("unique_name") => {
                tx.set_rollback();
                try!(tx.finish());
                tx = try!(db.transaction());
            }
        Err(e) => return Err(e.box_error()),
    }

    let pkg = try!(Package::find_by_name(&tx, name.as_slice()));
    try!(git::add_package(app, &new.package).chain_error(|| {
        internal(format!("could not add package `{}` to the git repo", pkg.name))
    }));
    tx.set_commit();

    #[deriving(Encodable)]
    struct R { package: EncodablePackage }
    Ok(req.json(&R { package: pkg.encodable() }))
}
<commit_msg>Update to master<commit_after>use conduit::{Request, Response};
use conduit_router::RequestParams;
use conduit_json_parser;
use pg::{PostgresConnection, PostgresRow};
use pg::error::PgDbError;

use app::RequestApp;
use db::Connection;
use git;
use user::{RequestUser, User};
use util::{RequestUtils, CargoResult, Require, internal, ChainError};
use util::errors::{NotFound, CargoError};

pub struct Package {
    pub id: i32,
    pub name: String,
}

#[deriving(Encodable)]
pub struct EncodablePackage {
    pub id: String,
    pub name: String,
}

impl Package {
    fn from_row(row: &PostgresRow) -> Package {
        Package {
            id: row.get("id"),
            name: row.get("name"),
        }
    }

    pub fn find_by_name(conn: &Connection, name: &str) -> CargoResult<Package> {
        let stmt = try!(conn.prepare("SELECT * FROM packages \
                                      WHERE name = $1 LIMIT 1"));
        match try!(stmt.query([&name])).next() {
            Some(row) => Ok(Package::from_row(&row)),
            None => Err(NotFound.box_error()),
        }
    }

    pub fn valid_name(name: &str) -> bool {
        if name.len() == 0 { return false }
        name.chars().all(|c| c.is_alphanumeric() || c == '_' || c == '-')
    }

    fn encodable(self) -> EncodablePackage {
        let Package { name, .. } = self;
        EncodablePackage { id: name.clone(), name: name }
    }
}

pub fn setup(conn: &PostgresConnection) {
    conn.execute("DROP TABLE IF EXISTS packages", []).unwrap();
    conn.execute("CREATE TABLE packages (
                    id              SERIAL PRIMARY KEY,
                    name            VARCHAR NOT NULL
                  )", []).unwrap();

    conn.execute("ALTER TABLE packages ADD CONSTRAINT \
                  unique_name UNIQUE (name)", []).unwrap();
    conn.execute("INSERT INTO packages (name) VALUES ($1)",
                 [&"Test"]).unwrap();
    conn.execute("INSERT INTO packages (name) VALUES ($1)",
                 [&"Test2"]).unwrap();
}

pub fn index(req: &mut Request) -> CargoResult<Response> {
    let limit = 10i64;
    let offset = 0i64;
    let conn = req.app().db();
    let stmt = try!(conn.prepare("SELECT * FROM packages LIMIT $1 OFFSET $2"));

    let mut pkgs = Vec::new();
    for row in try!(stmt.query([&limit, &offset])) {
        pkgs.push(Package::from_row(&row).encodable());
    }

    let stmt = try!(conn.prepare("SELECT COUNT(*) FROM packages"));
    let row = try!(stmt.query([])).next().unwrap();
    let total = row.get(0u);

    #[deriving(Encodable)]
    struct R { packages: Vec<EncodablePackage>, meta: Meta }
    #[deriving(Encodable)]
    struct Meta { total: i64, page: i64 }

    Ok(req.json(&R {
        packages: pkgs,
        meta: Meta { total: total, page: offset / limit }
    }))
}

pub fn show(req: &mut Request) -> CargoResult<Response> {
    let name = &req.params()["package_id"];
    let pkg = try!(Package::find_by_name(&req.app().db(), name.as_slice()));

    #[deriving(Encodable)]
    struct R { package: EncodablePackage }
    Ok(req.json(&R { package: pkg.encodable() }))
}

#[deriving(Decodable)]
pub struct UpdateRequest { package: UpdatePackage }

#[deriving(Decodable)]
pub struct UpdatePackage {
    name: String,
}

pub fn update(req: &mut Request) -> CargoResult<Response> {
    try!(req.user());
    let conn = req.app().db();
    let name = &req.params()["package_id"];
    let pkg = try!(Package::find_by_name(&conn, name.as_slice()));

    let update = conduit_json_parser::json_params::<UpdateRequest>(req).unwrap();
    // TODO: this should do something
    println!("new name: {}", update.package.name);

    #[deriving(Encodable)]
    struct R { package: EncodablePackage }
    Ok(req.json(&R { package: pkg.encodable() }))
}

#[deriving(Decodable, Clone)]
pub struct NewRequest { package: NewPackage }

#[deriving(Decodable, Encodable, Clone)]
pub struct NewPackage {
    pub name: String,
    pub version: String,
    pub other: String,
    pub dependencies: Vec<String>,
}

pub fn new(req: &mut Request) -> CargoResult<Response> {
    let app = req.app();
    let db = app.db();
    let mut tx = try!(db.transaction());
    tx.set_rollback();
    let _user = {
        let header = try!(req.headers().find("X-Cargo-Auth").require(|| {
            internal("missing X-Cargo-Auth header")
        }));
        try!(User::find_by_api_token(&tx, header[0].as_slice()))
    };

    let new = conduit_json_parser::json_params::<NewRequest>(req).unwrap();
    let mut new = new.clone();
    new.package.name = new.package.name.as_slice().chars()
                          .map(|c| c.to_lowercase()).collect();
    let name = new.package.name.as_slice();
    if !Package::valid_name(name.as_slice()) {
        return Err(internal(format!("invalid crate name: `{}`", name)))
    }
    match tx.execute("INSERT INTO packages (name) VALUES ($1)", [&name]) {
        Ok(..) => {}
        Err(PgDbError(ref e))
            if e.constraint.as_ref().map(|a| a.as_slice())
                == Some("unique_name") => {
                tx.set_rollback();
                try!(tx.finish());
                tx = try!(db.transaction());
            }
        Err(e) => return Err(e.box_error()),
    }

    let pkg = try!(Package::find_by_name(&tx, name.as_slice()));
    try!(git::add_package(app, &new.package).chain_error(|| {
        internal(format!("could not add package `{}` to the git repo", pkg.name))
    }));
    tx.set_commit();

    #[deriving(Encodable)]
    struct R { package: EncodablePackage }
    Ok(req.json(&R { package: pkg.encodable() }))
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

#[cfg(gtk_3_4)]
pub use auto::traits::ActionableExt;
pub use auto::traits::BinExt;
pub use auto::traits::BoxExt;
pub use auto::traits::ButtonExt;
pub use auto::traits::CellAreaExt;
pub use auto::traits::CellEditableExt;
pub use auto::traits::CellLayoutExt;
pub use auto::traits::CellRendererExt;
pub use auto::traits::CheckButtonExt;
pub use auto::traits::ContainerExt;
pub use auto::traits::DialogExt;
pub use auto::traits::EditableExt;
pub use auto::traits::EntryExt;
pub use auto::traits::FileChooserExt;
pub use auto::traits::FontChooserExt;
pub use auto::traits::FrameExt;
pub use auto::traits::MenuItemExt;
pub use auto::traits::MenuShellExt;
pub use auto::traits::MiscExt;
pub use auto::traits::OrientableExt;
#[cfg(gtk_3_12)]
pub use auto::traits::PopoverExt;
pub use auto::traits::RangeExt;
pub use auto::traits::RecentChooserExt;
pub use auto::traits::ScaleButtonExt;
pub use auto::traits::ScrollableExt;
pub use auto::traits::ScrolledWindowExt;
pub use auto::traits::ToggleButtonExt;
pub use auto::traits::ToolButtonExt;
pub use auto::traits::ToolItemExt;
pub use auto::traits::ToolShellExt;
//pub use auto::traits::TreeModelExt;
pub use auto::traits::TreeSortableExt;

pub use app_chooser::AppChooserExt;
pub use color_chooser::ColorChooserExt;
pub use tree_model::TreeModelExt;
pub use widget::WidgetExt;
pub use window::WindowExt;
<commit_msg>Add `ComboBoxExt` to prelude<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

#[cfg(gtk_3_4)]
pub use auto::traits::ActionableExt;
pub use auto::traits::BinExt;
pub use auto::traits::BoxExt;
pub use auto::traits::ButtonExt;
pub use auto::traits::CellAreaExt;
pub use auto::traits::CellEditableExt;
pub use auto::traits::CellLayoutExt;
pub use auto::traits::CellRendererExt;
pub use auto::traits::CheckButtonExt;
pub use auto::traits::ComboBoxExt;
pub use auto::traits::ContainerExt;
pub use auto::traits::DialogExt;
pub use auto::traits::EditableExt;
pub use auto::traits::EntryExt;
pub use auto::traits::FileChooserExt;
pub use auto::traits::FontChooserExt;
pub use auto::traits::FrameExt;
pub use auto::traits::MenuItemExt;
pub use auto::traits::MenuShellExt;
pub use auto::traits::MiscExt;
pub use auto::traits::OrientableExt;
#[cfg(gtk_3_12)]
pub use auto::traits::PopoverExt;
pub use auto::traits::RangeExt;
pub use auto::traits::RecentChooserExt;
pub use auto::traits::ScaleButtonExt;
pub use auto::traits::ScrollableExt;
pub use auto::traits::ScrolledWindowExt;
pub use auto::traits::ToggleButtonExt;
pub use auto::traits::ToolButtonExt;
pub use auto::traits::ToolItemExt;
pub use auto::traits::ToolShellExt;
//pub use auto::traits::TreeModelExt;
pub use auto::traits::TreeSortableExt;

pub use app_chooser::AppChooserExt;
pub use color_chooser::ColorChooserExt;
pub use tree_model::TreeModelExt;
pub use widget::WidgetExt;
pub use window::WindowExt;
<|endoftext|>


<commit_before>#[derive(Debug)]
pub struct Request {
    method: String,
    path: String,
    body: Option<String>
}

pub trait ToParams {
    fn to_params(&self) -> Vec<(&str, &str)>;
}

pub trait ToRequest {
    fn to_request(&self) -> Request;
}

impl Request {
    pub fn new(method: String, path: String, body: Option<String>) -> Request {
        Request { method, path, body }
    }
}
<commit_msg>request: add getters<commit_after>#[derive(Debug)]
pub struct Request {
    method: String,
    path: String,
    body: Option<String>
}

pub trait ToParams {
    fn to_params(&self) -> Vec<(&str, &str)>;
}

pub trait ToRequest {
    fn to_request(&self) -> Request;
}

impl Request {
    pub fn new(method: String, path: String, body: Option<String>) -> Request {
        Request { method, path, body }
    }

    pub fn method(&self) -> &str {
        &self.method
    }

    pub fn path(&self) -> &str {
        &self.path
    }

    pub fn body(&self) -> Option<&str> {
        match self.body {
            Some(ref body) => Some(body.as_str()),
            _ => None
        }
    }
}
<|endoftext|>