<commit_before>//! Collection traits for generic programming.
//!
//! Code that uses these traits should use them as generally as possible. For example, consider the
//! following function that fills a map with default values for some keys:
//!
//! ```
//! use eclectic::map::*;
//!
//! fn fill<M, K>(keys: K) -> M
//! where
//!     M: Default + Map,
//!     K: IntoIterator<Item = M::Key>,
//!     M::Value: Default,
//! {
//!     let mut map = M::default();
//!     for key in keys { map.insert(key, M::Value::default()); }
//!     map
//! }
//! ```
//!
//! `Map` is a convenient shorthand for code that uses multiple map APIs, but this code only ever
//! calls `insert`, so it could be rewritten more generally as:
//!
//! ```
//! use eclectic::map;
//!
//! fn fill<M, K>(keys: K) -> M
//! where
//!     M: Default + map::Insert,
//!     K: IntoIterator<Item = M::Key>,
//!     M::Value: Default,
//! {
//!     let mut map = M::default();
//!     for key in keys { map.insert(key, M::Value::default()); }
//!     map
//! }
//! ```

mod std_impls;

/// A collection that contains a finite number of items.
pub trait Len {
    /// Checks if the collection is empty.
    fn is_empty(&self) -> bool { self.len() == 0 }

    /// Returns the number of items in the collection.
    fn len(&self) -> usize;
}

/// A collection that can be cleared.
pub trait Clear {
    /// Removes all items from the collection.
    fn clear(&mut self);
}

pub mod map {
    //! Maps.
    //!
    //! A map is a collection that associates keys with corresponding values, where the keys are
    //! distinguished according to some uniqueness criteria.

    use super::*;

    /// A trait that declares a map's key and value types.
    ///
    /// It is unusual to bound a type by this trait directly.
    pub trait Base {
        /// The map's key type.
        type Key;

        /// The map's value type.
        type Value;
    }

    /// A map that supports lookups using keys of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Base>::Key>: Base {
        /// Checks if the map contains the given key.
        fn contains_key(&self, key: &Q) -> bool { self.get(key).is_some() }

        /// Returns a reference to the value in the map corresponding to the given key.
        fn get(&self, key: &Q) -> Option<&Self::Value>;
    }

    /// A map that supports mutable lookups using keys of type `&Q`.
    pub trait GetMut<Q: ?Sized = <Self as Base>::Key>: Get<Q> {
        /// Returns a mutable reference to the value in the map corresponding to the given key.
        fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;
    }

    /// A map that supports removals using keys of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Base>::Key>: GetMut<Q> {
        /// Removes the given key from the map and returns its corresponding value, if any.
        fn remove(&mut self, key: &Q) -> Option<Self::Value>;
    }

    /// A map that supports insertion.
    pub trait Insert: Base + Extend<(<Self as Base>::Key, <Self as Base>::Value)> {
        /// Inserts the given key and value into the map and returns the previous value
        /// corresponding to the given key, if any.
        // TODO: document replacement requirements
        fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
    }

    /// A map.
    ///
    /// This trait is implemented for all types that implement `{Len, Clear, Insert, Remove}`.
    pub trait Map: Len + Clear + Insert + Remove {}

    impl<M: ?Sized> Map for M where M: Len + Clear + Insert + Remove {}

    /// A map that supports efficient in-place manipulation.
    ///
    /// `'a` is the lifetime of the map.
    pub trait EntryMap<'a>: Base where
        <Self as Base>::Key: 'a,
        <Self as Base>::Value: 'a,
    {
        /// The type of the map's occupied entries.
        type OccupiedEntry: OccupiedEntry<'a, Key = Self::Key, Value = Self::Value>;

        /// The type of the map's vacant entries.
        type VacantEntry: VacantEntry<'a, Key = Self::Key, Value = Self::Value>;

        /// Returns the entry in the map corresponding to the given key.
        fn entry(&'a mut self, key: Self::Key) -> Entry<Self::OccupiedEntry, Self::VacantEntry>;
    }

    /// An occupied map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait OccupiedEntry<'a> {
        /// The type of the map's keys.
        type Key: 'a;

        /// The type of the map's values.
        type Value: 'a;

        /// Returns a reference to the entry's value.
        fn get(&self) -> &Self::Value;

        /// Returns a mutable reference to the entry's value.
        fn get_mut(&mut self) -> &mut Self::Value;

        /// Returns a mutable reference to the entry's value with the same lifetime as the map.
        fn into_mut(self) -> &'a mut Self::Value;

        /// Replaces the entry's value with the given one and returns the old value.
        fn insert(&mut self, value: Self::Value) -> Self::Value {
            ::std::mem::replace(self.get_mut(), value)
        }

        /// Removes the entry from the map and returns its value.
        fn remove(self) -> Self::Value;
    }

    /// A vacant map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait VacantEntry<'a> {
        /// The type of the map's keys.
        type Key: 'a;

        /// The type of the map's values.
        type Value: 'a;

        /// Inserts the entry into the map with the given value and returns a mutable reference to
        /// it with the same lifetime as the map.
        fn insert(self, value: Self::Value) -> &'a mut Self::Value;
    }

    /// A map entry.
    #[derive(Debug)]
    pub enum Entry<OE, VE> {
        /// An occupied map entry.
        Occupied(OE),
        /// A vacant map entry.
        Vacant(VE),
    }

    impl<'a, OE, VE> Entry<OE, VE>
    where
        OE: OccupiedEntry<'a>,
        VE: VacantEntry<'a, Value = OE::Value>,
    {
        /// Ensures the entry is occupied by inserting it with the given default value if it is
        /// vacant.
        pub fn or_insert(self, default: VE::Value) -> &'a mut OE::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(default),
            }
        }

        /// Ensures the entry is occupied by inserting it with the result of the given function if
        /// it is vacant.
        pub fn or_insert_with<F>(self, f: F) -> &'a mut OE::Value where F: FnOnce() -> VE::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(f()),
            }
        }
    }

    #[cfg(test)]
    pub fn count<M, I>(items: I) -> M
    where
        M: Default + for<'a> map::EntryMap<'a, Value = usize>,
        I: IntoIterator<Item = M::Key>,
    {
        let mut map = M::default();
        for item in items { *map.entry(item).or_insert(0) += 1; }
        map
    }
}

pub mod set {
    //! Sets.
    //!
    //! A set is a collection whose items are distinguished according to some uniqueness criteria.

    use super::*;

    /// A trait that declares a set's item type.
    ///
    /// It is unusual to bound a type by this trait directly.
    pub trait Base {
        type Item;
    }

    /// A set that supports lookups using items of type `&Q`.
    pub trait Contains<Q: ?Sized = <Self as Base>::Item>: Base {
        /// Checks if the set contains the given item.
        fn contains(&self, item: &Q) -> bool;
    }

    /// A set that supports removals using items of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Base>::Item>: Contains<Q> {
        /// Removes the given item from the set and returns `true` if the set contained it.
        fn remove(&mut self, item: &Q) -> bool;
    }

    /// A set that supports insertion.
    pub trait Insert: Base + Extend<<Self as Base>::Item> {
        /// Inserts the given item into the set and returns `true` if the set did not contain it.
        // TODO: document replacement requirements
        fn insert(&mut self, item: Self::Item) -> bool;
    }

    /// A set.
    ///
    /// This trait is implemented for all types that implement `{Len, Clear, Insert, Remove}`.
    pub trait Set: Len + Clear + Insert + Remove {}

    impl<S: ?Sized> Set for S where S: Len + Clear + Insert + Remove {}
}
<commit_msg>Document `set::Base::Item`<commit_after>//! Collection traits for generic programming.
//!
//! Code that uses these traits should use them as generally as possible. For example, consider the
//! following function that fills a map with default values for some keys:
//!
//! ```
//! use eclectic::map::*;
//!
//! fn fill<M, K>(keys: K) -> M
//! where
//!     M: Default + Map,
//!     K: IntoIterator<Item = M::Key>,
//!     M::Value: Default,
//! {
//!     let mut map = M::default();
//!     for key in keys { map.insert(key, M::Value::default()); }
//!     map
//! }
//! ```
//!
//! `Map` is a convenient shorthand for code that uses multiple map APIs, but this code only ever
//! calls `insert`, so it could be rewritten more generally as:
//!
//! ```
//! use eclectic::map;
//!
//! fn fill<M, K>(keys: K) -> M
//! where
//!     M: Default + map::Insert,
//!     K: IntoIterator<Item = M::Key>,
//!     M::Value: Default,
//! {
//!     let mut map = M::default();
//!     for key in keys { map.insert(key, M::Value::default()); }
//!     map
//! }
//! ```

mod std_impls;

/// A collection that contains a finite number of items.
pub trait Len {
    /// Checks if the collection is empty.
    fn is_empty(&self) -> bool { self.len() == 0 }

    /// Returns the number of items in the collection.
    fn len(&self) -> usize;
}

/// A collection that can be cleared.
pub trait Clear {
    /// Removes all items from the collection.
    fn clear(&mut self);
}

pub mod map {
    //! Maps.
    //!
    //! A map is a collection that associates keys with corresponding values, where the keys are
    //! distinguished according to some uniqueness criteria.

    use super::*;

    /// A trait that declares a map's key and value types.
    ///
    /// It is unusual to bound a type by this trait directly.
    pub trait Base {
        /// The map's key type.
        type Key;

        /// The map's value type.
        type Value;
    }

    /// A map that supports lookups using keys of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Base>::Key>: Base {
        /// Checks if the map contains the given key.
        fn contains_key(&self, key: &Q) -> bool { self.get(key).is_some() }

        /// Returns a reference to the value in the map corresponding to the given key.
        fn get(&self, key: &Q) -> Option<&Self::Value>;
    }

    /// A map that supports mutable lookups using keys of type `&Q`.
    pub trait GetMut<Q: ?Sized = <Self as Base>::Key>: Get<Q> {
        /// Returns a mutable reference to the value in the map corresponding to the given key.
        fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;
    }

    /// A map that supports removals using keys of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Base>::Key>: GetMut<Q> {
        /// Removes the given key from the map and returns its corresponding value, if any.
        fn remove(&mut self, key: &Q) -> Option<Self::Value>;
    }

    /// A map that supports insertion.
    pub trait Insert: Base + Extend<(<Self as Base>::Key, <Self as Base>::Value)> {
        /// Inserts the given key and value into the map and returns the previous value
        /// corresponding to the given key, if any.
        // TODO: document replacement requirements
        fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
    }

    /// A map.
    ///
    /// This trait is implemented for all types that implement `{Len, Clear, Insert, Remove}`.
    pub trait Map: Len + Clear + Insert + Remove {}

    impl<M: ?Sized> Map for M where M: Len + Clear + Insert + Remove {}

    /// A map that supports efficient in-place manipulation.
    ///
    /// `'a` is the lifetime of the map.
    pub trait EntryMap<'a>: Base where
        <Self as Base>::Key: 'a,
        <Self as Base>::Value: 'a,
    {
        /// The type of the map's occupied entries.
        type OccupiedEntry: OccupiedEntry<'a, Key = Self::Key, Value = Self::Value>;

        /// The type of the map's vacant entries.
        type VacantEntry: VacantEntry<'a, Key = Self::Key, Value = Self::Value>;

        /// Returns the entry in the map corresponding to the given key.
        fn entry(&'a mut self, key: Self::Key) -> Entry<Self::OccupiedEntry, Self::VacantEntry>;
    }

    /// An occupied map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait OccupiedEntry<'a> {
        /// The type of the map's keys.
        type Key: 'a;

        /// The type of the map's values.
        type Value: 'a;

        /// Returns a reference to the entry's value.
        fn get(&self) -> &Self::Value;

        /// Returns a mutable reference to the entry's value.
        fn get_mut(&mut self) -> &mut Self::Value;

        /// Returns a mutable reference to the entry's value with the same lifetime as the map.
        fn into_mut(self) -> &'a mut Self::Value;

        /// Replaces the entry's value with the given one and returns the old value.
        fn insert(&mut self, value: Self::Value) -> Self::Value {
            ::std::mem::replace(self.get_mut(), value)
        }

        /// Removes the entry from the map and returns its value.
        fn remove(self) -> Self::Value;
    }

    /// A vacant map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait VacantEntry<'a> {
        /// The type of the map's keys.
        type Key: 'a;

        /// The type of the map's values.
        type Value: 'a;

        /// Inserts the entry into the map with the given value and returns a mutable reference to
        /// it with the same lifetime as the map.
        fn insert(self, value: Self::Value) -> &'a mut Self::Value;
    }

    /// A map entry.
    #[derive(Debug)]
    pub enum Entry<OE, VE> {
        /// An occupied map entry.
        Occupied(OE),
        /// A vacant map entry.
        Vacant(VE),
    }

    impl<'a, OE, VE> Entry<OE, VE>
    where
        OE: OccupiedEntry<'a>,
        VE: VacantEntry<'a, Value = OE::Value>,
    {
        /// Ensures the entry is occupied by inserting it with the given default value if it is
        /// vacant.
        pub fn or_insert(self, default: VE::Value) -> &'a mut OE::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(default),
            }
        }

        /// Ensures the entry is occupied by inserting it with the result of the given function if
        /// it is vacant.
        pub fn or_insert_with<F>(self, f: F) -> &'a mut OE::Value where F: FnOnce() -> VE::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(f()),
            }
        }
    }

    #[cfg(test)]
    pub fn count<M, I>(items: I) -> M
    where
        M: Default + for<'a> map::EntryMap<'a, Value = usize>,
        I: IntoIterator<Item = M::Key>,
    {
        let mut map = M::default();
        for item in items { *map.entry(item).or_insert(0) += 1; }
        map
    }
}

pub mod set {
    //! Sets.
    //!
    //! A set is a collection whose items are distinguished according to some uniqueness criteria.

    use super::*;

    /// A trait that declares a set's item type.
    ///
    /// It is unusual to bound a type by this trait directly.
    pub trait Base {
        /// The set's item type.
        type Item;
    }

    /// A set that supports lookups using items of type `&Q`.
    pub trait Contains<Q: ?Sized = <Self as Base>::Item>: Base {
        /// Checks if the set contains the given item.
        fn contains(&self, item: &Q) -> bool;
    }

    /// A set that supports removals using items of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Base>::Item>: Contains<Q> {
        /// Removes the given item from the set and returns `true` if the set contained it.
        fn remove(&mut self, item: &Q) -> bool;
    }

    /// A set that supports insertion.
    pub trait Insert: Base + Extend<<Self as Base>::Item> {
        /// Inserts the given item into the set and returns `true` if the set did not contain it.
        // TODO: document replacement requirements
        fn insert(&mut self, item: Self::Item) -> bool;
    }

    /// A set.
    ///
    /// This trait is implemented for all types that implement `{Len, Clear, Insert, Remove}`.
    pub trait Set: Len + Clear + Insert + Remove {}

    impl<S: ?Sized> Set for S where S: Len + Clear + Insert + Remove {}
}
<|endoftext|>


<commit_before>#![cfg(target_os = "macos")]
#![deny(
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[macro_use]
extern crate bitflags;

extern crate fsevent_sys as fsevent;

use fsevent as fs;
use fsevent::core_foundation as cf;

use std::ffi::CStr;
use std::fmt::{Display, Formatter};
use std::os::raw::{c_char, c_void};
use std::ptr;
use std::slice;
use std::slice::from_raw_parts_mut;

use std::sync::mpsc::Sender;

#[cfg(target_pointer_width = "64")]
type SafePointer = u64;

#[cfg(target_pointer_width = "32")]
type SafePointer = u32;

#[derive(Clone, Copy, Debug)]
pub struct FsEventRefWrapper {
    ptr: SafePointer,
}

impl From<*mut c_void> for FsEventRefWrapper {
    fn from(raw: *mut c_void) -> FsEventRefWrapper {
        let ptr = raw as SafePointer;
        Self { ptr }
    }
}

impl From<FsEventRefWrapper> for *mut c_void {
    fn from(safe: FsEventRefWrapper) -> *mut c_void {
        safe.ptr as *mut c_void
    }
}

pub struct FsEvent {
    paths: Vec<String>,
    since_when: fs::FSEventStreamEventId,
    latency: cf::CFTimeInterval,
    flags: fs::FSEventStreamCreateFlags,
}

#[derive(Debug)]
pub struct Event {
    pub event_id: u64,
    pub flag: StreamFlags,
    pub path: String,
}

// Synchronize with
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Headers/FSEvents.h
bitflags! {
  #[repr(C)]
  pub struct StreamFlags: u32 {
    const NONE = 0x00000000;
    const MUST_SCAN_SUBDIRS = 0x00000001;
    const USER_DROPPED = 0x00000002;
    const KERNEL_DROPPED = 0x00000004;
    const IDS_WRAPPED = 0x00000008;
    const HISTORY_DONE = 0x00000010;
    const ROOT_CHANGED = 0x00000020;
    const MOUNT = 0x00000040;
    const UNMOUNT = 0x00000080;
    const ITEM_CREATED = 0x00000100;
    const ITEM_REMOVED = 0x00000200;
    const INODE_META_MOD = 0x00000400;
    const ITEM_RENAMED = 0x00000800;
    const ITEM_MODIFIED = 0x00001000;
    const FINDER_INFO_MOD = 0x00002000;
    const ITEM_CHANGE_OWNER = 0x00004000;
    const ITEM_XATTR_MOD = 0x00008000;
    const IS_FILE = 0x00010000;
    const IS_DIR = 0x00020000;
    const IS_SYMLINK = 0x00040000;
    const OWN_EVENT = 0x00080000;
    const IS_HARDLINK = 0x00100000;
    const IS_LAST_HARDLINK = 0x00200000;
    const ITEM_CLONED = 0x400000;
  }
}

impl Display for StreamFlags {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        if self.contains(StreamFlags::MUST_SCAN_SUBDIRS) {
            let _d = write!(f, "MUST_SCAN_SUBDIRS ");
        }
        if self.contains(StreamFlags::USER_DROPPED) {
            let _d = write!(f, "USER_DROPPED ");
        }
        if self.contains(StreamFlags::KERNEL_DROPPED) {
            let _d = write!(f, "KERNEL_DROPPED ");
        }
        if self.contains(StreamFlags::IDS_WRAPPED) {
            let _d = write!(f, "IDS_WRAPPED ");
        }
        if self.contains(StreamFlags::HISTORY_DONE) {
            let _d = write!(f, "HISTORY_DONE ");
        }
        if self.contains(StreamFlags::ROOT_CHANGED) {
            let _d = write!(f, "ROOT_CHANGED ");
        }
        if self.contains(StreamFlags::MOUNT) {
            let _d = write!(f, "MOUNT ");
        }
        if self.contains(StreamFlags::UNMOUNT) {
            let _d = write!(f, "UNMOUNT ");
        }
        if self.contains(StreamFlags::ITEM_CREATED) {
            let _d = write!(f, "ITEM_CREATED ");
        }
        if self.contains(StreamFlags::ITEM_REMOVED) {
            let _d = write!(f, "ITEM_REMOVED ");
        }
        if self.contains(StreamFlags::INODE_META_MOD) {
            let _d = write!(f, "INODE_META_MOD ");
        }
        if self.contains(StreamFlags::ITEM_RENAMED) {
            let _d = write!(f, "ITEM_RENAMED ");
        }
        if self.contains(StreamFlags::ITEM_MODIFIED) {
            let _d = write!(f, "ITEM_MODIFIED ");
        }
        if self.contains(StreamFlags::FINDER_INFO_MOD) {
            let _d = write!(f, "FINDER_INFO_MOD ");
        }
        if self.contains(StreamFlags::ITEM_CHANGE_OWNER) {
            let _d = write!(f, "ITEM_CHANGE_OWNER ");
        }
        if self.contains(StreamFlags::ITEM_XATTR_MOD) {
            let _d = write!(f, "ITEM_XATTR_MOD ");
        }
        if self.contains(StreamFlags::IS_FILE) {
            let _d = write!(f, "IS_FILE ");
        }
        if self.contains(StreamFlags::IS_DIR) {
            let _d = write!(f, "IS_DIR ");
        }
        if self.contains(StreamFlags::IS_SYMLINK) {
            let _d = write!(f, "IS_SYMLINK ");
        }
        if self.contains(StreamFlags::OWN_EVENT) {
            let _d = write!(f, "OWN_EVENT ");
        }
        if self.contains(StreamFlags::IS_LAST_HARDLINK) {
            let _d = write!(f, "IS_LAST_HARDLINK ");
        }
        if self.contains(StreamFlags::IS_HARDLINK) {
            let _d = write!(f, "IS_HARDLINK ");
        }
        if self.contains(StreamFlags::ITEM_CLONED) {
            let _d = write!(f, "ITEM_CLONED ");
        }
        write!(f, "")
    }
}

fn default_stream_context(event_sender: *const Sender<Event>) -> fs::FSEventStreamContext {
    let ptr = event_sender as *mut c_void;
    fs::FSEventStreamContext {
        version: 0,
        info: ptr,
        retain: None,
        release: None,
        copy_description: None,
    }
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub struct Error {
    msg: String,
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.msg
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        self.msg.fmt(f)
    }
}

impl From<std::sync::mpsc::RecvTimeoutError> for Error {
    fn from(err: std::sync::mpsc::RecvTimeoutError) -> Error {
        Self {
            msg: err.to_string(),
        }
    }
}

impl FsEvent {
    pub fn new(paths: Vec<String>) -> Self {
        Self {
            paths,
            since_when: fs::kFSEventStreamEventIdSinceNow,
            latency: 0.0,
            flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
        }
    }

    // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
    pub fn append_path(&mut self, source: &str) -> Result<()> {
        self.paths.push(source.to_string());
        Ok(())
    }

    fn build_native_paths(&self) -> Result<cf::CFMutableArrayRef> {
        let native_paths = unsafe {
            cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks)
        };

        if native_paths == std::ptr::null_mut() {
            Err(Error {
                msg: "Unable to allocate CFMutableArrayRef".to_string(),
            })
        } else {
            for path in &self.paths {
                unsafe {
                    let mut err = ptr::null_mut();
                    let cf_path = cf::str_path_to_cfstring_ref(path, &mut err);
                    if !err.is_null() {
                        let cf_str = cf::CFCopyDescription(err as cf::CFRef);
                        let mut buf = [0; 1024];
                        cf::CFStringGetCString(
                            cf_str,
                            buf.as_mut_ptr(),
                            buf.len() as cf::CFIndex,
                            cf::kCFStringEncodingUTF8,
                        );
                        return Err(Error {
                            msg: CStr::from_ptr(buf.as_ptr())
                                .to_str()
                                .unwrap_or("Unknown error")
                                .to_string(),
                        });
                    } else {
                        cf::CFArrayAppendValue(native_paths, cf_path);
                        cf::CFRelease(cf_path);
                    }
                }
            }

            Ok(native_paths)
        }
    }

    fn internal_observe(
        since_when: fs::FSEventStreamEventId,
        latency: cf::CFTimeInterval,
        flags: fs::FSEventStreamCreateFlags,
        paths: FsEventRefWrapper,
        event_sender: Sender<Event>,
        subscription_handle_sender: Option<Sender<FsEventRefWrapper>>,
    ) -> Result<()> {
        let stream_context = default_stream_context(&event_sender);
        let paths = paths.into();

        unsafe {
            let stream = fs::FSEventStreamCreate(
                cf::kCFAllocatorDefault,
                callback,
                &stream_context,
                paths,
                since_when,
                latency,
                flags,
            );

            // fs::FSEventStreamShow(stream);

            match subscription_handle_sender {
                Some(ret_tx) => {
                    let runloop_ref = cf::CFRunLoopGetCurrent();
                    let runloop_ref_safe = FsEventRefWrapper::from(runloop_ref);
                    let ptr_val = runloop_ref_safe.ptr.clone();
                    ret_tx
                        .send(runloop_ref_safe)
                        .expect(&format!("Unable to return CFRunLoopRef ({:#X})", ptr_val));
                }
                None => {}
            }

            fs::FSEventStreamScheduleWithRunLoop(
                stream,
                cf::CFRunLoopGetCurrent(),
                cf::kCFRunLoopDefaultMode,
            );

            fs::FSEventStreamStart(stream);
            cf::CFRunLoopRun();

            fs::FSEventStreamFlushSync(stream);
            fs::FSEventStreamStop(stream);
        }

        Ok(())
    }

    pub fn observe(&self, event_sender: Sender<Event>) {
        let native_paths = self
            .build_native_paths()
            .expect("Unable to build CFMutableArrayRef of watched paths.");
        let safe_native_paths = FsEventRefWrapper::from(native_paths);
        Self::internal_observe(
            self.since_when,
            self.latency,
            self.flags,
            safe_native_paths,
            event_sender,
            None,
        )
        .unwrap();
    }

    pub fn observe_async(&self, event_sender: Sender<Event>) -> Result<FsEventRefWrapper> {
        let (ret_tx, ret_rx) = std::sync::mpsc::channel();
        let native_paths = self.build_native_paths()?;
        let safe_native_paths = FsEventRefWrapper::from(native_paths);

        let since_when = self.since_when;
        let latency = self.latency;
        let flags = self.flags;
        std::thread::spawn(move || {
            Self::internal_observe(
                since_when,
                latency,
                flags,
                safe_native_paths,
                event_sender,
                Some(ret_tx),
            )
        });

        match ret_rx.recv_timeout(std::time::Duration::from_secs(5)) {
            Ok(v) => Ok(v),
            Err(e) => Err(Error::from(e)),
        }
    }

    pub fn shutdown_observe(&self, handle: FsEventRefWrapper) {
        unsafe { cf::CFRunLoopStop(handle.into()) };
    }
}

#[allow(unused_variables)]
extern "C" fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut c_void,
    num_events: usize,                               // size_t numEvents
    event_paths: *mut c_void,                        // void *eventPaths
    event_flags: *const fs::FSEventStreamEventFlags, // const FSEventStreamEventFlags eventFlags[]
    event_ids: *const fs::FSEventStreamEventId,      // const FSEventStreamEventId eventIds[]
) {
    unsafe {
        let event_paths = event_paths as *const *const c_char;
        let num = num_events;
        let e_ptr = event_flags as *mut u32;
        let i_ptr = event_ids as *mut u64;
        let sender = info as *mut Sender<Event>;

        let paths: &[*const c_char] = std::mem::transmute(slice::from_raw_parts(event_paths, num));
        let flags = from_raw_parts_mut(e_ptr, num);
        let ids = from_raw_parts_mut(i_ptr, num);

        for pos in 0..num {
            let path = CStr::from_ptr(*event_paths.add(pos) as *const c_char)
                .to_str()
                .expect("Invalid UTF8 string.");
            let flag = *event_flags.add(pos);
            let event_id = *event_ids.add(pos);

            let event = Event {
                event_id: event_id,
                flag: StreamFlags::from_bits(flag).unwrap_or_else(|| {
                    panic!("Unable to decode StreamFlags: {} for {}", flag, path)
                }),
                path: path.to_string(),
            };
            let _s = (*sender).send(event);
        }
    }
}
<commit_msg>Remove some unused variables and an unnecessary cast<commit_after>#![cfg(target_os = "macos")]
#![deny(
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[macro_use]
extern crate bitflags;

extern crate fsevent_sys as fsevent;

use fsevent as fs;
use fsevent::core_foundation as cf;

use std::ffi::CStr;
use std::fmt::{Display, Formatter};
use std::os::raw::{c_char, c_void};
use std::ptr;

use std::sync::mpsc::Sender;

#[cfg(target_pointer_width = "64")]
type SafePointer = u64;

#[cfg(target_pointer_width = "32")]
type SafePointer = u32;

#[derive(Clone, Copy, Debug)]
pub struct FsEventRefWrapper {
    ptr: SafePointer,
}

impl From<*mut c_void> for FsEventRefWrapper {
    fn from(raw: *mut c_void) -> FsEventRefWrapper {
        let ptr = raw as SafePointer;
        Self { ptr }
    }
}

impl From<FsEventRefWrapper> for *mut c_void {
    fn from(safe: FsEventRefWrapper) -> *mut c_void {
        safe.ptr as *mut c_void
    }
}

pub struct FsEvent {
    paths: Vec<String>,
    since_when: fs::FSEventStreamEventId,
    latency: cf::CFTimeInterval,
    flags: fs::FSEventStreamCreateFlags,
}

#[derive(Debug)]
pub struct Event {
    pub event_id: u64,
    pub flag: StreamFlags,
    pub path: String,
}

// Synchronize with
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Headers/FSEvents.h
bitflags! {
  #[repr(C)]
  pub struct StreamFlags: u32 {
    const NONE = 0x00000000;
    const MUST_SCAN_SUBDIRS = 0x00000001;
    const USER_DROPPED = 0x00000002;
    const KERNEL_DROPPED = 0x00000004;
    const IDS_WRAPPED = 0x00000008;
    const HISTORY_DONE = 0x00000010;
    const ROOT_CHANGED = 0x00000020;
    const MOUNT = 0x00000040;
    const UNMOUNT = 0x00000080;
    const ITEM_CREATED = 0x00000100;
    const ITEM_REMOVED = 0x00000200;
    const INODE_META_MOD = 0x00000400;
    const ITEM_RENAMED = 0x00000800;
    const ITEM_MODIFIED = 0x00001000;
    const FINDER_INFO_MOD = 0x00002000;
    const ITEM_CHANGE_OWNER = 0x00004000;
    const ITEM_XATTR_MOD = 0x00008000;
    const IS_FILE = 0x00010000;
    const IS_DIR = 0x00020000;
    const IS_SYMLINK = 0x00040000;
    const OWN_EVENT = 0x00080000;
    const IS_HARDLINK = 0x00100000;
    const IS_LAST_HARDLINK = 0x00200000;
    const ITEM_CLONED = 0x400000;
  }
}

impl Display for StreamFlags {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        if self.contains(StreamFlags::MUST_SCAN_SUBDIRS) {
            let _d = write!(f, "MUST_SCAN_SUBDIRS ");
        }
        if self.contains(StreamFlags::USER_DROPPED) {
            let _d = write!(f, "USER_DROPPED ");
        }
        if self.contains(StreamFlags::KERNEL_DROPPED) {
            let _d = write!(f, "KERNEL_DROPPED ");
        }
        if self.contains(StreamFlags::IDS_WRAPPED) {
            let _d = write!(f, "IDS_WRAPPED ");
        }
        if self.contains(StreamFlags::HISTORY_DONE) {
            let _d = write!(f, "HISTORY_DONE ");
        }
        if self.contains(StreamFlags::ROOT_CHANGED) {
            let _d = write!(f, "ROOT_CHANGED ");
        }
        if self.contains(StreamFlags::MOUNT) {
            let _d = write!(f, "MOUNT ");
        }
        if self.contains(StreamFlags::UNMOUNT) {
            let _d = write!(f, "UNMOUNT ");
        }
        if self.contains(StreamFlags::ITEM_CREATED) {
            let _d = write!(f, "ITEM_CREATED ");
        }
        if self.contains(StreamFlags::ITEM_REMOVED) {
            let _d = write!(f, "ITEM_REMOVED ");
        }
        if self.contains(StreamFlags::INODE_META_MOD) {
            let _d = write!(f, "INODE_META_MOD ");
        }
        if self.contains(StreamFlags::ITEM_RENAMED) {
            let _d = write!(f, "ITEM_RENAMED ");
        }
        if self.contains(StreamFlags::ITEM_MODIFIED) {
            let _d = write!(f, "ITEM_MODIFIED ");
        }
        if self.contains(StreamFlags::FINDER_INFO_MOD) {
            let _d = write!(f, "FINDER_INFO_MOD ");
        }
        if self.contains(StreamFlags::ITEM_CHANGE_OWNER) {
            let _d = write!(f, "ITEM_CHANGE_OWNER ");
        }
        if self.contains(StreamFlags::ITEM_XATTR_MOD) {
            let _d = write!(f, "ITEM_XATTR_MOD ");
        }
        if self.contains(StreamFlags::IS_FILE) {
            let _d = write!(f, "IS_FILE ");
        }
        if self.contains(StreamFlags::IS_DIR) {
            let _d = write!(f, "IS_DIR ");
        }
        if self.contains(StreamFlags::IS_SYMLINK) {
            let _d = write!(f, "IS_SYMLINK ");
        }
        if self.contains(StreamFlags::OWN_EVENT) {
            let _d = write!(f, "OWN_EVENT ");
        }
        if self.contains(StreamFlags::IS_LAST_HARDLINK) {
            let _d = write!(f, "IS_LAST_HARDLINK ");
        }
        if self.contains(StreamFlags::IS_HARDLINK) {
            let _d = write!(f, "IS_HARDLINK ");
        }
        if self.contains(StreamFlags::ITEM_CLONED) {
            let _d = write!(f, "ITEM_CLONED ");
        }
        write!(f, "")
    }
}

fn default_stream_context(event_sender: *const Sender<Event>) -> fs::FSEventStreamContext {
    let ptr = event_sender as *mut c_void;
    fs::FSEventStreamContext {
        version: 0,
        info: ptr,
        retain: None,
        release: None,
        copy_description: None,
    }
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub struct Error {
    msg: String,
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.msg
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        self.msg.fmt(f)
    }
}

impl From<std::sync::mpsc::RecvTimeoutError> for Error {
    fn from(err: std::sync::mpsc::RecvTimeoutError) -> Error {
        Self {
            msg: err.to_string(),
        }
    }
}

impl FsEvent {
    pub fn new(paths: Vec<String>) -> Self {
        Self {
            paths,
            since_when: fs::kFSEventStreamEventIdSinceNow,
            latency: 0.0,
            flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
        }
    }

    // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
    pub fn append_path(&mut self, source: &str) -> Result<()> {
        self.paths.push(source.to_string());
        Ok(())
    }

    fn build_native_paths(&self) -> Result<cf::CFMutableArrayRef> {
        let native_paths = unsafe {
            cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks)
        };

        if native_paths == std::ptr::null_mut() {
            Err(Error {
                msg: "Unable to allocate CFMutableArrayRef".to_string(),
            })
        } else {
            for path in &self.paths {
                unsafe {
                    let mut err = ptr::null_mut();
                    let cf_path = cf::str_path_to_cfstring_ref(path, &mut err);
                    if !err.is_null() {
                        let cf_str = cf::CFCopyDescription(err as cf::CFRef);
                        let mut buf = [0; 1024];
                        cf::CFStringGetCString(
                            cf_str,
                            buf.as_mut_ptr(),
                            buf.len() as cf::CFIndex,
                            cf::kCFStringEncodingUTF8,
                        );
                        return Err(Error {
                            msg: CStr::from_ptr(buf.as_ptr())
                                .to_str()
                                .unwrap_or("Unknown error")
                                .to_string(),
                        });
                    } else {
                        cf::CFArrayAppendValue(native_paths, cf_path);
                        cf::CFRelease(cf_path);
                    }
                }
            }

            Ok(native_paths)
        }
    }

    fn internal_observe(
        since_when: fs::FSEventStreamEventId,
        latency: cf::CFTimeInterval,
        flags: fs::FSEventStreamCreateFlags,
        paths: FsEventRefWrapper,
        event_sender: Sender<Event>,
        subscription_handle_sender: Option<Sender<FsEventRefWrapper>>,
    ) -> Result<()> {
        let stream_context = default_stream_context(&event_sender);
        let paths = paths.into();

        unsafe {
            let stream = fs::FSEventStreamCreate(
                cf::kCFAllocatorDefault,
                callback,
                &stream_context,
                paths,
                since_when,
                latency,
                flags,
            );

            // fs::FSEventStreamShow(stream);

            match subscription_handle_sender {
                Some(ret_tx) => {
                    let runloop_ref = cf::CFRunLoopGetCurrent();
                    let runloop_ref_safe = FsEventRefWrapper::from(runloop_ref);
                    let ptr_val = runloop_ref_safe.ptr.clone();
                    ret_tx
                        .send(runloop_ref_safe)
                        .expect(&format!("Unable to return CFRunLoopRef ({:#X})", ptr_val));
                }
                None => {}
            }

            fs::FSEventStreamScheduleWithRunLoop(
                stream,
                cf::CFRunLoopGetCurrent(),
                cf::kCFRunLoopDefaultMode,
            );

            fs::FSEventStreamStart(stream);
            cf::CFRunLoopRun();

            fs::FSEventStreamFlushSync(stream);
            fs::FSEventStreamStop(stream);
        }

        Ok(())
    }

    pub fn observe(&self, event_sender: Sender<Event>) {
        let native_paths = self
            .build_native_paths()
            .expect("Unable to build CFMutableArrayRef of watched paths.");
        let safe_native_paths = FsEventRefWrapper::from(native_paths);
        Self::internal_observe(
            self.since_when,
            self.latency,
            self.flags,
            safe_native_paths,
            event_sender,
            None,
        )
        .unwrap();
    }

    pub fn observe_async(&self, event_sender: Sender<Event>) -> Result<FsEventRefWrapper> {
        let (ret_tx, ret_rx) = std::sync::mpsc::channel();
        let native_paths = self.build_native_paths()?;
        let safe_native_paths = FsEventRefWrapper::from(native_paths);

        let since_when = self.since_when;
        let latency = self.latency;
        let flags = self.flags;
        std::thread::spawn(move || {
            Self::internal_observe(
                since_when,
                latency,
                flags,
                safe_native_paths,
                event_sender,
                Some(ret_tx),
            )
        });

        match ret_rx.recv_timeout(std::time::Duration::from_secs(5)) {
            Ok(v) => Ok(v),
            Err(e) => Err(Error::from(e)),
        }
    }

    pub fn shutdown_observe(&self, handle: FsEventRefWrapper) {
        unsafe { cf::CFRunLoopStop(handle.into()) };
    }
}

extern "C" fn callback(
    _stream_ref: fs::FSEventStreamRef,
    info: *mut c_void,
    num_events: usize,                               // size_t numEvents
    event_paths: *mut c_void,                        // void *eventPaths
    event_flags: *const fs::FSEventStreamEventFlags, // const FSEventStreamEventFlags eventFlags[]
    event_ids: *const fs::FSEventStreamEventId,      // const FSEventStreamEventId eventIds[]
) {
    unsafe {
        let event_paths = event_paths as *const *const c_char;
        let sender = info as *mut Sender<Event>;

        for pos in 0..num_events {
            let path = CStr::from_ptr(*event_paths.add(pos))
                .to_str()
                .expect("Invalid UTF8 string.");
            let flag = *event_flags.add(pos);
            let event_id = *event_ids.add(pos);

            let event = Event {
                event_id: event_id,
                flag: StreamFlags::from_bits(flag).unwrap_or_else(|| {
                    panic!("Unable to decode StreamFlags: {} for {}", flag, path)
                }),
                path: path.to_string(),
            };
            let _s = (*sender).send(event);
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "phant"]

extern crate url;

use std::collections::hashmap::HashMap;
use std::io::TcpStream;

/// A structure which holds the data for a Phant data stream
///
/// # Example
/// ```
/// let mut phant = phant::Phant::new("data.sparkfun.com", "123abc", "456def");
///
/// phant.add("computer_name", "my-computer");
/// phant.add("external_ip", "123.321.111.222");
/// phant.add("internal_ip", "192.168.1.104");
///
/// phant.push().ok().expect("Pushing to server did not succeed");
/// ```

#[deriving(Show)]
pub struct Phant {
    pub hostname: String,
    pub public_key: String,
    pub private_key: String,
    pub data: HashMap<String, String>
}

impl Phant {
    pub fn new(hostname: &str, public_key: &str, private_key: &str) -> Phant {
        Phant {
            hostname: String::from_str(hostname),
            public_key: String::from_str(public_key),
            private_key: String::from_str(private_key),
            data: HashMap::new()
        }
    }

    /// Adds a key-value pair to the current phant dataset.  The `key` is the
    /// phant column name.  The `value` is a `.to_string()`-able data item. This function
    /// does not manipulate server data.
    pub fn add<T: ToString>(&mut self, key: &str, value: T) {
        self.data.insert(key.to_string(), value.to_string());
    }

    /// Pushes data to the server. All the data that has been `add`ed will be pushed as a row
    /// to the phant server located at `hostname`. The local row will then be cleared so `add`
    /// can be called again to repeat the process.
    ///
    /// Returns an [IoResult](http://doc.rust-lang.org/std/io/type.IoResult.html) where a successful
    /// push will return the response from the server in `String` form.
    pub fn push(&mut self) -> std::io::IoResult<String> {
        let query_string = self.data_query_string();
        let request: String = format!("POST /input/{} HTTP/1.0\nPhant-Private-Key: {}\nContent-Type: application/x-www-form-urlencoded\nContent-Length: {}\n\n{}\n\n",
            self.public_key, self.private_key, query_string.len(), query_string);
        let mut socket = try!(TcpStream::connect(self.hostname.as_slice(), 80));
        try!(socket.write_str(request.as_slice()));
        let result = try!(socket.read_to_string());
        self.clear_local();
        Ok(result)
    }

    /// Clears the data locally.  Any key-value pairs that have been added since creation or
    /// previous clear will be removed.
    pub fn clear_local(&mut self) {
        self.data.clear();
    }

    /// Clears the data on the server.
    pub fn clear_server(&mut self) -> std::io::IoResult<String> {
        let request: String = format!("DELETE /input/{} HTTP/1.0\nPhant-Private-Key: {}\n\n", self.public_key, self.private_key);
        let mut socket = TcpStream::connect(self.hostname.as_slice(), 80).unwrap();
        try!(socket.write_str(request.as_slice()));
        socket.read_to_string()
    }

    /// Gets a formatted URL in string form for adding the current row to the server.
    /// Local data is _not_ cleared, unlike the `push()` method.
    ///
    /// # Example
    /// ```
    /// let mut phant = phant::Phant::new("data.sparkfun.com".to_string(), "123abc", "456def");
    ///
    /// phant.add("apple_color", "red");
    /// let url = phant.get_url();
    /// assert!(url.as_slice() == "http://data.sparkfun.com/input/123abc?private_key=456def&apple_color=red")
    /// ```
    pub fn get_url(&self) -> String {
        format!("http://{}/input/{}?private_key={}&{}", self.hostname, self.public_key, self.private_key, self.data_query_string())
    }

    fn data_query_string(&self) -> String {
        let mut result_list = Vec::new();
        for (key, value) in self.data.iter() {
            result_list.push(format!("{}={}", key, value));
        }
        url::encode(result_list.connect("&"))
    }
}
<commit_msg>modified access modifiers for the Phant struct and added the row_data() function<commit_after>#![crate_name = "phant"]

extern crate url;

use std::collections::hashmap::HashMap;
use std::io::TcpStream;

/// A structure which holds the data for a Phant data stream
///
/// # Example
/// ```
/// let mut phant = phant::Phant::new("data.sparkfun.com", "123abc", "456def");
///
/// phant.add("computer_name", "my-computer");
/// phant.add("external_ip", "123.321.111.222");
/// phant.add("internal_ip", "192.168.1.104");
///
/// phant.push().ok().expect("Pushing to server did not succeed");
/// ```

#[deriving(Show)]
pub struct Phant {
    hostname: String,
    public_key: String,
    private_key: String,
    data: HashMap<String, String>
}

impl Phant {
    pub fn new(hostname: &str, public_key: &str, private_key: &str) -> Phant {
        Phant {
            hostname: String::from_str(hostname),
            public_key: String::from_str(public_key),
            private_key: String::from_str(private_key),
            data: HashMap::new()
        }
    }

    /// Adds a key-value pair to the current phant dataset.  The `key` is the
    /// phant column name.  The `value` is a `.to_string()`-able data item. This function
    /// does not manipulate server data.
    pub fn add<T: ToString>(&mut self, key: &str, value: T) {
        self.data.insert(key.to_string(), value.to_string());
    }

    /// Pushes data to the server. All the data that has been `add`ed will be pushed as a row
    /// to the phant server located at `hostname`. The local row will then be cleared so `add`
    /// can be called again to repeat the process.
    ///
    /// Returns an [IoResult](http://doc.rust-lang.org/std/io/type.IoResult.html) where a successful
    /// push will return the response from the server in `String` form.
    pub fn push(&mut self) -> std::io::IoResult<String> {
        let query_string = self.data_query_string();
        let request: String = format!("POST /input/{} HTTP/1.0\nPhant-Private-Key: {}\nContent-Type: application/x-www-form-urlencoded\nContent-Length: {}\n\n{}\n\n",
            self.public_key, self.private_key, query_string.len(), query_string);
        let mut socket = try!(TcpStream::connect(self.hostname.as_slice(), 80));
        try!(socket.write_str(request.as_slice()));
        let result = try!(socket.read_to_string());
        self.clear_local();
        Ok(result)
    }

    /// Clears the data locally.  Any key-value pairs that have been added since creation or
    /// previous clear will be removed.
    pub fn clear_local(&mut self) {
        self.data.clear();
    }

    /// Clears the data on the server.
    pub fn clear_server(&mut self) -> std::io::IoResult<String> {
        let request: String = format!("DELETE /input/{} HTTP/1.0\nPhant-Private-Key: {}\n\n", self.public_key, self.private_key);
        let mut socket = TcpStream::connect(self.hostname.as_slice(), 80).unwrap();
        try!(socket.write_str(request.as_slice()));
        socket.read_to_string()
    }

    /// Gets a formatted URL in string form for adding the current row to the server.
    /// Local data is _not_ cleared, unlike the `push()` method.
    ///
    /// # Example
    /// ```
    /// let mut phant = phant::Phant::new("data.sparkfun.com".to_string(), "123abc", "456def");
    ///
    /// phant.add("apple_color", "red");
    /// let url = phant.get_url();
    /// assert!(url.as_slice() == "http://data.sparkfun.com/input/123abc?private_key=456def&apple_color=red")
    /// ```
    pub fn get_url(&self) -> String {
        format!("http://{}/input/{}?private_key={}&{}", self.hostname, self.public_key, self.private_key, self.data_query_string())
    }

    /// Returns a clone of the data for the current row being added to. Notice: it's a
    /// clone, so manipulations done to this returned object will _not_ modify the
    /// data being held locally in the `Phant` object.
    pub fn row_data(&self) -> HashMap<String, String> {
        self.data.clone()
    }

    fn data_query_string(&self) -> String {
        let mut result_list = Vec::new();
        for (key, value) in self.data.iter() {
            result_list.push(format!("{}={}", key, value));
        }
        url::encode(result_list.connect("&"))
    }
}
<|endoftext|>


<commit_before>#![feature(default_type_params, unsafe_destructor, globs)]
#![cfg_attr(not(test), no_std)]

//! Thread-local and thread-safe shared slice types, like `&[T]` but
//! without lifetimes.
//!
//! This library depends only on `alloc` and `core`, so can be used in
//! environments without `std`.
//!
//! # Examples
//!
//! Alice has a long list of numbers of which she needs to know the sum before
//! she's allowed to enter Wonderland. She's impatient to get there and she has
//! a computer with many cores so she wants to use all of them.
//!
//! Using a `ArcSlice`, she can manually divide up the numbers into
//! chunks and distribute them across some threads.
//!
//! ```rust
//! use shared_slice::arc::ArcSlice;
//! use std::{cmp, rand, sync};
//!
//! // Alice's numbers (the Mad Hatter doesn't care which numbers,
//! // just that they've been summed up).
//! let numbers = range(0u, 10_000)
//!     .map(|_| rand::random::<u64>() % 100)
//!     .collect::<Vec<_>>();
//!
//!
//! const NTHREADS: uint = 10;
//!
//! let numbers = ArcSlice::new(numbers.into_boxed_slice());
//!
//! // number of elements per thread (rounded up)
//! let per_thread = (numbers.len() + NTHREADS - 1) / NTHREADS;
//!
//! let mut futures = range(0, NTHREADS).map(|i| {
//!     // compute the bounds
//!     let lo = i * per_thread;
//!     let hi = cmp::min(numbers.len(), lo + per_thread);
//!
//!     // extract the subsection of the vector that we care about,
//!     // note that the `clone` (which just increases the reference
//!     // counts) is necessary because `ArcSlice::slice` consumes
//!     // the receiver (in order to minimise unnecessary reference
//!     // count modifications).
//!     let my_numbers: ArcSlice<_> = numbers.clone().slice(lo, hi);
//!
//!     // do this part of the sum:
//!     sync::Future::spawn(move || {
//!         my_numbers.iter().fold(0, |a, &b| a + b)
//!     })
//! }).collect::<Vec<sync::Future<u64>>>();
//!
//! // sum up the results from each subsum.
//! let sum = futures.iter_mut().fold(0, |a, b| a + b.get());
//!
//! println!("the sum is {}", sum);
//! ```
//!
//! (NB. `ArcSlice` may become unnecessary for situations like this if
//! [`Send` stops implying
//! `'static`](https://github.com/rust-lang/rfcs/pull/458), since it
//! is likely that one will be able to use conventional borrowed
//! `&[T]` slices directly.)

extern crate alloc;
extern crate core;

pub mod rc;
pub mod arc;
<commit_msg>Tweak doc wording.<commit_after>#![feature(default_type_params, unsafe_destructor, globs)]
#![cfg_attr(not(test), no_std)]

//! Thread-local and thread-safe shared slice types, like `&[T]` but
//! without lifetimes.
//!
//! This library depends only on `alloc` and `core`, so can be used in
//! environments without `std`.
//!
//! # Examples
//!
//! Alice has a long list of numbers which she needs to sum up before
//! she's allowed to enter Wonderland. She's impatient to get there
//! and she has a computer with many cores so she wants to use all of
//! them.
//!
//! Using a `ArcSlice`, she can manually divide up the numbers into
//! chunks and distribute them across some threads.
//!
//! ```rust
//! use shared_slice::arc::ArcSlice;
//! use std::{cmp, rand, sync};
//!
//! // Alice's numbers (the Mad Hatter doesn't care which numbers,
//! // just that they've been summed up).
//! let numbers = range(0u, 10_000)
//!     .map(|_| rand::random::<u64>() % 100)
//!     .collect::<Vec<_>>();
//!
//!
//! const NTHREADS: uint = 10;
//!
//! let numbers = ArcSlice::new(numbers.into_boxed_slice());
//!
//! // number of elements per thread (rounded up)
//! let per_thread = (numbers.len() + NTHREADS - 1) / NTHREADS;
//!
//! let mut futures = range(0, NTHREADS).map(|i| {
//!     // compute the bounds
//!     let lo = i * per_thread;
//!     let hi = cmp::min(numbers.len(), lo + per_thread);
//!
//!     // extract the subsection of the vector that we care about,
//!     // note that the `clone` (which just increases the reference
//!     // counts) is necessary because `ArcSlice::slice` consumes
//!     // the receiver (in order to minimise unnecessary reference
//!     // count modifications).
//!     let my_numbers: ArcSlice<_> = numbers.clone().slice(lo, hi);
//!
//!     // do this part of the sum:
//!     sync::Future::spawn(move || {
//!         my_numbers.iter().fold(0, |a, &b| a + b)
//!     })
//! }).collect::<Vec<sync::Future<u64>>>();
//!
//! // sum up the results from each subsum.
//! let sum = futures.iter_mut().fold(0, |a, b| a + b.get());
//!
//! println!("the sum is {}", sum);
//! ```
//!
//! (NB. `ArcSlice` may become unnecessary for situations like this if
//! [`Send` stops implying
//! `'static`](https://github.com/rust-lang/rfcs/pull/458), since it
//! is likely that one will be able to use conventional borrowed
//! `&[T]` slices directly.)

extern crate alloc;
extern crate core;

pub mod rc;
pub mod arc;
<|endoftext|>


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

fn materialise<T, I: Iterator<Item=T>>(iter: I) -> Vec<T> {
    let mut dest = Vec::new();
    dest.extend(iter);

    dest
}

pub fn distance<T, I: Iterator<Item=T>>(left_stream: I, right_stream: I) -> usize
    where T: Eq {
        let left  = materialise(left_stream);
        let right = materialise(right_stream);

        let width = left.len() + 1;
        let depth = right.len() + 1;

        let mut current  = vec![0; width];
        let mut previous = vec![0; width];

        for i in 0..width {
            previous[i] = i;
        }

        current[0] = previous[0] + 1;

        for row in 1..depth {
            for column in 1..width {
                if left[column - 1] == right[row - 1] {
                    current[column] = previous[column - 1];
                } else {
                    let above = previous[column]     + 1;
                    let diag  = previous[column - 1] + 1;
                    let aside = current [column - 1] + 1;

                    current[column] = *[above, diag, aside]
                        .iter()
                        .min()
                        .unwrap();
                }
            }

            previous = current.clone();
            current = vec![0; width];
            current[0] = row+1;
        }

        previous[width-1]
    }
<commit_msg>we don't actually need to allocate this, either (saves anothe few % points)<commit_after>#![crate_name = "editdistancewf"]
#![crate_type = "lib"]

fn materialise<T, I: Iterator<Item=T>>(iter: I) -> Vec<T> {
    let mut dest = Vec::new();
    dest.extend(iter);

    dest
}

pub fn distance<T, I: Iterator<Item=T>>(left_stream: I, right_stream: I) -> usize
    where T: Eq {
        let left  = materialise(left_stream);
        let right = materialise(right_stream);

        let width = left.len() + 1;
        let depth = right.len() + 1;

        let mut current  = vec![0; width];
        let mut previous = vec![0; width];

        for i in 0..width {
            previous[i] = i;
        }

        current[0] = previous[0] + 1;

        for row in 1..depth {
            for column in 1..width {
                if left[column - 1] == right[row - 1] {
                    current[column] = previous[column - 1];
                } else {
                    let above = previous[column]     + 1;
                    let diag  = previous[column - 1] + 1;
                    let aside = current [column - 1] + 1;

                    current[column] = *[above, diag, aside]
                        .iter()
                        .min()
                        .unwrap();
                }
            }

            previous = current.clone();
            current[0] = row+1;
        }

        previous[width-1]
    }
<|endoftext|>


<commit_before>//! This crate contains the EnergyMonitor trait.
//! A dummy implementation is included in the `dummy` module.

pub mod dummy;

/// An energy monitor typically reads from an internal or external sensor.
/// It could also estimate energy consumption using hardware counters or other heuristics.
pub trait EnergyMonitor {
    /// Read the energy value in microjoules
    fn read_uj(&self) -> Result<u64, &'static str>;

    /// Get the energy monitoring source as a String
    fn source(&self) -> String;

    /// Get the energy monitor's refresh interval in microseconds.
    /// This cna be used as a minimum polling period.
    fn interval_us(&self) -> u64;
}
<commit_msg>Fix typo<commit_after>//! This crate contains the EnergyMonitor trait.
//! A dummy implementation is included in the `dummy` module.

pub mod dummy;

/// An energy monitor typically reads from an internal or external sensor.
/// It could also estimate energy consumption using hardware counters or other heuristics.
pub trait EnergyMonitor {
    /// Read the energy value in microjoules
    fn read_uj(&self) -> Result<u64, &'static str>;

    /// Get the energy monitoring source as a String
    fn source(&self) -> String;

    /// Get the energy monitor's refresh interval in microseconds.
    /// This can be used as a minimum polling period.
    fn interval_us(&self) -> u64;
}
<|endoftext|>


<commit_before>// Filebuffer -- Fast and simple file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Filebuffer, a library for fast and simple file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as a slice of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`.
//!
//! ```
//! use filebuffer::FileBuffer;
//! let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
//! assert_eq!(&fbuffer[3..45], &b"Filebuffer -- Fast and simple file reading"[..]);
//! ```

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::ops::Deref;
use std::path::Path;
use std::ptr;
use std::slice;

#[cfg(unix)]
mod unix;

#[cfg(windows)]
mod windows;

#[cfg(target_os = "macos")]
mod macos;

#[cfg(unix)]
use unix::{PlatformData, get_page_size, map_file, unmap_file, prefetch};

#[cfg(all(unix, not(target_os = "macos")))]
use unix::get_resident;

#[cfg(target_os = "macos")]
use macos::get_resident;

#[cfg(windows)]
use windows::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

/// A memory-mapped file.
///
/// # Safety
///
/// **On Unix-ish platforms, external modifications to the file made after the file buffer was
/// opened can show up in this file buffer.** In particular, if a file is truncated after opening,
/// accessing the removed part causes undefined behavior. On Windows it is possible to prevent this
/// by opening the file in exclusive mode, but that functionality is not available in stable Rust
/// currently. (Filebuffer will be updated after stabilization.)
///
/// It is recommended to ensure that other applications do not write to the file when it is mapped,
/// possibly by marking the file read-only. (Though even this is no guarantee.)
#[derive(Debug)]
pub struct FileBuffer {
    page_size: usize,
    buffer: *const u8,
    length: usize,

    #[allow(dead_code)] // This field is not dead, it might have an effectful destructor.
    platform_data: PlatformData,
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl FileBuffer {
    /// Maps the file at `path` into memory.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<FileBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when `map_file` returns on
        // Unix-ish platforms, but `mmap` only requires the descriptor to be open for the `mmap`
        // call, so this is fine. On Windows, the file must be kept open for the lifetime of the
        // mapping, so `map_file` moves the file into the platform data.
        let mut open_opts = fs::OpenOptions::new();
        open_opts.read(true);

        // TODO: On Windows, set `share_mode()` to read-only. This requires the
        // `open_options_ext` feature that is currently unstable, but it is
        // required to ensure that a different process does not suddenly modify
        // the contents of the file. See also Rust issue 27720.

        let file = try!(open_opts.open(path));
        let (buffer, length, platform_data) = try!(map_file(file));
        let fbuffer = FileBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
            platform_data: platform_data
        };
        Ok(fbuffer)
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    ///
    /// # Remarks
    ///
    /// Windows does not expose a mechanism to query which pages are resident in physical
    /// memory. Therefore this function optimistically claims that the entire range is resident
    /// on Windows.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return 0; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }

    /// Returns the system page size.
    ///
    /// When the kernel makes the file resident in physical memory, it does so with page
    /// granularity. (In practice this happens in larger chunks, but still in multiples of
    /// the page size.) Therefore, when processing the file in chunks, this is a good chunk
    /// length.
    pub fn chunk_len_hint(&self) -> usize {
        self.page_size
    }

    /// Advises the kernel to make a slice of the file resident in physical memory.
    ///
    /// This method does not block, meaning that when the function returns, the slice is not
    /// necessarily resident. After this function returns, the kernel may read the requested slice
    /// from disk and make it resident. Note that this is only an advice, the kernel need not honor
    /// it.
    ///
    /// To check whether the slice is resident at a later time, use `resident_len()`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn prefetch(&self, offset: usize, length: usize) {
        // TODO: This function should use `collections::range::RangeArgument` once stabilized.
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);

        let buffer = unsafe { self.buffer.offset(aligned_offset as isize) };
        prefetch(buffer, aligned_length);
    }

    /// Leaks the file buffer as a byte slice.
    ///
    /// This prevents the buffer from being unmapped, keeping the file mapped until the program
    /// ends. This is not as bad as it sounds, because the kernel is free to evict pages from
    /// physical memory in case of memory pressure. Because the file is mapped read-only, it can
    /// always be read from disk again.
    ///
    /// If the file buffer is going to be open for the entire duration of the program anyway, this
    /// method can avoid some lifetime issues. Still, it is good practice to close the file buffer
    /// if possible. This method should be a last resort.
    pub fn leak(mut self) -> &'static [u8] {
        let buffer = unsafe { slice::from_raw_parts(self.buffer, self.length) };

        // Prevent `drop()` from freeing the buffer.
        self.buffer = ptr::null();
        self.length = 0;

        buffer
    }
}

// There is no possibility of data races when passing `&FileBuffer` across threads,
// because the buffer is read-only. `&FileBuffer` has no interior mutability.
unsafe impl Sync for FileBuffer {}

// It is safe to move a `FileBuffer` into a different thread.
unsafe impl Send for FileBuffer {}

impl Drop for FileBuffer {
    fn drop(&mut self) {
        if self.buffer != ptr::null() { unmap_file(self.buffer, self.length); }
    }
}

impl Deref for FileBuffer {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }
}

#[test]
fn open_file() {
    let fbuffer = FileBuffer::open("src/lib.rs");
    assert!(fbuffer.is_ok());
}

#[test]
fn make_resident() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fbuffer.resident_len(3, 10), 10);
}

#[test]
fn prefetch_is_not_harmful() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // It is impossible to test that this actually works without root access to instruct the kernel
    // to drop its caches, but at least we can verify that calling `prefetch` is not harmful.
    fbuffer.prefetch(0, fbuffer.len());

    // Reading from the file should still work as normal.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
}

#[test]
fn drop_after_leak() {
    let mut bytes = &[0u8][..];
    assert_eq!(bytes[0], 0);
    {
        let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
        bytes = fbuffer.leak();
    }
    assert_eq!(&bytes[3..13], &b"Filebuffer"[..]);
}

#[test]
fn fbuffer_can_be_moved_into_thread() {
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    thread::spawn(move || {
        assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
    });
}

#[test]
fn fbuffer_can_be_shared_among_threads() {
    use std::sync;
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    let buffer1 = sync::Arc::new(fbuffer);
    let buffer2 = buffer1.clone();
    thread::spawn(move || {
        assert_eq!(&buffer2[3..13], &b"Filebuffer"[..]);
    });
    assert_eq!(&buffer1[17..45], &b"Fast and simple file reading"[..]);
}

#[test]
fn open_empty_file_is_fine() {
    FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
}

#[test]
fn empty_file_prefetch_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    fbuffer.prefetch(0, 0);
}

#[test]
fn empty_file_deref_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.iter().any(|_| true), false);
}

#[test]
fn empty_file_has_zero_resident_len() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.resident_len(0, 0), 0);
}

#[test]
fn page_size_at_least_4096() {
    // There is no reason why the page size cannot be smaller, it is just that in practice there
    // is no platform with a smaller page size, so this tests that `get_page_size()` returns
    // a plausible value.
    assert!(get_page_size() >= 4096);
}
<commit_msg>Implement AsRef<[u8]> for FileBuffer<commit_after>// Filebuffer -- Fast and simple file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Filebuffer, a library for fast and simple file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as a slice of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`.
//!
//! ```
//! use filebuffer::FileBuffer;
//! let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
//! assert_eq!(&fbuffer[3..45], &b"Filebuffer -- Fast and simple file reading"[..]);
//! ```

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::ops::Deref;
use std::path::Path;
use std::ptr;
use std::slice;

#[cfg(unix)]
mod unix;

#[cfg(windows)]
mod windows;

#[cfg(target_os = "macos")]
mod macos;

#[cfg(unix)]
use unix::{PlatformData, get_page_size, map_file, unmap_file, prefetch};

#[cfg(all(unix, not(target_os = "macos")))]
use unix::get_resident;

#[cfg(target_os = "macos")]
use macos::get_resident;

#[cfg(windows)]
use windows::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

/// A memory-mapped file.
///
/// # Safety
///
/// **On Unix-ish platforms, external modifications to the file made after the file buffer was
/// opened can show up in this file buffer.** In particular, if a file is truncated after opening,
/// accessing the removed part causes undefined behavior. On Windows it is possible to prevent this
/// by opening the file in exclusive mode, but that functionality is not available in stable Rust
/// currently. (Filebuffer will be updated after stabilization.)
///
/// It is recommended to ensure that other applications do not write to the file when it is mapped,
/// possibly by marking the file read-only. (Though even this is no guarantee.)
#[derive(Debug)]
pub struct FileBuffer {
    page_size: usize,
    buffer: *const u8,
    length: usize,

    #[allow(dead_code)] // This field is not dead, it might have an effectful destructor.
    platform_data: PlatformData,
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl FileBuffer {
    /// Maps the file at `path` into memory.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<FileBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when `map_file` returns on
        // Unix-ish platforms, but `mmap` only requires the descriptor to be open for the `mmap`
        // call, so this is fine. On Windows, the file must be kept open for the lifetime of the
        // mapping, so `map_file` moves the file into the platform data.
        let mut open_opts = fs::OpenOptions::new();
        open_opts.read(true);

        // TODO: On Windows, set `share_mode()` to read-only. This requires the
        // `open_options_ext` feature that is currently unstable, but it is
        // required to ensure that a different process does not suddenly modify
        // the contents of the file. See also Rust issue 27720.

        let file = try!(open_opts.open(path));
        let (buffer, length, platform_data) = try!(map_file(file));
        let fbuffer = FileBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
            platform_data: platform_data
        };
        Ok(fbuffer)
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    ///
    /// # Remarks
    ///
    /// Windows does not expose a mechanism to query which pages are resident in physical
    /// memory. Therefore this function optimistically claims that the entire range is resident
    /// on Windows.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return 0; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }

    /// Returns the system page size.
    ///
    /// When the kernel makes the file resident in physical memory, it does so with page
    /// granularity. (In practice this happens in larger chunks, but still in multiples of
    /// the page size.) Therefore, when processing the file in chunks, this is a good chunk
    /// length.
    pub fn chunk_len_hint(&self) -> usize {
        self.page_size
    }

    /// Advises the kernel to make a slice of the file resident in physical memory.
    ///
    /// This method does not block, meaning that when the function returns, the slice is not
    /// necessarily resident. After this function returns, the kernel may read the requested slice
    /// from disk and make it resident. Note that this is only an advice, the kernel need not honor
    /// it.
    ///
    /// To check whether the slice is resident at a later time, use `resident_len()`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn prefetch(&self, offset: usize, length: usize) {
        // TODO: This function should use `collections::range::RangeArgument` once stabilized.
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);

        let buffer = unsafe { self.buffer.offset(aligned_offset as isize) };
        prefetch(buffer, aligned_length);
    }

    /// Leaks the file buffer as a byte slice.
    ///
    /// This prevents the buffer from being unmapped, keeping the file mapped until the program
    /// ends. This is not as bad as it sounds, because the kernel is free to evict pages from
    /// physical memory in case of memory pressure. Because the file is mapped read-only, it can
    /// always be read from disk again.
    ///
    /// If the file buffer is going to be open for the entire duration of the program anyway, this
    /// method can avoid some lifetime issues. Still, it is good practice to close the file buffer
    /// if possible. This method should be a last resort.
    pub fn leak(mut self) -> &'static [u8] {
        let buffer = unsafe { slice::from_raw_parts(self.buffer, self.length) };

        // Prevent `drop()` from freeing the buffer.
        self.buffer = ptr::null();
        self.length = 0;

        buffer
    }
}

// There is no possibility of data races when passing `&FileBuffer` across threads,
// because the buffer is read-only. `&FileBuffer` has no interior mutability.
unsafe impl Sync for FileBuffer {}

// It is safe to move a `FileBuffer` into a different thread.
unsafe impl Send for FileBuffer {}

impl Drop for FileBuffer {
    fn drop(&mut self) {
        if self.buffer != ptr::null() { unmap_file(self.buffer, self.length); }
    }
}

impl Deref for FileBuffer {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }
}

impl AsRef<[u8]> for FileBuffer {
    fn as_ref(&self) -> &[u8] {
        self.deref()
    }
}

#[test]
fn open_file() {
    let fbuffer = FileBuffer::open("src/lib.rs");
    assert!(fbuffer.is_ok());
}

#[test]
fn make_resident() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fbuffer.resident_len(3, 10), 10);
}

#[test]
fn prefetch_is_not_harmful() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // It is impossible to test that this actually works without root access to instruct the kernel
    // to drop its caches, but at least we can verify that calling `prefetch` is not harmful.
    fbuffer.prefetch(0, fbuffer.len());

    // Reading from the file should still work as normal.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
}

#[test]
fn drop_after_leak() {
    let mut bytes = &[0u8][..];
    assert_eq!(bytes[0], 0);
    {
        let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
        bytes = fbuffer.leak();
    }
    assert_eq!(&bytes[3..13], &b"Filebuffer"[..]);
}

#[test]
fn fbuffer_can_be_moved_into_thread() {
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    thread::spawn(move || {
        assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
    });
}

#[test]
fn fbuffer_can_be_shared_among_threads() {
    use std::sync;
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    let buffer1 = sync::Arc::new(fbuffer);
    let buffer2 = buffer1.clone();
    thread::spawn(move || {
        assert_eq!(&buffer2[3..13], &b"Filebuffer"[..]);
    });
    assert_eq!(&buffer1[17..45], &b"Fast and simple file reading"[..]);
}

#[test]
fn open_empty_file_is_fine() {
    FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
}

#[test]
fn empty_file_prefetch_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    fbuffer.prefetch(0, 0);
}

#[test]
fn empty_file_deref_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.iter().any(|_| true), false);
}

#[test]
fn empty_file_has_zero_resident_len() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.resident_len(0, 0), 0);
}

#[test]
fn page_size_at_least_4096() {
    // There is no reason why the page size cannot be smaller, it is just that in practice there
    // is no platform with a smaller page size, so this tests that `get_page_size()` returns
    // a plausible value.
    assert!(get_page_size() >= 4096);
}
<|endoftext|>