<commit_before>use scaly::memory::page::Page;
use scaly::memory::page::PAGE_SIZE;
use std::alloc::alloc;
use std::alloc::alloc_zeroed;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::null_mut;

const STACK_BUCKET_PAGES: usize = 0x100;

pub struct Region<'a> {
    page: &'a mut Page,
}

impl<'a> Region<'a> {
    pub fn create_from_page(page: &Page) -> Region<'a> {
        let our_page_address = StackBucket::new_page(page);
        Region {
            page: unsafe { &mut *(our_page_address as *mut Page) },
        }
    }
    pub fn create(region: &Region<'a>) -> Region<'a> {
        Region::create_from_page(region.page)
    }
}

impl<'a> Drop for Region<'a> {
    fn drop(&mut self) {
        self.page.deallocate_extensions();
    }
}

pub enum Bucket {
    Stack(StackBucket),
    Heap(HeapBucket),
}

pub struct HeapBucket {
    map: usize,
}

pub struct Pool {
    root_map: usize,
    maps: *mut usize,
    pointers: *mut HeapBucket,
}

const MAPS_SIZE: usize = size_of::<usize>() * 8 * size_of::<usize>();
const POINTERS_SIZE: usize = MAPS_SIZE * 8 * size_of::<usize>();

impl Pool {
    pub fn create() -> Pool {
        unsafe {
            let maps_memory = alloc_zeroed(Layout::from_size_align_unchecked(MAPS_SIZE, PAGE_SIZE));
            if maps_memory == null_mut() {
                panic!("Unable to allocate maps memory: Out of memory.");
            }
            let pointers_memory =
                alloc_zeroed(Layout::from_size_align_unchecked(POINTERS_SIZE, PAGE_SIZE));
            if pointers_memory == null_mut() {
                panic!("Unable to allocate maps memory: Out of memory.");
            }
            Pool {
                root_map: 0,
                maps: maps_memory as *mut usize,
                pointers: pointers_memory as *mut HeapBucket,
            }
        }
    }
}

impl Drop for Pool {
    fn drop(&mut self) {
        if self.root_map != 0 {
            panic!("Pool is not empty!")
        }
        unsafe {
            dealloc(
                self.maps as *mut u8,
                Layout::from_size_align_unchecked(MAPS_SIZE, PAGE_SIZE),
            );
            dealloc(
                self.pointers as *mut u8,
                Layout::from_size_align_unchecked(POINTERS_SIZE, PAGE_SIZE),
            );
        }
    }
}

pub struct StackBucket {
    next_bucket: *mut StackBucket,
}

impl StackBucket {
    pub fn new_page(page: &Page) -> *mut Page {
        let page_address = page as *const Page as usize;
        let stack_bucket_page_address = page_address & !(PAGE_SIZE * STACK_BUCKET_PAGES - 1);
        let overflowed_page_address = stack_bucket_page_address + PAGE_SIZE * STACK_BUCKET_PAGES;
        let our_page_address = page_address + PAGE_SIZE;
        if overflowed_page_address == our_page_address {
            let stack_bucket = (stack_bucket_page_address + size_of::<Page>()) as *mut StackBucket;
            unsafe { (*stack_bucket).get_page_from_next_bucket() }
        } else {
            our_page_address as *mut Page
        }
    }

    fn get_page_from_next_bucket(self: &mut StackBucket) -> *mut Page {
        if self.next_bucket == null_mut() {
            self.next_bucket = StackBucket::create();
        }
        Page::get_page(self.next_bucket as usize)
    }

    fn create() -> *mut StackBucket {
        unsafe {
            let memory = alloc(Layout::from_size_align_unchecked(
                PAGE_SIZE * STACK_BUCKET_PAGES,
                PAGE_SIZE * STACK_BUCKET_PAGES,
            ));
            if memory == null_mut() {
                panic!("Unable to crete a new stack bucket: Out of memory.");
            }
            let page = &mut *(memory as *mut Page);
            page.reset();
            let bucket = page.allocate(StackBucket {
                next_bucket: null_mut(),
            });
            bucket
        }
    }

    pub fn deallocate(&self) {
        let mut bucket = self as *const StackBucket;
        unsafe {
            while !(*bucket).next_bucket.is_null() {
                let next_bucket = (*bucket).next_bucket;
                let page = Page::get_page(bucket as usize);
                dealloc(
                    page as *mut u8,
                    Layout::from_size_align_unchecked(
                        PAGE_SIZE * STACK_BUCKET_PAGES,
                        PAGE_SIZE * STACK_BUCKET_PAGES,
                    ),
                );

                bucket = next_bucket;
            }
        }
    }
}

impl Drop for StackBucket {
    fn drop(&mut self) {
        self.deallocate();
    }
}

#[test]
fn test_region() {
    unsafe {
        let root_stack_bucket = StackBucket::create();
        let r1 = Region::create_from_page(&*Page::get_page(root_stack_bucket as usize));
        {
            let r2 = Region::create(&r1);
            {
                let _ = Region::create(&r2);
            }
        }
        (*root_stack_bucket).deallocate();
    }
    unsafe {
        let root_stack_bucket = StackBucket::create();

        let mut r = Region::create_from_page(&*Page::get_page(root_stack_bucket as usize));
        for _ in 1..STACK_BUCKET_PAGES * 2 {
            r = Region::create(&r);
        }

        (*root_stack_bucket).deallocate();
    }
}
<commit_msg>Storing a pointer to the pool with StackBucket<commit_after>use scaly::memory::page::Page;
use scaly::memory::page::PAGE_SIZE;
use std::alloc::alloc;
use std::alloc::alloc_zeroed;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::null_mut;

const STACK_BUCKET_PAGES: usize = 0x100;

pub struct Region<'a> {
    page: &'a mut Page,
}

impl<'a> Region<'a> {
    pub fn create_from_page(page: &Page) -> Region<'a> {
        let our_page_address = StackBucket::new_page(page);
        Region {
            page: unsafe { &mut *(our_page_address as *mut Page) },
        }
    }
    pub fn create(region: &Region<'a>) -> Region<'a> {
        Region::create_from_page(region.page)
    }
}

impl<'a> Drop for Region<'a> {
    fn drop(&mut self) {
        self.page.deallocate_extensions();
    }
}

pub enum Bucket {
    Stack(StackBucket),
    Heap(HeapBucket),
}

pub struct HeapBucket {
    map: usize,
}

pub struct Pool {
    root_map: usize,
    maps: *mut usize,
    pointers: *mut HeapBucket,
}

const MAPS_SIZE: usize = size_of::<usize>() * 8 * size_of::<usize>();
const POINTERS_SIZE: usize = MAPS_SIZE * 8 * size_of::<usize>();

impl Pool {
    pub fn create() -> Pool {
        unsafe {
            let maps_memory = alloc_zeroed(Layout::from_size_align_unchecked(MAPS_SIZE, PAGE_SIZE));
            if maps_memory == null_mut() {
                panic!("Unable to allocate maps memory: Out of memory.");
            }
            let pointers_memory =
                alloc_zeroed(Layout::from_size_align_unchecked(POINTERS_SIZE, PAGE_SIZE));
            if pointers_memory == null_mut() {
                panic!("Unable to allocate maps memory: Out of memory.");
            }
            Pool {
                root_map: 0,
                maps: maps_memory as *mut usize,
                pointers: pointers_memory as *mut HeapBucket,
            }
        }
    }
}

impl Drop for Pool {
    fn drop(&mut self) {
        if self.root_map != 0 {
            panic!("Pool is not empty!")
        }
        unsafe {
            dealloc(
                self.maps as *mut u8,
                Layout::from_size_align_unchecked(MAPS_SIZE, PAGE_SIZE),
            );
            dealloc(
                self.pointers as *mut u8,
                Layout::from_size_align_unchecked(POINTERS_SIZE, PAGE_SIZE),
            );
        }
    }
}

pub struct StackBucket {
    next_bucket: *mut StackBucket,
    pool: *mut Pool,
}

impl StackBucket {
    pub fn new_page(page: &Page) -> *mut Page {
        let page_address = page as *const Page as usize;
        let stack_bucket_page_address = page_address & !(PAGE_SIZE * STACK_BUCKET_PAGES - 1);
        let overflowed_page_address = stack_bucket_page_address + PAGE_SIZE * STACK_BUCKET_PAGES;
        let our_page_address = page_address + PAGE_SIZE;
        if overflowed_page_address == our_page_address {
            let stack_bucket = (stack_bucket_page_address + size_of::<Page>()) as *mut StackBucket;
            unsafe { (*stack_bucket).get_page_from_next_bucket() }
        } else {
            our_page_address as *mut Page
        }
    }

    fn get_page_from_next_bucket(self: &mut StackBucket) -> *mut Page {
        if self.next_bucket == null_mut() {
            self.next_bucket = StackBucket::create(self.pool);
        }
        Page::get_page(self.next_bucket as usize)
    }

    fn create(pool: *mut Pool) -> *mut StackBucket {
        unsafe {
            let memory = alloc(Layout::from_size_align_unchecked(
                PAGE_SIZE * STACK_BUCKET_PAGES,
                PAGE_SIZE * STACK_BUCKET_PAGES,
            ));
            if memory == null_mut() {
                panic!("Unable to crete a new stack bucket: Out of memory.");
            }
            let page = &mut *(memory as *mut Page);
            page.reset();
            let bucket = page.allocate(StackBucket {
                next_bucket: null_mut(),
                pool: pool,
            });
            bucket
        }
    }

    pub fn deallocate(&self) {
        let mut bucket = self as *const StackBucket;
        unsafe {
            while !(*bucket).next_bucket.is_null() {
                let next_bucket = (*bucket).next_bucket;
                let page = Page::get_page(bucket as usize);
                dealloc(
                    page as *mut u8,
                    Layout::from_size_align_unchecked(
                        PAGE_SIZE * STACK_BUCKET_PAGES,
                        PAGE_SIZE * STACK_BUCKET_PAGES,
                    ),
                );

                bucket = next_bucket;
            }
        }
    }
}

impl Drop for StackBucket {
    fn drop(&mut self) {
        self.deallocate();
    }
}

#[test]
fn test_region() {
    unsafe {
        let mut pool = Pool::create();
        let root_stack_bucket = StackBucket::create(&mut pool);
        let r1 = Region::create_from_page(&*Page::get_page(root_stack_bucket as usize));
        {
            let r2 = Region::create(&r1);
            {
                let _ = Region::create(&r2);
            }
        }
        (*root_stack_bucket).deallocate();
    }
    unsafe {
        let mut pool = Pool::create();
        let root_stack_bucket = StackBucket::create(&mut pool);

        let mut r = Region::create_from_page(&*Page::get_page(root_stack_bucket as usize));
        for _ in 1..STACK_BUCKET_PAGES * 2 {
            r = Region::create(&r);
        }

        (*root_stack_bucket).deallocate();
    }
}
<|endoftext|>


<commit_before>extern crate orbital;

pub use std::collections::VecDeque;

mod editor;
pub use self::editor::*;

mod parse;
pub use self::parse::*;

mod key_state;
pub use self::key_state::*;

mod key;
pub use self::key::*;

mod prompt;
pub use self::prompt::*;

mod open;
pub use self::open::*;

mod redraw;
pub use self::redraw::*;

mod options;
pub use self::options::*;

mod position;
pub use self::position::*;

mod graphics;
pub use self::graphics::*;

mod selection;
pub use self::selection::*;

mod mode;
pub use self::mode::*;

mod movement;
pub use self::movement::*;

mod motion;
pub use self::motion::*;

mod cursor;
pub use self::cursor::*;

mod insert;
pub use self::insert::*;

mod delete;
pub use self::delete::*;

mod exec;
pub use self::exec::*;

pub mod invert;

#[no_mangle]
pub fn main() {
    Editor::init();
}
<commit_msg>WIP: Emit true rust executables<commit_after>extern crate orbital;

pub use std::collections::VecDeque;

mod editor;
pub use self::editor::*;

mod parse;
pub use self::parse::*;

mod key_state;
pub use self::key_state::*;

mod key;
pub use self::key::*;

mod prompt;
pub use self::prompt::*;

mod open;
pub use self::open::*;

mod redraw;
pub use self::redraw::*;

mod options;
pub use self::options::*;

mod position;
pub use self::position::*;

mod graphics;
pub use self::graphics::*;

mod selection;
pub use self::selection::*;

mod mode;
pub use self::mode::*;

mod movement;
pub use self::movement::*;

mod motion;
pub use self::motion::*;

mod cursor;
pub use self::cursor::*;

mod insert;
pub use self::insert::*;

mod delete;
pub use self::delete::*;

mod exec;
pub use self::exec::*;

pub mod invert;

fn main() {
    Editor::init();
}
<|endoftext|>


<commit_before>#![feature(phase)]

#[phase(plugin, link)]
extern crate log;
extern crate native;
extern crate rsfml;

use rsfml::window::{ContextSettings, VideoMode, event, DefaultStyle};
use rsfml::graphics::RenderWindow;
use rsfml::window::keyboard;

use std::os::args;

mod cpu;

#[cfg(target_os="macos")]
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}

fn main() {
    let arg_list = args();
    if arg_list.len() <= 1 {
        panic!("You must pass in a ROM for rustchip to read.");
    }

    // Create the window of the application
    let setting = ContextSettings::default();
    let mut window = match RenderWindow::new(VideoMode::new_init(640, 320, 32), "rustchip", DefaultStyle, &setting) {
        Some(window) => window,
        None => panic!("Cannot create a new Render Window.")
    };
    window.set_framerate_limit(60);
	let mut c8 = cpu::Cpu::new();

	c8.load(&arg_list[1]);

    while window.is_open() {
        loop {
            match window.poll_event() {
                event::Closed => { window.close()}
                event::NoEvent => { break }
                event::KeyPressed{code, alt, ..} => {
                    if code == keyboard::R && alt {
                        c8 = cpu::Cpu::new();
                        c8.load(&arg_list[1]);
                    }
                    if c8.is_waiting() {
                        let val = match code {
                            keyboard::Num1 => 1,
                            keyboard::Num2 => 2,
                            keyboard::Num3 => 3,
                            keyboard::Num4 => 0xC,
                            keyboard::Q => 4,
                            keyboard::W => 5,
                            keyboard::E => 6,
                            keyboard::R => 0xD,
                            keyboard::A => 7,
                            keyboard::S => 8,
                            keyboard::D => 9,
                            keyboard::F => 0xE,
                            keyboard::Z => 0xA,
                            keyboard::X => 0,
                            keyboard::C => 0xB,
                            keyboard::V => 0xF,
                            _ => -1
                        };
                        if val != -1 {
                            c8.set_wait_register(val);
                        }
                    }
                }
                _ => {}
            }
        }

        if !c8.is_waiting() {
    		c8.run_cycle();
            c8.draw(&mut window);
            c8.update_keys();
        }
    }

}<commit_msg>Removed use of native::start<commit_after>#![feature(phase)]

#[phase(plugin, link)]
extern crate log;
extern crate rsfml;

use rsfml::window::{ContextSettings, VideoMode, event, DefaultStyle};
use rsfml::graphics::RenderWindow;
use rsfml::window::keyboard;

use std::os::args;
use std::rt;

mod cpu;

#[cfg(target_os="macos")]
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    rt::start(argc, argv, main)
}

fn main() {
    let arg_list = args();
    if arg_list.len() <= 1 {
        panic!("You must pass in a ROM for rustchip to read.");
    }

    // Create the window of the application
    let setting = ContextSettings::default();
    let mut window = match RenderWindow::new(VideoMode::new_init(640, 320, 32), "rustchip", DefaultStyle, &setting) {
        Some(window) => window,
        None => panic!("Cannot create a new Render Window.")
    };
    window.set_framerate_limit(60);
	let mut c8 = cpu::Cpu::new();

	c8.load(&arg_list[1]);

    while window.is_open() {
        loop {
            match window.poll_event() {
                event::Closed => { window.close()}
                event::NoEvent => { break }
                event::KeyPressed{code, alt, ..} => {
                    if code == keyboard::R && alt {
                        c8 = cpu::Cpu::new();
                        c8.load(&arg_list[1]);
                    }
                    if c8.is_waiting() {
                        let val = match code {
                            keyboard::Num1 => 1,
                            keyboard::Num2 => 2,
                            keyboard::Num3 => 3,
                            keyboard::Num4 => 0xC,
                            keyboard::Q => 4,
                            keyboard::W => 5,
                            keyboard::E => 6,
                            keyboard::R => 0xD,
                            keyboard::A => 7,
                            keyboard::S => 8,
                            keyboard::D => 9,
                            keyboard::F => 0xE,
                            keyboard::Z => 0xA,
                            keyboard::X => 0,
                            keyboard::C => 0xB,
                            keyboard::V => 0xF,
                            _ => -1
                        };
                        if val != -1 {
                            c8.set_wait_register(val);
                        }
                    }
                }
                _ => {}
            }
        }

        if !c8.is_waiting() {
    		c8.run_cycle();
            c8.draw(&mut window);
            c8.update_keys();
        }
    }

}<|endoftext|>


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

#[cfg(feature = "bytes")]
use bytes::Bytes;

use crate::clear::Clear;
use crate::coded_input_stream::CodedInputStream;
use crate::coded_output_stream::CodedOutputStream;
use crate::coded_output_stream::WithCodedOutputStream;
use crate::error::ProtobufError;
use crate::error::ProtobufResult;
use crate::message_dyn::MessageDyn;
use crate::reflect::reflect_eq::ReflectEqMode;
use crate::reflect::MessageDescriptor;
use crate::unknown::UnknownFields;

/// Trait implemented for all generated structs for protobuf messages.
///
/// Also, generated messages implement `Clone + Default + PartialEq`
pub trait Message: fmt::Debug + Clear + Send + Sync + Sized + 'static {
    /// Message descriptor for this message, used for reflection.
    ///
    /// This function is rarely needed to be called directly, use
    /// [`Message::descriptor_static()`] instead.
    fn descriptor_by_instance(&self) -> MessageDescriptor {
        Self::descriptor_static()
    }

    /// Get message descriptor for message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let descriptor = MyMessage::descriptor_static();
    /// assert_eq!("MyMessage", descriptor.name());
    /// # }
    /// ```
    fn descriptor_static() -> MessageDescriptor {
        panic!(
            "descriptor_static is not implemented for message, \
             LITE_RUNTIME must be used"
        );
    }

    /// True iff all required fields are initialized.
    /// Always returns `true` for protobuf 3.
    fn is_initialized(&self) -> bool;

    /// Update this message object with fields read from given stream.
    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()>;

    /// Parse message from stream.
    fn parse_from(is: &mut CodedInputStream) -> ProtobufResult<Self> {
        let mut r: Self = Message::new();
        r.merge_from(is)?;
        r.check_initialized()?;
        Ok(r)
    }

    /// Write message to the stream.
    ///
    /// Sizes of this messages and nested messages must be cached
    /// by calling `compute_size` prior to this call.
    fn write_to_with_cached_sizes(&self, os: &mut CodedOutputStream) -> ProtobufResult<()>;

    /// Compute and cache size of this message and all nested messages
    fn compute_size(&self) -> u32;

    /// Get size previously computed by `compute_size`.
    fn get_cached_size(&self) -> u32;

    /// Write the message to the stream.
    ///
    /// Results in error if message is not fully initialized.
    fn write_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.check_initialized()?;

        // cache sizes
        self.compute_size();
        // TODO: reserve additional
        self.write_to_with_cached_sizes(os)?;

        Ok(())
    }

    /// Write the message to the stream prepending the message with message length
    /// encoded as varint.
    fn write_length_delimited_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        let size = self.compute_size();
        os.write_raw_varint32(size)?;
        self.write_to_with_cached_sizes(os)?;

        // TODO: assert we've written same number of bytes as computed

        Ok(())
    }

    /// Write the message to the vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_vec(&self, vec: &mut Vec<u8>) -> ProtobufResult<()> {
        let mut os = CodedOutputStream::vec(vec);
        self.write_length_delimited_to(&mut os)?;
        os.flush()?;
        Ok(())
    }

    /// Update this message object with fields read from given stream.
    fn merge_from_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> {
        let mut is = CodedInputStream::from_bytes(bytes);
        self.merge_from(&mut is)
    }

    /// Parse message from reader.
    /// Parse stops on EOF or when error encountered.
    fn parse_from_reader(reader: &mut dyn Read) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::new(reader);
        let r = Message::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from byte array.
    fn parse_from_bytes(bytes: &[u8]) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::from_bytes(bytes);
        let r = Message::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from `Bytes` object.
    /// Resulting message may share references to the passed bytes object.
    #[cfg(feature = "bytes")]
    fn parse_from_carllerche_bytes(bytes: &Bytes) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::from_carllerche_bytes(bytes);
        let r = Self::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Check if all required fields of this object are initialized.
    fn check_initialized(&self) -> ProtobufResult<()> {
        if !self.is_initialized() {
            Err(ProtobufError::MessageNotInitialized(
                self.descriptor_by_instance().name().to_owned(),
            ))
        } else {
            Ok(())
        }
    }

    /// Write the message to the writer.
    fn write_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    fn write_to_vec(&self, v: &mut Vec<u8>) -> ProtobufResult<()> {
        v.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    ///
    /// > **Note**: You can use [`Message::parse_from_bytes`]
    /// to do the reverse.
    fn write_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        self.check_initialized()?;

        let size = self.compute_size() as usize;
        let mut v = Vec::with_capacity(size);
        // skip zerofill
        unsafe {
            v.set_len(size);
        }
        {
            let mut os = CodedOutputStream::bytes(&mut v);
            self.write_to_with_cached_sizes(&mut os)?;
            os.check_eof();
        }
        Ok(v)
    }

    /// Write the message to the writer, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_length_delimited_to(os))
    }

    /// Write the message to the bytes vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        let mut v = Vec::new();
        v.with_coded_output_stream(|os| self.write_length_delimited_to(os))?;
        Ok(v)
    }

    /// Get a reference to unknown fields.
    fn get_unknown_fields(&self) -> &UnknownFields;
    /// Get a mutable reference to unknown fields.
    fn mut_unknown_fields(&mut self) -> &mut UnknownFields;

    /// Create an empty message object.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let m = MyMessage::new();
    /// # }
    /// ```
    fn new() -> Self;

    /// Return a pointer to default immutable message with static lifetime.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let m: &MyMessage = MyMessage::default_instance();
    /// # }
    /// ```
    fn default_instance() -> &'static Self;

    /// Reflective equality.
    ///
    /// # See also
    ///
    /// [`dyn Message::reflect_eq_dyn()`], `dyn` version of this function.
    fn reflect_eq(&self, other: &Self, mode: &ReflectEqMode) -> bool {
        <dyn MessageDyn>::reflect_eq_dyn(self, other, mode)
    }
}
<commit_msg>More docs<commit_after>use std::fmt;
use std::io::Read;
use std::io::Write;

#[cfg(feature = "bytes")]
use bytes::Bytes;

use crate::clear::Clear;
use crate::coded_input_stream::CodedInputStream;
use crate::coded_output_stream::CodedOutputStream;
use crate::coded_output_stream::WithCodedOutputStream;
use crate::error::ProtobufError;
use crate::error::ProtobufResult;
use crate::message_dyn::MessageDyn;
use crate::reflect::reflect_eq::ReflectEqMode;
use crate::reflect::MessageDescriptor;
use crate::unknown::UnknownFields;

/// Trait implemented for all the messages (generated and dynamic).
///
/// * Generated messages are generated from `.proto` files
/// * Dynamic messages can be created without code generation using only parsed proto files
///   (see [FileDescriptor::new_dynamic](crate::reflect::FileDescriptor::new_dynamic)).
///
///
/// Also, generated messages implement `Clone + Default + PartialEq`
///
/// This trait is sized, there's accompanying [`MessageDyn`](crate::MessageDyn) trait
/// which is implemented for all messages which can be used in functions
/// without making message a function type parameter.
pub trait Message: fmt::Debug + Clear + Send + Sync + Sized + 'static {
    /// Message descriptor for this message, used for reflection.
    ///
    /// This function is rarely needed to be called directly, use
    /// [`Message::descriptor_static()`] instead.
    fn descriptor_by_instance(&self) -> MessageDescriptor {
        Self::descriptor_static()
    }

    /// Get message descriptor for message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let descriptor = MyMessage::descriptor_static();
    /// assert_eq!("MyMessage", descriptor.name());
    /// # }
    /// ```
    fn descriptor_static() -> MessageDescriptor {
        panic!(
            "descriptor_static is not implemented for message, \
             LITE_RUNTIME must be used"
        );
    }

    /// True iff all required fields are initialized.
    /// Always returns `true` for protobuf 3.
    fn is_initialized(&self) -> bool;

    /// Update this message object with fields read from given stream.
    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()>;

    /// Parse message from stream.
    fn parse_from(is: &mut CodedInputStream) -> ProtobufResult<Self> {
        let mut r: Self = Message::new();
        r.merge_from(is)?;
        r.check_initialized()?;
        Ok(r)
    }

    /// Write message to the stream.
    ///
    /// Sizes of this messages and nested messages must be cached
    /// by calling `compute_size` prior to this call.
    fn write_to_with_cached_sizes(&self, os: &mut CodedOutputStream) -> ProtobufResult<()>;

    /// Compute and cache size of this message and all nested messages
    fn compute_size(&self) -> u32;

    /// Get size previously computed by `compute_size`.
    fn get_cached_size(&self) -> u32;

    /// Write the message to the stream.
    ///
    /// Results in error if message is not fully initialized.
    fn write_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.check_initialized()?;

        // cache sizes
        self.compute_size();
        // TODO: reserve additional
        self.write_to_with_cached_sizes(os)?;

        Ok(())
    }

    /// Write the message to the stream prepending the message with message length
    /// encoded as varint.
    fn write_length_delimited_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        let size = self.compute_size();
        os.write_raw_varint32(size)?;
        self.write_to_with_cached_sizes(os)?;

        // TODO: assert we've written same number of bytes as computed

        Ok(())
    }

    /// Write the message to the vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_vec(&self, vec: &mut Vec<u8>) -> ProtobufResult<()> {
        let mut os = CodedOutputStream::vec(vec);
        self.write_length_delimited_to(&mut os)?;
        os.flush()?;
        Ok(())
    }

    /// Update this message object with fields read from given stream.
    fn merge_from_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> {
        let mut is = CodedInputStream::from_bytes(bytes);
        self.merge_from(&mut is)
    }

    /// Parse message from reader.
    /// Parse stops on EOF or when error encountered.
    fn parse_from_reader(reader: &mut dyn Read) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::new(reader);
        let r = Message::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from byte array.
    fn parse_from_bytes(bytes: &[u8]) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::from_bytes(bytes);
        let r = Message::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from `Bytes` object.
    /// Resulting message may share references to the passed bytes object.
    #[cfg(feature = "bytes")]
    fn parse_from_carllerche_bytes(bytes: &Bytes) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::from_carllerche_bytes(bytes);
        let r = Self::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Check if all required fields of this object are initialized.
    fn check_initialized(&self) -> ProtobufResult<()> {
        if !self.is_initialized() {
            Err(ProtobufError::MessageNotInitialized(
                self.descriptor_by_instance().name().to_owned(),
            ))
        } else {
            Ok(())
        }
    }

    /// Write the message to the writer.
    fn write_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    fn write_to_vec(&self, v: &mut Vec<u8>) -> ProtobufResult<()> {
        v.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    ///
    /// > **Note**: You can use [`Message::parse_from_bytes`]
    /// to do the reverse.
    fn write_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        self.check_initialized()?;

        let size = self.compute_size() as usize;
        let mut v = Vec::with_capacity(size);
        // skip zerofill
        unsafe {
            v.set_len(size);
        }
        {
            let mut os = CodedOutputStream::bytes(&mut v);
            self.write_to_with_cached_sizes(&mut os)?;
            os.check_eof();
        }
        Ok(v)
    }

    /// Write the message to the writer, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_length_delimited_to(os))
    }

    /// Write the message to the bytes vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        let mut v = Vec::new();
        v.with_coded_output_stream(|os| self.write_length_delimited_to(os))?;
        Ok(v)
    }

    /// Get a reference to unknown fields.
    fn get_unknown_fields(&self) -> &UnknownFields;
    /// Get a mutable reference to unknown fields.
    fn mut_unknown_fields(&mut self) -> &mut UnknownFields;

    /// Create an empty message object.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let m = MyMessage::new();
    /// # }
    /// ```
    fn new() -> Self;

    /// Return a pointer to default immutable message with static lifetime.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let m: &MyMessage = MyMessage::default_instance();
    /// # }
    /// ```
    fn default_instance() -> &'static Self;

    /// Reflective equality.
    ///
    /// # See also
    ///
    /// [`dyn Message::reflect_eq_dyn()`], `dyn` version of this function.
    fn reflect_eq(&self, other: &Self, mode: &ReflectEqMode) -> bool {
        <dyn MessageDyn>::reflect_eq_dyn(self, other, mode)
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow::{self, Borrowed, Owned};

use rustyline::highlight::Highlighter;
use rustyline::hint::{Hinter, HistoryHinter};
use rustyline::{
    Cmd, ConditionalEventHandler, Context, Editor, Event, EventContext, EventHandler, KeyEvent,
    RepeatCount,
};
use rustyline_derive::{Completer, Helper, Validator};

#[derive(Completer, Helper, Validator)]
struct MyHelper(HistoryHinter);

impl Hinter for MyHelper {
    type Hint = String;

    fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<String> {
        self.0.hint(line, pos, ctx)
    }
}

impl Highlighter for MyHelper {
    fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
        &'s self,
        prompt: &'p str,
        default: bool,
    ) -> Cow<'b, str> {
        if default {
            Owned(format!("\x1b[1;32m{}\x1b[m", prompt))
        } else {
            Borrowed(prompt)
        }
    }

    fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
        Owned(format!("\x1b[1m{}\x1b[m", hint))
    }
}

#[derive(Clone)]
struct CompleteHintHandler;
impl ConditionalEventHandler for CompleteHintHandler {
    fn handle(&self, evt: &Event, _: RepeatCount, _: bool, ctx: &EventContext) -> Option<Cmd> {
        if !ctx.has_hint() {
            return None; // default
        }
        if let Some(k) = evt.get(0) {
            #[allow(clippy::if_same_then_else)]
            if *k == KeyEvent::ctrl('E') {
                Some(Cmd::CompleteHint)
            } else if *k == KeyEvent::alt('f') && ctx.line().len() == ctx.pos() {
                Some(Cmd::CompleteHint) // TODO give access to hint
            } else {
                None
            }
        } else {
            unreachable!()
        }
    }
}

struct TabEventHandler;
impl ConditionalEventHandler for TabEventHandler {
    fn handle(&self, evt: &Event, n: RepeatCount, _: bool, ctx: &EventContext) -> Option<Cmd> {
        debug_assert_eq!(*evt, Event::from(KeyEvent::from('\t')));
        if ctx.line()[..ctx.pos()]
            .chars()
            .rev()
            .next()
            .filter(|c| c.is_whitespace())
            .is_some()
        {
            Some(Cmd::SelfInsert(n, '\t'))
        } else {
            None // default complete
        }
    }
}

fn main() {
    let mut rl = Editor::<MyHelper>::new();
    rl.set_helper(Some(MyHelper(HistoryHinter {})));

    let ceh = Box::new(CompleteHintHandler);
    rl.bind_sequence(KeyEvent::ctrl('E'), EventHandler::Conditional(ceh.clone()));
    rl.bind_sequence(KeyEvent::alt('f'), EventHandler::Conditional(ceh));
    rl.bind_sequence(
        KeyEvent::from('\t'),
        EventHandler::Conditional(Box::new(TabEventHandler)),
    );

    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(line.as_str());
                println!("Line: {}", line);
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}
<commit_msg>Add example for custom key bindings<commit_after>use smallvec::smallvec;
use std::borrow::Cow::{self, Borrowed, Owned};

use rustyline::highlight::Highlighter;
use rustyline::hint::{Hinter, HistoryHinter};
use rustyline::{
    Cmd, ConditionalEventHandler, Context, Editor, Event, EventContext, EventHandler, KeyEvent,
    RepeatCount,
};
use rustyline_derive::{Completer, Helper, Validator};

#[derive(Completer, Helper, Validator)]
struct MyHelper(HistoryHinter);

impl Hinter for MyHelper {
    type Hint = String;

    fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<String> {
        self.0.hint(line, pos, ctx)
    }
}

impl Highlighter for MyHelper {
    fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
        &'s self,
        prompt: &'p str,
        default: bool,
    ) -> Cow<'b, str> {
        if default {
            Owned(format!("\x1b[1;32m{}\x1b[m", prompt))
        } else {
            Borrowed(prompt)
        }
    }

    fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
        Owned(format!("\x1b[1m{}\x1b[m", hint))
    }
}

#[derive(Clone)]
struct CompleteHintHandler;
impl ConditionalEventHandler for CompleteHintHandler {
    fn handle(&self, evt: &Event, _: RepeatCount, _: bool, ctx: &EventContext) -> Option<Cmd> {
        if !ctx.has_hint() {
            return None; // default
        }
        if let Some(k) = evt.get(0) {
            #[allow(clippy::if_same_then_else)]
            if *k == KeyEvent::ctrl('E') {
                Some(Cmd::CompleteHint)
            } else if *k == KeyEvent::alt('f') && ctx.line().len() == ctx.pos() {
                Some(Cmd::CompleteHint) // TODO give access to hint
            } else {
                None
            }
        } else {
            unreachable!()
        }
    }
}

struct TabEventHandler;
impl ConditionalEventHandler for TabEventHandler {
    fn handle(&self, evt: &Event, n: RepeatCount, _: bool, ctx: &EventContext) -> Option<Cmd> {
        debug_assert_eq!(*evt, Event::from(KeyEvent::from('\t')));
        if ctx.line()[..ctx.pos()]
            .chars()
            .rev()
            .next()
            .filter(|c| c.is_whitespace())
            .is_some()
        {
            Some(Cmd::SelfInsert(n, '\t'))
        } else {
            None // default complete
        }
    }
}

fn main() {
    let mut rl = Editor::<MyHelper>::new();
    rl.set_helper(Some(MyHelper(HistoryHinter {})));

    let ceh = Box::new(CompleteHintHandler);
    rl.bind_sequence(KeyEvent::ctrl('E'), EventHandler::Conditional(ceh.clone()));
    rl.bind_sequence(KeyEvent::alt('f'), EventHandler::Conditional(ceh));
    rl.bind_sequence(
        KeyEvent::from('\t'),
        EventHandler::Conditional(Box::new(TabEventHandler)),
    );
    rl.bind_sequence(
        Event::KeySeq(smallvec![KeyEvent::ctrl('X'), KeyEvent::ctrl('E')]),
        EventHandler::Simple(Cmd::Suspend), // TODO external editor
    );

    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(line.as_str());
                println!("Line: {}", line);
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
#[cfg(test)]

extern crate jmespath;
extern crate test;
extern crate rustc_serialize;

use rustc_serialize::json::Json;
use test::Bencher;

#[bench]
fn bench_parsing_foo_bar_baz(b: &mut Bencher) {
    b.iter(|| jmespath::Expression::new("foo.bar.baz"));
}

#[bench]
fn bench_lexing_foo_bar_baz(b: &mut Bencher) {
    b.iter(|| for _ in jmespath::tokenize("foo.bar.baz") {});
}

#[bench]
fn bench_parse_and_interpret_foo_bar_baz(b: &mut Bencher) {
    let json = Json::from_str("{\"foo\":{\"bar\":{\"baz\":true}}}").unwrap();
    b.iter(|| {
        let expr = jmespath::Expression::new("foo.bar.baz").unwrap();
        expr.search(&json).unwrap();
    });
}

#[bench]
fn bench_full_or_branches(b: &mut Bencher) {
    let json = Json::from_str("{\"foo\":true}").unwrap();
    b.iter(|| {
        let expr = jmespath::Expression::new("bar || baz || bam || foo").unwrap();
        expr.search(&json).unwrap();
    });
}

#[bench]
fn bench_expr_identifier(b: &mut Bencher) {
    let expr = "abcdefghijklmnopqrstuvwxyz";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_expr_subexpr(b: &mut Bencher) {
    let expr = "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_deep_projection_104(b: &mut Bencher) {
    let deep = "a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*]";
    b.iter(|| jmespath::parse(deep));
}

#[bench]
fn bench_parse_identifier(b: &mut Bencher) {
    let expr = "abcdefghijklmnopqrstuvwxyz";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_subexpr(b: &mut Bencher) {
    let expr = "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_nested50(b: &mut Bencher) {
    let expr = "j49.j48.j47.j46.j45.j44.j43.j42.j41.j40.j39.j38.j37.j36.j35.j34.j33.j32.j31.j30.j29.j28.j27.j26.j25.j24.j23.j22.j21.j20.j19.j18.j17.j16.j15.j14.j13.j12.j11.j10.j9.j8.j7.j6.j5.j4.j3.j2.j1.j0";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_nested50_pipe(b: &mut Bencher) {
    let expr = "j49|j48|j47|j46|j45|j44|j43|j42|j41|j40|j39|j38|j37|j36|j35|j34|j33|j32|j31|j30|j29|j28|j27|j26|j25|j24|j23|j22|j21|j20|j19|j18|j17|j16|j15|j14|j13|j12|j11|j10|j9|j8|j7|j6|j5|j4|j3|j2|j1|j0";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_nested50_index(b: &mut Bencher) {
    let expr = "[49][48][47][46][45][44][43][42][41][40][39][38][37][36][35][34][33][32][31][30][29][28][27][26][25][24][23][22][21][20][19][18][17][16][15][14][13][12][11][10][9][8][7][6][5][4][3][2][1][0]";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_raw_string_literal(b: &mut Bencher) {
    let expr = "'abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz'";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_function_five_args(b: &mut Bencher) {
    let expr = "function(foo, bar, baz, bam, qux)";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_mutli_list_five_exprs(b: &mut Bencher) {
    let expr = "foo.[foo, bar, baz, bam, qux]";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_filter_projection(b: &mut Bencher) {
    let expr = "foo[bar > baz].qux";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_and_interpret_seven_deep_subexpr(b: &mut Bencher) {
    let expr = "a.b.c.d.e.f.g";
    let data = Json::from_str("{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":{\"f\":{\"g\":true}}}}}}}")
        .unwrap();
    let expression = jmespath::Expression::new(expr).unwrap();
    b.iter(|| {
        expression.search(&data)
    });
}
<commit_msg>Adding deep eval benchmark<commit_after>#![feature(test)]
#[cfg(test)]

extern crate jmespath;
extern crate test;
extern crate rustc_serialize;

use rustc_serialize::json::Json;
use test::Bencher;

#[bench]
fn bench_parsing_foo_bar_baz(b: &mut Bencher) {
    b.iter(|| jmespath::Expression::new("foo.bar.baz"));
}

#[bench]
fn bench_lexing_foo_bar_baz(b: &mut Bencher) {
    b.iter(|| for _ in jmespath::tokenize("foo.bar.baz") {});
}

#[bench]
fn bench_parse_and_interpret_foo_bar_baz(b: &mut Bencher) {
    let json = Json::from_str("{\"foo\":{\"bar\":{\"baz\":true}}}").unwrap();
    b.iter(|| {
        let expr = jmespath::Expression::new("foo.bar.baz").unwrap();
        expr.search(&json).unwrap();
    });
}

#[bench]
fn bench_full_or_branches(b: &mut Bencher) {
    let json = Json::from_str("{\"foo\":true}").unwrap();
    b.iter(|| {
        let expr = jmespath::Expression::new("bar || baz || bam || foo").unwrap();
        expr.search(&json).unwrap();
    });
}

#[bench]
fn bench_expr_identifier(b: &mut Bencher) {
    let expr = "abcdefghijklmnopqrstuvwxyz";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_expr_subexpr(b: &mut Bencher) {
    let expr = "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_deep_projection_104(b: &mut Bencher) {
    let deep = "a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*]";
    b.iter(|| jmespath::parse(deep));
}

#[bench]
fn bench_parse_identifier(b: &mut Bencher) {
    let expr = "abcdefghijklmnopqrstuvwxyz";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_subexpr(b: &mut Bencher) {
    let expr = "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_nested50(b: &mut Bencher) {
    let expr = "j49.j48.j47.j46.j45.j44.j43.j42.j41.j40.j39.j38.j37.j36.j35.j34.j33.j32.j31.j30.j29.j28.j27.j26.j25.j24.j23.j22.j21.j20.j19.j18.j17.j16.j15.j14.j13.j12.j11.j10.j9.j8.j7.j6.j5.j4.j3.j2.j1.j0";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_nested50_pipe(b: &mut Bencher) {
    let expr = "j49|j48|j47|j46|j45|j44|j43|j42|j41|j40|j39|j38|j37|j36|j35|j34|j33|j32|j31|j30|j29|j28|j27|j26|j25|j24|j23|j22|j21|j20|j19|j18|j17|j16|j15|j14|j13|j12|j11|j10|j9|j8|j7|j6|j5|j4|j3|j2|j1|j0";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_nested50_index(b: &mut Bencher) {
    let expr = "[49][48][47][46][45][44][43][42][41][40][39][38][37][36][35][34][33][32][31][30][29][28][27][26][25][24][23][22][21][20][19][18][17][16][15][14][13][12][11][10][9][8][7][6][5][4][3][2][1][0]";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_raw_string_literal(b: &mut Bencher) {
    let expr = "'abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz'";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_function_five_args(b: &mut Bencher) {
    let expr = "function(foo, bar, baz, bam, qux)";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_mutli_list_five_exprs(b: &mut Bencher) {
    let expr = "foo.[foo, bar, baz, bam, qux]";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_filter_projection(b: &mut Bencher) {
    let expr = "foo[bar > baz].qux";
    b.iter(|| jmespath::parse(expr));
}

#[bench]
fn bench_parse_and_interpret_seven_deep_subexpr(b: &mut Bencher) {
    let expr = "a.b.c.d.e.f.g";
    let data = Json::from_str("{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":{\"f\":{\"g\":true}}}}}}}")
        .unwrap();
    let expression = jmespath::Expression::new(expr).unwrap();
    b.iter(|| {
        expression.search(&data)
    });
}

#[bench]
fn bench_evaluate_deep(b: &mut Bencher) {
    let expr = "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z";
    let expression = jmespath::Expression::new(expr).unwrap();
    let json = Json::from_str("{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":{\"f\":{\"g\":{\"h\":{\"i\":{\"j\":{\"k\":{\"l\":{\"m\":{\"n\":{\"o\":{\"p\":{\"q\":{\"r\":{\"s\":{\"t\":{\"u\":{\"v\":{\"w\":{\"x\":{\"y\":{\"z\":1}}}}}}}}}}}}}}}}}}}}}}}}}}").unwrap();
    b.iter(|| expression.search(&json));
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// arch/amd64/crate.rs
// - AMD64/x86_64 architecture support
use core::option::Option;

pub use self::log::{puts, puth};

module_define!{arch, [APIC, HPET], init}

pub mod interrupts;
#[doc(hidden)]
pub mod cpu_faults;
pub mod memory;
pub mod threads;
pub mod boot;
pub mod sync;

mod tss;

mod log;
pub mod x86_io;
pub mod hw;
pub mod acpi;
pub mod pci;

extern "C"
{
	static v_kernel_end : ::Void;
}

fn init()
{
	// None needed, just dependencies
}

#[inline(always)]
pub fn checkmark() {
	// SAFE: nop ASM
	unsafe { asm!("xchg %bx, %bx" : : : "memory" : "volatile"); }
}
#[inline(always)]
pub fn checkmark_val<T>(v: *const T) {
	// SAFE: nop ASM (TODO: Ensure)
	unsafe { asm!("xchg %bx, %bx; mov $0,$0" : : "r"(v) : "memory" : "volatile"); }
}

#[allow(improper_ctypes)]
extern "C" {
	pub fn drop_to_user(entry: usize, stack: usize, cmdline_len: usize) -> !;
}

/// Return the system timestamp (miliseconds since an arbitary point)
pub fn cur_timestamp() -> u64
{
	hw::hpet::get_timestamp()
}

/// Print a backtrace, starting at the current location.
pub fn print_backtrace()
{
	let cur_bp: u64;
	// SAFE: Reads from bp
	unsafe{ asm!("mov %rbp, $0" : "=r" (cur_bp)); }
	puts("Backtrace: ");
	puth(cur_bp);

	let mut bp = cur_bp;
	while let Option::Some((newbp, ip)) = cpu_faults::backtrace(bp)
	{
		puts(" > ");
		puth(ip);
		if let Some( (name, ofs) ) = ::symbols::get_symbol_for_addr(ip as usize - 1) {
			puts("(");
			puts(name);
			puts("+");
			puth(ofs as u64 + 1);
			puts(")");
		}
		bp = newbp;
	}
	puts("\n");
}

// vim: ft=rust

<commit_msg>Kernel/AMD64 - Demangled and symbol-annoated backtrace<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// arch/amd64/crate.rs
// - AMD64/x86_64 architecture support
use core::option::Option;

pub use self::log::{puts, puth};

module_define!{arch, [APIC, HPET], init}

pub mod interrupts;
#[doc(hidden)]
pub mod cpu_faults;
pub mod memory;
pub mod threads;
pub mod boot;
pub mod sync;

mod tss;

mod log;
pub mod x86_io;
pub mod hw;
pub mod acpi;
pub mod pci;

extern "C"
{
	static v_kernel_end : ::Void;
}

fn init()
{
	// None needed, just dependencies
}

#[inline(always)]
pub fn checkmark() {
	// SAFE: nop ASM
	unsafe { asm!("xchg %bx, %bx" : : : "memory" : "volatile"); }
}
#[inline(always)]
pub fn checkmark_val<T>(v: *const T) {
	// SAFE: nop ASM (TODO: Ensure)
	unsafe { asm!("xchg %bx, %bx; mov $0,$0" : : "r"(v) : "memory" : "volatile"); }
}

#[allow(improper_ctypes)]
extern "C" {
	pub fn drop_to_user(entry: usize, stack: usize, cmdline_len: usize) -> !;
}

/// Return the system timestamp (miliseconds since an arbitary point)
pub fn cur_timestamp() -> u64
{
	hw::hpet::get_timestamp()
}

/// Print a backtrace, starting at the current location.
pub fn print_backtrace()
{
	let cur_bp: u64;
	// SAFE: Reads from bp
	unsafe{ asm!("mov %rbp, $0" : "=r" (cur_bp)); }
	log_notice!("Backtrace: {}", Backtrace(cur_bp as usize));
}
pub struct Backtrace(usize);
impl ::core::fmt::Display for Backtrace {
	fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
		let mut bp = self.0 as u64;
		while let Option::Some((newbp, ip)) = cpu_faults::backtrace(bp)
		{
			try!(write!(f, " > {:#x}", ip));
			if let Some( (name, ofs) ) = ::symbols::get_symbol_for_addr(ip as usize - 1) {
				try!(write!(f, "({}+{:#x})", ::symbols::Demangle(name), ofs + 1));
			}
			bp = newbp;
		}
		Ok( () )
	}
}

// vim: ft=rust

<|endoftext|>


<commit_before><commit_msg>sync: add warning for watch in non-Send futures (#4741)<commit_after><|endoftext|>


<commit_before>use simplepattern;

use simplepattern::SimplePattern;

#[test]
fn root_url_matches_only_root() {
    let p=SimplePattern::new("/");
    assert!(p.matches("/").is_match);
}

#[test]
fn raw_routes_match_urls() {
    let p=SimplePattern::new("/foo/bar");
    assert!(p.matches("/foo/bar").is_match);
    assert!(p.matches("/foo/bar/").is_match);
    assert!(!p.matches("/biz/bar").is_match);
    assert!(!p.matches("/foo/bar/baz").is_match);
    assert!(!p.matches("/").is_match);
}
<commit_msg>More tests to verify I don't do bad things :(<commit_after>use simplepattern;

use simplepattern::SimplePattern;

#[test]
fn root_url_matches_only_root() {
    let p=SimplePattern::new("/");
    assert!(p.matches("/").is_match);
}

#[test]
fn raw_routes_match_urls() {
    let p=SimplePattern::new("/foo/bar");
    assert!(p.matches("/foo/bar").is_match);
    assert!(p.matches("/foo/bar/").is_match);
    assert!(!p.matches("/biz/bar").is_match);
    assert!(!p.matches("/foo/bar/baz").is_match);
    assert!(!p.matches("/").is_match);
}

#[test]
fn route_raw_text_doesnt_always_match_url() {
    let p=SimplePattern::new("/foo/[bar]/[biz=foo]");
    assert!(!p.matches("/foo/[bar]/[biz=foo]").is_match);
}<|endoftext|>


<commit_before>// some data
static B: [u8; 10] = [99, 97, 114, 114, 121, 116, 111, 119, 101, 108];
static C: [u8; 11] = [116, 104, 97, 110, 107, 115, 102, 105, 115, 104, 0];

fn main() {

    let a = 42;
    let b = &B;
    let c = &C;

    println!("a: {:?}, b: {:p}, c: {:p}", a, b, c);
}
<commit_msg>print info on different pointer types<commit_after>use std::mem::size_of;

// some data
static B: [u8; 10] = [99, 97, 114, 114, 121, 116, 111, 119, 101, 108];
static C: [u8; 11] = [116, 104, 97, 110, 107, 115, 102, 105, 115, 104, 0];

// print_info
fn print_info_ptr<T: std::fmt::Pointer>(desc: &str, x: T) {
    println!("{}:", desc);
    println!(" location:  {:p}", &x);
    println!(" size:      {:?} bytes", size_of::<T>());
    println!(" points to: {:p}", x);
}

fn print_info<T: std::fmt::Debug>(desc: &str, x: T) {
    println!("{}:", desc);
    println!(" location:  {:p}", &x);
    println!(" size:      {:?} bytes", size_of::<T>());
    println!(" value:     {:?}", x);
}

fn main() {
    let a = 42;
    let b = &B;
    let c = Box::new(C);

    print_info("a (an unsigned integer)", a);
    println!();

    print_info_ptr("b (a reference to B)", b);
    println!();

    print_info_ptr("c (a 'box' for C):", c);
    println!();

    print_info("B (an array of 10 bytes)", B);
    println!();

    print_info("C (an array of 11 bytes)", C);
}
<|endoftext|>


<commit_before>use entities::*;
use super::geo::Coordinate;

pub trait InBBox {
    fn in_bbox(&self, bb: &[Coordinate]) -> bool;
}

impl InBBox for Entry {
    fn in_bbox(&self, bb: &[Coordinate]) -> bool {
        // TODO: either return a Result or create a bounding box struct
        if bb.len() != 2 {
            warn!("invalid bounding box: {:?}", bb);
            return false;
        }
        self.lat >= bb[0].lat &&
        self.lng >= bb[0].lng &&
        self.lat <= bb[1].lat &&
        self.lng <= bb[1].lng
    }
}

pub fn entries_by_category_ids<'a>(ids: &'a [String]) -> Box<Fn(&&Entry) -> bool + 'a> {
    Box::new(move |e| ids.iter().any(|c| e.categories.iter().any(|x| x == c)))
}

pub fn triple_by_subject<'a>(o_id: ObjectId) -> Box<Fn(&&Triple) -> bool + 'a> {
    Box::new(move |triple| o_id == triple.subject)
}

pub fn entries_by_tags_or_search_text<'a>(text: &'a str, tags: &'a [String], triples: &'a [Triple]) -> Box<Fn(&&Entry) -> bool + 'a> {
    let tag_triples : Vec<(&String, &String)> = triples
        .into_iter()
        .filter_map(|x| match *x {
            Triple {
                subject   : ObjectId::Entry(ref e_id),
                predicate : Relation::IsTaggedWith,
                object    : ObjectId::Tag(ref t_id)
            } => Some((e_id,t_id)),
            _ => None
        })
        .collect();

    let words = to_words(text);

    Box::new(move |entry|
        tags.iter()
            .any(|tag| tag_triples.iter().any(|t| *t.0 == entry.id && t.1 == tag))
            || (text.len() > 0 && words.iter().any(|word| {
                entry.title.to_lowercase().contains(word) || entry.description.to_lowercase().contains(word)
            }))
            || (text.len() == 0 && (tags.len() == 0 || tags[0] == ""))
    )
}

fn to_words(txt: &str) -> Vec<String> {
    txt.to_lowercase()
        .split(',')
        .map(|x| x.to_string())
        .collect()
}

#[cfg(test)]
mod tests {

    use super::*;
    use business::builder::*;

    #[test]
    fn is_in_bounding_box() {
        let bb = vec![Coordinate {
                          lat: -10.0,
                          lng: -10.0,
                      },
                      Coordinate {
                          lat: 10.0,
                          lng: 10.0,
                      }];
        let e = Entry::build()
            .title("foo")
            .description("bar")
            .lat(5.0)
            .lng(5.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), true);
        let e = Entry::build()
            .title("foo")
            .description("bar")
            .lat(10.1)
            .lng(10.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), false);
    }

    #[test]
    fn is_in_invalid_bounding_box() {
        let bb = vec![Coordinate {
                          lat: 10.0,
                          lng: 10.0,
                      }];
        let e = Entry::build()
            .lat(5.0)
            .lng(5.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), false);
    }

    #[test]
    fn filter_by_bounding_box() {
        let bb = vec![Coordinate {
                          lat: -10.0,
                          lng: -10.0,
                      },
                      Coordinate {
                          lat: 10.0,
                          lng: 10.0,
                      }];
        let entries = vec![
            Entry::build().lat(5.0).lng(5.0).finish(),
            Entry::build().lat(-5.0).lng(5.0).finish(),
            Entry::build().lat(10.0).lng(10.1).finish(),
        ];
        assert_eq!(entries.iter().filter(|&x| x.in_bbox(&bb)).collect::<Vec<&Entry>>().len(),
                   2);
    }

    #[test]
    fn filter_by_category() {
        let entries = vec![
            Entry::build().categories(vec!["a"]).finish(),
            Entry::build().categories(vec!["c"]).finish(),
            Entry::build().categories(vec!["b","a"]).finish(),
        ];
        let ab = vec!["a".into(), "b".into()];
        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_category_ids(&ab)).collect();
        assert_eq!(x.len(), 2);
        let b = vec!["b".into()];
        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_category_ids(&b)).collect();
        assert_eq!(x.len(), 1);
        let c = vec!["c".into()];
        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_category_ids(&c)).collect();
        assert_eq!(x.len(), 1);
    }

    #[test]
    fn search_entries_by_title() {
        let entries = vec![
            Entry::build().title("a title").description("x").finish(),
            Entry::build().title("not so interesting").description("y").finish(),
        ];
        let filter = entries_by_search_text("a");
        let x: Vec<&Entry> = entries.iter().filter(&*filter).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].title, "a title");
        let filter = entries_by_search_text("ti");
        let x: Vec<&Entry> = entries.iter().filter(&*filter).collect();
        assert_eq!(x.len(), 2);
    }

    #[test]
    fn search_entries_by_description() {
        let entries = vec![
            Entry::build().title("a").description("x").finish(),
            Entry::build().title("b").description("y").finish(),
            Entry::build().title("c").description("x").finish(),
        ];
        let filter = entries_by_search_text("x");
        let x: Vec<&Entry> = entries.iter().filter(&*filter).collect();
        assert_eq!(x.len(), 2);
    }

    #[test]
    fn search_with_multiple_words() {
        let entries = vec![
            Entry::build().title("SoLaWi").description("mit gemüse").finish(),
            Entry::build().title("csa").description("This is a great csa").finish(),
            Entry::build().title("solawi").description("Das ist eine tolle solawi").finish(),
        ];
        let filter = entries_by_search_text("csa,toll");
        let x: Vec<&Entry> = entries.iter().filter(&*filter).collect();
        assert_eq!(x.len(), 2);
        let filter = entries_by_search_text("great,to,gemü");
        let x: Vec<&Entry> = entries.iter().filter(&*filter).collect();
        assert_eq!(x.len(), 3);
    }

    #[test]
    fn search_and_ignore_capitalisation() {
        let e0 = Entry::build().title("Eintrag").description("Hallo! Ein EinTrag").finish();
        let e1 = Entry::build().title("Ein trag").description("foo").finish();
        let e2 = Entry::build().title("CSA").description("cool vegetables").finish();
        let entries = vec![&e0, &e1, &e2];

        let filter = entries_by_search_text("Foo");
        let x: Vec<&Entry> = entries.iter().cloned().filter(&*filter).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id, e1.id);

        let filter = entries_by_search_text("trag");
        let x: Vec<&Entry> = entries.iter().cloned().filter(&*filter).collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, e0.id);
        assert_eq!(x[1].id, e1.id);

        let filter = entries_by_search_text("csa");
        let x: Vec<&Entry> = entries.iter().cloned().filter(&*filter).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id, e2.id);
    }

     #[test]
    fn filter_by_tags_or_text() {
        let entries = vec![
            Entry::build().id("a").title("solawi").finish(),
            Entry::build().id("b").title("blabla").description("bla-blubb").finish(),  // bla
            Entry::build().id("c").finish(),    // foo-bar
        ];
        let tags1 = vec!["bla".into()];
        let tags2 = vec!["bla".into(),"foo-bar".into()];
        let tags3 = vec!["foo-bar".into()];
        let no_tags = vec![];
        let solawi = "solawi";
        let blablubb = "bla-blubb";
        let slowtec = "slowtec";
        let no_string = "";
        let no_triples = vec![];
        let triples = vec![
            Triple{ subject: ObjectId::Entry("b".into()), predicate: Relation::IsTaggedWith, object: ObjectId::Tag("bla".into())},
            Triple{ subject: ObjectId::Entry("c".into()), predicate: Relation::IsTaggedWith, object: ObjectId::Tag("foo-bar".into())}
        ];

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&slowtec, &tags1, &no_triples)).collect();
        assert_eq!(x.len(), 0);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&slowtec, &tags1, &triples)).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id,"b");

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&no_string, &tags1, &triples)).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id,"b");

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&no_string, &no_tags, &triples)).collect();
        assert_eq!(x.len(), 3);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&solawi, &no_tags, &triples)).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id, "a");

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&slowtec, &tags2, &triples)).collect();
        assert_eq!(x.len(), 2);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&slowtec, &tags2, &no_triples)).collect();
        assert_eq!(x.len(), 0);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&solawi, &tags2, &triples)).collect();
        assert_eq!(x[0].id,"a");
        assert_eq!(x[1].id,"b");
        assert_eq!(x[2].id,"c");
        assert_eq!(x.len(), 3);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&blablubb, &tags3, &triples)).collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "c");
    }
}
<commit_msg>fix(search): removed tests of unused functions that were removed as well<commit_after>use entities::*;
use super::geo::Coordinate;

pub trait InBBox {
    fn in_bbox(&self, bb: &[Coordinate]) -> bool;
}

impl InBBox for Entry {
    fn in_bbox(&self, bb: &[Coordinate]) -> bool {
        // TODO: either return a Result or create a bounding box struct
        if bb.len() != 2 {
            warn!("invalid bounding box: {:?}", bb);
            return false;
        }
        self.lat >= bb[0].lat &&
        self.lng >= bb[0].lng &&
        self.lat <= bb[1].lat &&
        self.lng <= bb[1].lng
    }
}

pub fn entries_by_category_ids<'a>(ids: &'a [String]) -> Box<Fn(&&Entry) -> bool + 'a> {
    Box::new(move |e| ids.iter().any(|c| e.categories.iter().any(|x| x == c)))
}

pub fn triple_by_subject<'a>(o_id: ObjectId) -> Box<Fn(&&Triple) -> bool + 'a> {
    Box::new(move |triple| o_id == triple.subject)
}

pub fn entries_by_tags_or_search_text<'a>(text: &'a str, tags: &'a [String], triples: &'a [Triple]) -> Box<Fn(&&Entry) -> bool + 'a> {
    let tag_triples : Vec<(&String, &String)> = triples
        .into_iter()
        .filter_map(|x| match *x {
            Triple {
                subject   : ObjectId::Entry(ref e_id),
                predicate : Relation::IsTaggedWith,
                object    : ObjectId::Tag(ref t_id)
            } => Some((e_id,t_id)),
            _ => None
        })
        .collect();

    let words = to_words(text);

    Box::new(move |entry|
        tags.iter()
            .any(|tag| tag_triples.iter().any(|t| *t.0 == entry.id && t.1 == tag))
            || (text.len() > 0 && words.iter().any(|word| {
                entry.title.to_lowercase().contains(word) || entry.description.to_lowercase().contains(word)
            }))
            || (text.len() == 0 && (tags.len() == 0 || tags[0] == ""))
    )
}

fn to_words(txt: &str) -> Vec<String> {
    txt.to_lowercase()
        .split(',')
        .map(|x| x.to_string())
        .collect()
}

#[cfg(test)]
mod tests {

    use super::*;
    use business::builder::*;

    #[test]
    fn is_in_bounding_box() {
        let bb = vec![Coordinate {
                          lat: -10.0,
                          lng: -10.0,
                      },
                      Coordinate {
                          lat: 10.0,
                          lng: 10.0,
                      }];
        let e = Entry::build()
            .title("foo")
            .description("bar")
            .lat(5.0)
            .lng(5.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), true);
        let e = Entry::build()
            .title("foo")
            .description("bar")
            .lat(10.1)
            .lng(10.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), false);
    }

    #[test]
    fn is_in_invalid_bounding_box() {
        let bb = vec![Coordinate {
                          lat: 10.0,
                          lng: 10.0,
                      }];
        let e = Entry::build()
            .lat(5.0)
            .lng(5.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), false);
    }

    #[test]
    fn filter_by_bounding_box() {
        let bb = vec![Coordinate {
                          lat: -10.0,
                          lng: -10.0,
                      },
                      Coordinate {
                          lat: 10.0,
                          lng: 10.0,
                      }];
        let entries = vec![
            Entry::build().lat(5.0).lng(5.0).finish(),
            Entry::build().lat(-5.0).lng(5.0).finish(),
            Entry::build().lat(10.0).lng(10.1).finish(),
        ];
        assert_eq!(entries.iter().filter(|&x| x.in_bbox(&bb)).collect::<Vec<&Entry>>().len(),
                   2);
    }

    #[test]
    fn filter_by_category() {
        let entries = vec![
            Entry::build().categories(vec!["a"]).finish(),
            Entry::build().categories(vec!["c"]).finish(),
            Entry::build().categories(vec!["b","a"]).finish(),
        ];
        let ab = vec!["a".into(), "b".into()];
        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_category_ids(&ab)).collect();
        assert_eq!(x.len(), 2);
        let b = vec!["b".into()];
        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_category_ids(&b)).collect();
        assert_eq!(x.len(), 1);
        let c = vec!["c".into()];
        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_category_ids(&c)).collect();
        assert_eq!(x.len(), 1);
    }

     #[test]
    fn filter_by_tags_or_text() {
        let entries = vec![
            Entry::build().id("a").title("solawi").finish(),
            Entry::build().id("b").title("blabla").description("bla-blubb").finish(),  // bla
            Entry::build().id("c").finish(),    // foo-bar
        ];
        let tags1 = vec!["bla".into()];
        let tags2 = vec!["bla".into(),"foo-bar".into()];
        let tags3 = vec!["foo-bar".into()];
        let no_tags = vec![];
        let solawi = "solawi";
        let blablubb = "bla-blubb";
        let slowtec = "slowtec";
        let no_string = "";
        let no_triples = vec![];
        let triples = vec![
            Triple{ subject: ObjectId::Entry("b".into()), predicate: Relation::IsTaggedWith, object: ObjectId::Tag("bla".into())},
            Triple{ subject: ObjectId::Entry("c".into()), predicate: Relation::IsTaggedWith, object: ObjectId::Tag("foo-bar".into())}
        ];

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&slowtec, &tags1, &no_triples)).collect();
        assert_eq!(x.len(), 0);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&slowtec, &tags1, &triples)).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id,"b");

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&no_string, &tags1, &triples)).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id,"b");

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&no_string, &no_tags, &triples)).collect();
        assert_eq!(x.len(), 3);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&solawi, &no_tags, &triples)).collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id, "a");

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&slowtec, &tags2, &triples)).collect();
        assert_eq!(x.len(), 2);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&slowtec, &tags2, &no_triples)).collect();
        assert_eq!(x.len(), 0);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&solawi, &tags2, &triples)).collect();
        assert_eq!(x[0].id,"a");
        assert_eq!(x[1].id,"b");
        assert_eq!(x[2].id,"c");
        assert_eq!(x.len(), 3);

        let x: Vec<&Entry> = entries.iter().filter(&*entries_by_tags_or_search_text(&blablubb, &tags3, &triples)).collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "c");
    }
}
<|endoftext|>


<commit_before>use mem;

use nvpair;
use xdr;

// nvp implementation version
const NV_VERSION: i32 = 0;

// nvlist pack encoding
const NV_ENCODE_NATIVE: u8 = 0;
const NV_ENCODE_XDR:    u8 = 1;

// nvlist pack endian
const NV_BIG_ENDIAN:    u8 = 0;
const NV_LITTLE_ENDIAN: u8 = 1;

// nvlist persistent unique name flags, stored in nvl_nvflags
const NV_UNIQUE_NAME:      u32 = 0x1;
const NV_UNIQUE_NAME_TYPE: u32 = 0x2;

// nvlist lookup pairs related flags
const NV_FLAG_NOENTOK: isize = 0x1;

enum DataType {
    Unknown = 0,
    Boolean,
    Byte,
    Int16,
    Uint16,
    Int32,
    Uint32,
    Int64,
    Uint64,
    String,
    ByteArray,
    Int16Array,
    Uint16Array,
    Int32Array,
    Uint32Array,
    Int64Array,
    Uint64Array,
    StringArray,
    HrTime,
    NvList,
    NvListArray,
    BooleanValue,
    Int8,
    Uint8,
    BooleanArray,
    Int8Array,
    Uint8Array
}

// Name value stream header
pub struct NvsHeader {
    encoding: u8,  // nvs encoding method
    endian: u8,    // nvs endian
    reserved1: u8, // reserved for future use
    reserved2: u8, // reserved for future use
}

pub struct XdrNvListEncoder<T: xdr::XdrOps> {
    xdr_ops: T,
}

impl<T: xdr::XdrOps> XdrNvListEncoder<T> {
    pub fn new(xdr_ops: T) -> XdrNvListEncoder {
        XdrNvListEncoder {
            xdr_ops: xdr_ops,
        }
    }

    pub fn encode(&mut self, nv_list: &NvList) {
        self.encode_header();
    }

    fn encode_header(&mut self) {
        let header =
            NvsHeader {
                encoding: NV_ENCODE_XDR,
                endian: NV_LITTLE_ENDIAN,
                reserved1: 0,
                reserved2: 0,
            };
        self.xdr_ops.put_bytes(&transmute(header));
    }
}
<commit_msg>Fixed mem import in zfs<commit_after>use core::mem;

use nvpair;
use xdr;

// nvp implementation version
const NV_VERSION: i32 = 0;

// nvlist pack encoding
const NV_ENCODE_NATIVE: u8 = 0;
const NV_ENCODE_XDR:    u8 = 1;

// nvlist pack endian
const NV_BIG_ENDIAN:    u8 = 0;
const NV_LITTLE_ENDIAN: u8 = 1;

// nvlist persistent unique name flags, stored in nvl_nvflags
const NV_UNIQUE_NAME:      u32 = 0x1;
const NV_UNIQUE_NAME_TYPE: u32 = 0x2;

// nvlist lookup pairs related flags
const NV_FLAG_NOENTOK: isize = 0x1;

enum DataType {
    Unknown = 0,
    Boolean,
    Byte,
    Int16,
    Uint16,
    Int32,
    Uint32,
    Int64,
    Uint64,
    String,
    ByteArray,
    Int16Array,
    Uint16Array,
    Int32Array,
    Uint32Array,
    Int64Array,
    Uint64Array,
    StringArray,
    HrTime,
    NvList,
    NvListArray,
    BooleanValue,
    Int8,
    Uint8,
    BooleanArray,
    Int8Array,
    Uint8Array
}

// Name value stream header
pub struct NvsHeader {
    encoding: u8,  // nvs encoding method
    endian: u8,    // nvs endian
    reserved1: u8, // reserved for future use
    reserved2: u8, // reserved for future use
}

pub struct XdrNvListEncoder<T: xdr::XdrOps> {
    xdr_ops: T,
}

impl<T: xdr::XdrOps> XdrNvListEncoder<T> {
    pub fn new(xdr_ops: T) -> XdrNvListEncoder {
        XdrNvListEncoder {
            xdr_ops: xdr_ops,
        }
    }

    pub fn encode(&mut self, nv_list: &NvList) {
        self.encode_header();
    }

    fn encode_header(&mut self) {
        let header =
            NvsHeader {
                encoding: NV_ENCODE_XDR,
                endian: NV_LITTLE_ENDIAN,
                reserved1: 0,
                reserved2: 0,
            };
        self.xdr_ops.put_bytes(&mem::transmute(header));
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate coreutils;
extern crate extra;

use std::env;
use std::fs;
use std::fs::FileType;
use std::path::Path;
use std::io::{stdout, stderr, Stderr, Write, BufWriter};
use std::os::unix::fs::MetadataExt;
use std::process::exit;

use coreutils::{ArgParser, to_human_readable_string, format_system_time};
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{ls} */ r#"
NAME
    ls - list directory contents

SYNOPSIS
    ls [ -h | --help | -l ] [FILE]...

DESCRIPTION
    List information about the FILE(s), or the current directory

OPTIONS
    -a, --all
        do not ignore entries starting with .
    -h, --human-readable
        with -l, print human readable sizes
    --help
        display this help and exit
    -l
        use a long listing format
    -r, --reverse
        reverse order while sorting
    -R, --recursive
        list subdirectories recursively
    --mdate --modified-date
        display date of last modification
    --adate --accessed-date
        display date of last access
    --cdate --created-date
        display date of creation

"#; /* @MANEND */

fn mode_to_human_readable(file_type: &FileType, symlink_file_type: &FileType, mode: u32) -> String {

    let mut result = String::from("");
    if symlink_file_type.is_symlink() {
        result.push('l')
    } else if file_type.is_dir() {
        result.push('d');
    } else {
        result.push('-');
    }

    let mode_str = format!("{:>6o}", mode);
    let mode_chars = mode_str[3..].chars();
    for i in mode_chars {
        match i {
            '7' => result.push_str("rwx"),
            '6' => result.push_str("rw-"),
            '5' => result.push_str("r-x"),
            '4' => result.push_str("r--"),
            '3' => result.push_str("-wx"),
            '2' => result.push_str("-w-"),
            '1' => result.push_str("--x"),
            _ => result.push_str("---"),
        }
    }

    return result;
}

fn print_item<W: Write>(item_path: &str, parser: &ArgParser, output: &mut W, stderr: &mut Stderr) {

    let mut link_error = "";
    let symlink_metadata = fs::symlink_metadata(&item_path).try(stderr);
    let metadata = match fs::metadata(&item_path) {
        Ok(metadata) => metadata,
        Err(_) => {
            link_error = "broken link";
            fs::symlink_metadata(&item_path).try(stderr)
        }
    };
    if parser.found("long-format") {
        output.write(&format!("{} {:>5} {:>5} ",
                              mode_to_human_readable(&(metadata.file_type()), &(symlink_metadata.file_type()), metadata.mode()),
                              metadata.uid(),
                              metadata.gid())
                              .as_bytes())
            .try(stderr);
        if parser.found("human-readable") {
            output.write(&format!("{:>6} ", to_human_readable_string(metadata.size())).as_bytes()).try(stderr);
        } else {
            output.write(&format!("{:>8} ", metadata.size()).as_bytes()).try(stderr);
        }
    }
    if parser.found("modified-date") || parser.found("long-format") {
        let mtime = match metadata.modified(){
            Ok(mtime) => format_system_time(mtime),
            Err(_) => "mdate err".to_string(),
        };
        output.write(&format!("{:>20} ", mtime).as_bytes()).try(stderr);
    }
    if parser.found("accessed-date") {
        let atime = match metadata.accessed(){
            Ok(atime) => format_system_time(atime),
            Err(_) => "adate err".to_string(),
        };
        output.write(&format!("{:>20} ", atime).as_bytes()).try(stderr);
    }
    if parser.found("created-date") {
        let ctime = match metadata.created(){
            Ok(ctime) => format_system_time(ctime),
            Err(_) => "cdate err".to_string(),
        };
        output.write(&format!("{:>20} ", ctime).as_bytes()).try(stderr);
    }

    if item_path.starts_with("./") {
        output.write(&item_path[2..].as_bytes()).try(stderr);
    } else {
        output.write(item_path.as_bytes()).try(stderr);
    }
    if parser.found("long-format") && symlink_metadata.file_type().is_symlink() {
        let symlink_target = fs::read_link(item_path)
            .expect("can't read link")
            .into_os_string()
            .into_string()
            .expect("can't get path as string");
        output.write(&format!(" -> {}", symlink_target).as_bytes()).try(stderr);
        if !link_error.is_empty() {
            output.write(&format!(" ({})", link_error).as_bytes()).try(stderr);
        }
    }

    output.write("\n".as_bytes()).try(stderr);
}

fn list_dir<W: Write>(path: &str, parser: &ArgParser, output: &mut W, stderr: &mut Stderr) {
    let show_hidden = parser.found("all");

    let metadata = fs::metadata(path).try(stderr);
    if metadata.is_dir() {
        let read_dir = Path::new(path).read_dir().try(stderr);

        let mut entries: Vec<String> = read_dir.filter_map(|x| x.ok())
            .map(|x| {
                let file_name = x.file_name().to_string_lossy().into_owned();
                file_name
            })
            .filter(|x| show_hidden || !x.starts_with("."))
            .collect();

        if parser.found("reverse") {
            entries.sort_by(|a, b| b.cmp(a));
        } else {
            entries.sort_by(|a, b| a.cmp(b));
        }

        for entry in entries.iter() {
            let mut entry_path = path.to_owned();
            if !entry_path.ends_with('/') {
                entry_path.push('/');
            }
            entry_path.push_str(&entry);
            print_item(&entry_path, &parser, output, stderr);
            if parser.found("recursive") && metadata.is_dir() {
                list_dir(&entry_path, parser, output, stderr);
            }
        }
    } else {
        print_item(&path, &parser, output, stderr);
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = BufWriter::new(stdout.lock());
    let mut stderr = stderr();

    let mut parser = ArgParser::new(6)
        .add_flag(&["a", "all"])
        .add_flag(&["l", "long-format"])
        .add_flag(&["h", "human-readable"])
        .add_flag(&["r", "reverse"])
        .add_flag(&["R", "recursive"])
        .add_flag(&["mdate", "modified-date"])
        .add_flag(&["adate", "accessed-date"])
        .add_flag(&["cdate", "created-date"])
        .add_flag(&["", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    if parser.args.is_empty() {
        list_dir(".", &parser, &mut stdout, &mut stderr);
    } else {
        for dir in parser.args.iter() {
            list_dir(&dir, &parser, &mut stdout, &mut stderr);
        }
    }
}

#[test]
fn test_human_readable() {
    assert_eq!(to_human_readable_string(0), "0");
    assert_eq!(to_human_readable_string(1023), "1023");
    assert_eq!(to_human_readable_string(1024), "1.0K");
    assert_eq!(to_human_readable_string(1024 + 100), "1.1K");
    assert_eq!(to_human_readable_string(1024u64.pow(2) * 2), "2.0M");
    assert_eq!(to_human_readable_string(1024u64.pow(3) * 3), "3.0G");
    assert_eq!(to_human_readable_string(1024u64.pow(4) * 4), "4.0T");
    assert_eq!(to_human_readable_string(1024u64.pow(5) * 5), "5.0P");
    assert_eq!(to_human_readable_string(1024u64.pow(6) * 6), "6.0E");
}

#[test]
fn test_format_system_time() {
    use std::ops::Add;
    use std::time::{SystemTime, Duration};
    let now = SystemTime::now();
    let future = SystemTime::now().add(Duration::from_secs(10));
    assert_ne!(format_system_time(now), format_system_time(future));
    // compare up to ten minutes: 2017-03-21 17:1_:__
    assert_eq!(format_system_time(now)[..15], format_system_time(future)[..15]);
}
<commit_msg>instead of directly writing to stdout, there is a Vec<String>, called output, where all output is collected now. at the end of main all content from output is writen to stdout.<commit_after>#![deny(warnings)]
extern crate coreutils;
extern crate extra;

use std::env;
use std::fs;
use std::fs::FileType;
use std::path::Path;
use std::io::{stdout, stderr, Stderr, Write, BufWriter};
use std::os::unix::fs::MetadataExt;
use std::process::exit;
use std::vec::Vec;

use coreutils::{ArgParser, to_human_readable_string, format_system_time};
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{ls} */ r#"
NAME
    ls - list directory contents

SYNOPSIS
    ls [ -h | --help | -l ] [FILE]...

DESCRIPTION
    List information about the FILE(s), or the current directory

OPTIONS
    -a, --all
        do not ignore entries starting with .
    -h, --human-readable
        with -l, print human readable sizes
    --help
        display this help and exit
    -l
        use a long listing format
    -r, --reverse
        reverse order while sorting
    -R, --recursive
        list subdirectories recursively
    --mdate --modified-date
        display date of last modification
    --adate --accessed-date
        display date of last access
    --cdate --created-date
        display date of creation

"#; /* @MANEND */

fn mode_to_human_readable(file_type: &FileType, symlink_file_type: &FileType, mode: u32) -> String {

    let mut result = String::from("");
    if symlink_file_type.is_symlink() {
        result.push('l')
    } else if file_type.is_dir() {
        result.push('d');
    } else {
        result.push('-');
    }

    let mode_str = format!("{:>6o}", mode);
    let mode_chars = mode_str[3..].chars();
    for i in mode_chars {
        match i {
            '7' => result.push_str("rwx"),
            '6' => result.push_str("rw-"),
            '5' => result.push_str("r-x"),
            '4' => result.push_str("r--"),
            '3' => result.push_str("-wx"),
            '2' => result.push_str("-w-"),
            '1' => result.push_str("--x"),
            _ => result.push_str("---"),
        }
    }

    return result;
}

fn print_item(item_path: &str, parser: &ArgParser, output: &mut Vec<String>, stderr: &mut Stderr) {

    let mut link_error = "";
    let symlink_metadata = fs::symlink_metadata(&item_path).try(stderr);
    let metadata = match fs::metadata(&item_path) {
        Ok(metadata) => metadata,
        Err(_) => {
            link_error = "broken link";
            fs::symlink_metadata(&item_path).try(stderr)
        }
    };
    if parser.found("long-format") {
        output.push(format!("{} {:>5} {:>5} ",
                              mode_to_human_readable(&(metadata.file_type()), &(symlink_metadata.file_type()), metadata.mode()),
                              metadata.uid(),
                              metadata.gid())
                    );
        if parser.found("human-readable") {
            output.push(format!("{:>6} ", to_human_readable_string(metadata.size())));
        } else {
            output.push(format!("{:>8} ", metadata.size()));
        }
    }
    if parser.found("modified-date") || parser.found("long-format") {
        let mtime = match metadata.modified(){
            Ok(mtime) => format_system_time(mtime),
            Err(_) => "mdate err".to_string(),
        };
        output.push(format!("{:>20} ", mtime));
    }
    if parser.found("accessed-date") {
        let atime = match metadata.accessed(){
            Ok(atime) => format_system_time(atime),
            Err(_) => "adate err".to_string(),
        };
        output.push(format!("{:>20} ", atime));
    }
    if parser.found("created-date") {
        let ctime = match metadata.created(){
            Ok(ctime) => format_system_time(ctime),
            Err(_) => "cdate err".to_string(),
        };
        output.push(format!("{:>20} ", ctime));
    }

    if item_path.starts_with("./") {
        output.push(item_path[2..].to_string());
    } else {
        output.push(item_path.to_string());
    }
    if parser.found("long-format") && symlink_metadata.file_type().is_symlink() {
        let symlink_target = fs::read_link(item_path)
            .expect("can't read link")
            .into_os_string()
            .into_string()
            .expect("can't get path as string");
        output.push(format!(" -> {}", symlink_target));
        if !link_error.is_empty() {
            output.push(format!(" ({})", link_error));
        }
    }
}

fn list_dir(path: &str, parser: &ArgParser, output: &mut Vec<String>, stderr: &mut Stderr) {
    let show_hidden = parser.found("all");

    let metadata = fs::metadata(path).try(stderr);
    if metadata.is_dir() {
        let read_dir = Path::new(path).read_dir().try(stderr);

        let mut entries: Vec<String> = read_dir.filter_map(|x| x.ok())
            .map(|x| {
                let file_name = x.file_name().to_string_lossy().into_owned();
                file_name
            })
            .filter(|x| show_hidden || !x.starts_with("."))
            .collect();

        if parser.found("reverse") {
            entries.sort_by(|a, b| b.cmp(a));
        } else {
            entries.sort_by(|a, b| a.cmp(b));
        }

        for entry in entries.iter() {
            let mut entry_path = path.to_owned();
            if !entry_path.ends_with('/') {
                entry_path.push('/');
            }
            entry_path.push_str(&entry);
            print_item(&entry_path, &parser, output, stderr);
            if parser.found("recursive") && metadata.is_dir() {
                list_dir(&entry_path, parser, output, stderr);
            }
        }
    } else {
        print_item(&path, &parser, output, stderr);
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = BufWriter::new(stdout.lock());
    let mut stderr = stderr();

    let mut parser = ArgParser::new(6)
        .add_flag(&["a", "all"])
        .add_flag(&["l", "long-format"])
        .add_flag(&["h", "human-readable"])
        .add_flag(&["r", "reverse"])
        .add_flag(&["R", "recursive"])
        .add_flag(&["mdate", "modified-date"])
        .add_flag(&["adate", "accessed-date"])
        .add_flag(&["cdate", "created-date"])
        .add_flag(&["", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let mut output = Vec::new();
    if parser.args.is_empty() {
        list_dir(".", &parser, &mut output, &mut stderr);
    } else {
        for dir in parser.args.iter() {
            list_dir(&dir, &parser, &mut output, &mut stderr);
        }
    }
    for i in output {
        stdout.write(i.as_bytes()).try(&mut stderr);
        stdout.write("\n".as_bytes()).try(&mut stderr);
    }
    stdout.flush().try(&mut stderr);
}

#[test]
fn test_human_readable() {
    assert_eq!(to_human_readable_string(0), "0");
    assert_eq!(to_human_readable_string(1023), "1023");
    assert_eq!(to_human_readable_string(1024), "1.0K");
    assert_eq!(to_human_readable_string(1024 + 100), "1.1K");
    assert_eq!(to_human_readable_string(1024u64.pow(2) * 2), "2.0M");
    assert_eq!(to_human_readable_string(1024u64.pow(3) * 3), "3.0G");
    assert_eq!(to_human_readable_string(1024u64.pow(4) * 4), "4.0T");
    assert_eq!(to_human_readable_string(1024u64.pow(5) * 5), "5.0P");
    assert_eq!(to_human_readable_string(1024u64.pow(6) * 6), "6.0E");
}

#[test]
fn test_format_system_time() {
    use std::ops::Add;
    use std::time::{SystemTime, Duration};
    let now = SystemTime::now();
    let future = SystemTime::now().add(Duration::from_secs(10));
    assert_ne!(format_system_time(now), format_system_time(future));
    // compare up to ten minutes: 2017-03-21 17:1_:__
    assert_eq!(format_system_time(now)[..15], format_system_time(future)[..15]);
}
<|endoftext|>


<commit_before>use libc;
use std;
use std::ffi::CString;
use std::io::{Error, ErrorKind};

#[derive(Debug)]
pub struct Buffer {
    buf: *mut libc::c_char,
    offset: isize,
    buflen: libc::size_t,
}

impl Buffer {
    pub fn new(buf: *mut libc::c_char, buflen: libc::size_t) -> Self { Self { buf, offset: 0, buflen } }

    fn write(&mut self, data: *const libc::c_char, len: usize) -> Result<*mut libc::c_char, Error> {
        if self.buflen < len + self.offset as libc::size_t {
            return Err(Error::new(ErrorKind::AddrNotAvailable, "ERANGE"));
        }
        unsafe {
            let pos = self.buf.offset(self.offset);
            std::ptr::copy(data as *mut i8, pos as *mut i8, len);
            self.offset += len as isize;
            self.buflen -= len as libc::size_t;
            Ok(pos)
        }
    }

    fn add_pointers(&mut self, ptrs: &[*mut libc::c_char]) -> Result<*mut *mut libc::c_char, Error> {
        use std::mem::size_of;
        let step = std::cmp::max(size_of::<*mut libc::c_char>() / size_of::<libc::c_char>(), 1);
        if self.buflen < (((ptrs.len() + 1) * step) as isize + self.offset) as libc::size_t {
            return Err(Error::new(ErrorKind::AddrNotAvailable, "ERANGE"));
        }
        unsafe {
            let mem = self.buf.offset(self.offset) as *mut *mut libc::c_char;
            for (i, p) in ptrs.iter().enumerate() {
                *(mem.add(i)) = *p;
                self.offset += step as isize;
                self.buflen -= step as libc::size_t;
            }
            *(mem.add(ptrs.len())) = std::ptr::null_mut::<libc::c_char>();
            self.offset += step as isize;
            self.buflen -= step as libc::size_t;
            Ok(mem)
        }
    }

    pub fn write_string(&mut self, s: &str) -> Result<*mut libc::c_char, Error> {
        let cs = CString::new(s).unwrap();
        self.write(cs.as_ptr(), s.len() + 1)
    }

    pub fn write_vecstr(&mut self, ss: &[&str]) -> Result<*mut *mut libc::c_char, Error> {
        let mut ptrs = Vec::<*mut libc::c_char>::new();
        for s in ss {
            ptrs.push(self.write_string(s)?);
        }
        self.add_pointers(&ptrs)
    }
}
<commit_msg>Add some trick to align offset<commit_after>use libc;
use std;
use std::ffi::CString;
use std::io::{Error, ErrorKind};

#[derive(Debug)]
pub struct Buffer {
    buf: *mut libc::c_char,
    offset: isize,
    buflen: libc::size_t,
}

impl Buffer {
    pub fn new(buf: *mut libc::c_char, buflen: libc::size_t) -> Self { Self { buf, offset: 0, buflen } }

    fn write(&mut self, data: *const libc::c_char, len: usize) -> Result<*mut libc::c_char, Error> {
        if self.buflen < len + self.offset as libc::size_t {
            return Err(Error::new(ErrorKind::AddrNotAvailable, "ERANGE"));
        }
        unsafe {
            let pos = self.buf.offset(self.offset);
            std::ptr::copy(data as *mut i8, pos as *mut i8, len);
            self.offset += len as isize;
            self.buflen -= len as libc::size_t;
            Ok(pos)
        }
    }

    #[allow(clippy::cast_ptr_alignment)] // NOTE: waiting for align_offset https://github.com/rust-lang/rust/issues/44488
    fn add_pointers(&mut self, ptrs: &[*mut libc::c_char]) -> Result<*mut *mut libc::c_char, Error> {
        use std::mem::size_of;
        let step = std::cmp::max(size_of::<*mut libc::c_char>() / size_of::<libc::c_char>(), 1);
        let align_offset = self.offset % step as isize;
        self.offset += align_offset; // NOTE: remove after stabilization of align_offset
        if self.buflen < (((ptrs.len() + 1) * step) as isize + self.offset) as libc::size_t {
            return Err(Error::new(ErrorKind::AddrNotAvailable, "ERANGE"));
        }
        unsafe {
            let mem = self.buf.offset(self.offset) as *mut *mut libc::c_char;
            for (i, p) in ptrs.iter().enumerate() {
                *(mem.add(i)) = *p;
                self.offset += step as isize;
                self.buflen -= step as libc::size_t;
            }
            *(mem.add(ptrs.len())) = std::ptr::null_mut::<libc::c_char>();
            self.offset += step as isize;
            self.buflen -= step as libc::size_t;
            Ok(mem)
        }
    }

    pub fn write_string(&mut self, s: &str) -> Result<*mut libc::c_char, Error> {
        let cs = CString::new(s).unwrap();
        self.write(cs.as_ptr(), s.len() + 1)
    }

    pub fn write_vecstr(&mut self, ss: &[&str]) -> Result<*mut *mut libc::c_char, Error> {
        let mut ptrs = Vec::<*mut libc::c_char>::new();
        for s in ss {
            ptrs.push(self.write_string(s)?);
        }
        self.add_pointers(&ptrs)
    }
}
<|endoftext|>