<commit_before>use std::ops::Deref;

use crate::*;

/// The `sled` embedded database!
#[derive(Clone)]
pub struct Db {
    context: Context,
    pub(crate) default: Tree,
    tenants: Arc<RwLock<FastMap8<Vec<u8>, Tree>>>,
}

#[allow(unsafe_code)]
unsafe impl Send for Db {}

#[allow(unsafe_code)]
unsafe impl Sync for Db {}

impl Deref for Db {
    type Target = Tree;

    fn deref(&self) -> &Tree {
        &self.default
    }
}

impl Debug for Db {
    fn fmt(
        &self,
        f: &mut fmt::Formatter<'_>,
    ) -> std::result::Result<(), fmt::Error> {
        let tenants = self.tenants.read();
        writeln!(f, "Db {{")?;
        for (raw_name, tree) in tenants.iter() {
            let name = std::str::from_utf8(&raw_name)
                .ok()
                .map_or_else(|| format!("{:?}", raw_name), String::from);
            write!(f, "    Tree: {:?} contents: {:?}", name, tree)?;
        }
        write!(f, "}}")?;
        Ok(())
    }
}

impl Db {
    /// Load existing or create a new `Db` with a default configuration.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use sled::Db;
    ///
    /// let t = Db::open("my_db").unwrap();
    /// ```
    pub fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
        Config::new().path(path).open()
    }

    #[doc(hidden)]
    #[deprecated(since = "0.24.2", note = "replaced by `Db:open`")]
    pub fn start_default<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
        Self::open(path)
    }

    #[doc(hidden)]
    #[deprecated(
        since = "0.29.0",
        note = "please use ConfigBuilder::open instead"
    )]
    pub fn start(config: RunningConfig) -> Result<Self> {
        Db::start_inner(config)
    }

    pub(crate) fn start_inner(config: RunningConfig) -> Result<Self> {
        let _measure = Measure::new(&M.tree_start);

        let context = Context::start(config)?;

        #[cfg(any(windows, target_os = "linux", target_os = "macos"))]
        {
            if !context.read_only {
                let flusher_pagecache = context.pagecache.clone();
                let flusher = context.flush_every_ms.map(move |fem| {
                    flusher::Flusher::new(
                        "log flusher".to_owned(),
                        flusher_pagecache,
                        fem,
                    )
                });
                *context._flusher.lock() = flusher;
            }
        }

        // create or open the default tree
        let guard = pin();
        let default =
            meta::open_tree(&context, DEFAULT_TREE_ID.to_vec(), &guard)?;

        let ret = Self {
            context: context.clone(),
            default,
            tenants: Arc::new(RwLock::new(FastMap8::default())),
        };

        let mut tenants = ret.tenants.write();

        for (id, root) in context.pagecache.meta(&guard)?.tenants() {
            let tree = Tree(Arc::new(TreeInner {
                tree_id: id.clone(),
                subscriptions: Subscriptions::default(),
                context: context.clone(),
                root: AtomicU64::new(root),
                concurrency_control: RwLock::new(()),
                merge_operator: RwLock::new(None),
            }));
            assert!(tenants.insert(id, tree).is_none());
        }

        drop(tenants);

        Ok(ret)
    }

    /// Open or create a new disk-backed Tree with its own keyspace,
    /// accessible from the `Db` via the provided identifier.
    pub fn open_tree<V: AsRef<[u8]>>(&self, name: V) -> Result<Tree> {
        let name = name.as_ref();
        let tenants = self.tenants.read();
        if let Some(tree) = tenants.get(name) {
            return Ok(tree.clone());
        }
        drop(tenants);

        let guard = pin();

        let mut tenants = self.tenants.write();

        // we need to check this again in case another
        // thread opened it concurrently.
        if let Some(tree) = tenants.get(name) {
            return Ok(tree.clone());
        }

        let tree = meta::open_tree(&self.context, name.to_vec(), &guard)?;

        assert!(tenants.insert(name.to_vec(), tree.clone()).is_none());

        Ok(tree)
    }

    /// Remove a disk-backed collection.
    pub fn drop_tree(&self, name: &[u8]) -> Result<bool> {
        if name == DEFAULT_TREE_ID {
            return Err(Error::Unsupported(
                "cannot remove the core structures".into(),
            ));
        }
        trace!("dropping tree {:?}", name,);

        let mut tenants = self.tenants.write();

        let tree = if let Some(tree) = tenants.remove(&*name) {
            tree
        } else {
            return Ok(false);
        };

        let guard = pin();

        let mut root_id =
            Some(self.context.pagecache.meta_pid_for_name(&name, &guard)?);

        let mut leftmost_chain: Vec<PageId> = vec![root_id.unwrap()];
        let mut cursor = root_id.unwrap();
        while let Some(view) = self.view_for_pid(cursor, &guard)? {
            if let Some(index) = view.data.index_ref() {
                let leftmost_child = index[0].1;
                leftmost_chain.push(leftmost_child);
                cursor = leftmost_child;
            } else {
                break;
            }
        }

        loop {
            let res = self
                .context
                .pagecache
                .cas_root_in_meta(&name, root_id, None, &guard)?;

            if let Err(actual_root) = res {
                root_id = actual_root;
            } else {
                break;
            }
        }

        tree.root.store(u64::max_value(), SeqCst);

        // drop writer lock
        drop(tenants);

        tree.gc_pages(leftmost_chain)?;

        guard.flush();

        Ok(true)
    }

    /// Returns the trees names saved in this Db.
    pub fn tree_names(&self) -> Vec<Vec<u8>> {
        let tenants = self.tenants.read();
        tenants.iter().map(|(name, _)| name.clone()).collect()
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.context.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<u64> {
        self.context.generate_id()
    }

    /// A database export method for all collections in the `Db`,
    /// for use in sled version upgrades. Can be used in combination
    /// with the `import` method below on a database running a later
    /// version.
    ///
    /// # Panics
    ///
    /// Panics if any IO problems occur while trying
    /// to perform the export.
    pub fn export(
        &self,
    ) -> Vec<(CollectionType, CollectionName, impl Iterator<Item = Vec<Vec<u8>>>)>
    {
        let tenants = self.tenants.read();

        let mut ret = vec![];

        for (name, tree) in tenants.iter() {
            ret.push((
                b"tree".to_vec(),
                name.to_vec(),
                tree.iter().map(|kv| {
                    let kv = kv.unwrap();
                    vec![kv.0.to_vec(), kv.1.to_vec()]
                }),
            ));
        }

        ret
    }

    /// Imports the collections from a previous database.
    ///
    /// # Panics
    ///
    /// Panics if any IO problems occur while trying
    /// to perform the import.
    pub fn import(
        &self,
        export: Vec<(
            CollectionType,
            CollectionName,
            impl Iterator<Item = Vec<Vec<u8>>>,
        )>,
    ) {
        for (collection_type, collection_name, collection_iter) in export {
            match collection_type {
                ref t if t == b"tree" => {
                    let tree = self
                        .open_tree(collection_name)
                        .expect("failed to open new tree during import");
                    for mut kv in collection_iter {
                        let v = kv
                            .pop()
                            .expect("failed to get value from tree export");
                        let k = kv
                            .pop()
                            .expect("failed to get key from tree export");
                        let old = tree.insert(k, v).expect(
                            "failed to insert value during tree import",
                        );
                        assert!(
                            old.is_none(),
                            "import is overwriting existing data"
                        );
                    }
                }
                other => panic!("unknown collection type {:?}", other),
            }
        }
    }

    /// Returns the CRC32 of all keys and values
    /// in this Db.
    ///
    /// This is O(N) and locks all underlying Trees
    /// for the duration of the entire scan.
    pub fn checksum(&self) -> Result<u32> {
        let tenants_mu = self.tenants.write();

        // we use a btreemap to ensure lexicographic
        // iteration over tree names to have consistent
        // checksums.
        let tenants: BTreeMap<_, _> = tenants_mu.iter().collect();

        let mut hasher = crc32fast::Hasher::new();
        let mut locks = vec![];

        for (_, tree) in tenants.iter() {
            locks.push(tree.concurrency_control.write());
        }

        for (name, tree) in tenants.iter() {
            hasher.update(name);

            let mut iter = tree.iter();
            let _ = self.concurrency_control.write();
            while let Some(kv_res) = iter.next_inner() {
                let (k, v) = kv_res?;
                hasher.update(&k);
                hasher.update(&v);
            }
        }

        Ok(hasher.finalize())
    }

    /// Traverses all files and calculates their total physical
    /// size, then traverses all pages and calculates their
    /// total logical size, then divides the physical size
    /// by the logical size.
    #[doc(hidden)]
    pub fn space_amplification(&self) -> Result<f64> {
        self.context.pagecache.space_amplification()
    }
}

/// These types provide the information that allows an entire
/// system to be exported and imported to facilitate
/// major upgrades. It is comprised entirely
/// of standard library types to be forward compatible.
/// NB this definitions are expensive to change, because
/// they impact the migration path.
type CollectionType = Vec<u8>;
type CollectionName = Vec<u8>;
<commit_msg>Fix deprecation notice<commit_after>use std::ops::Deref;

use crate::*;

/// The `sled` embedded database!
#[derive(Clone)]
pub struct Db {
    context: Context,
    pub(crate) default: Tree,
    tenants: Arc<RwLock<FastMap8<Vec<u8>, Tree>>>,
}

#[allow(unsafe_code)]
unsafe impl Send for Db {}

#[allow(unsafe_code)]
unsafe impl Sync for Db {}

impl Deref for Db {
    type Target = Tree;

    fn deref(&self) -> &Tree {
        &self.default
    }
}

impl Debug for Db {
    fn fmt(
        &self,
        f: &mut fmt::Formatter<'_>,
    ) -> std::result::Result<(), fmt::Error> {
        let tenants = self.tenants.read();
        writeln!(f, "Db {{")?;
        for (raw_name, tree) in tenants.iter() {
            let name = std::str::from_utf8(&raw_name)
                .ok()
                .map_or_else(|| format!("{:?}", raw_name), String::from);
            write!(f, "    Tree: {:?} contents: {:?}", name, tree)?;
        }
        write!(f, "}}")?;
        Ok(())
    }
}

impl Db {
    /// Load existing or create a new `Db` with a default configuration.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use sled::Db;
    ///
    /// let t = Db::open("my_db").unwrap();
    /// ```
    pub fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
        Config::new().path(path).open()
    }

    #[doc(hidden)]
    #[deprecated(since = "0.24.2", note = "replaced by `Db:open`")]
    pub fn start_default<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
        Self::open(path)
    }

    #[doc(hidden)]
    #[deprecated(since = "0.29.0", note = "please use Config::open instead")]
    pub fn start(config: RunningConfig) -> Result<Self> {
        Db::start_inner(config)
    }

    pub(crate) fn start_inner(config: RunningConfig) -> Result<Self> {
        let _measure = Measure::new(&M.tree_start);

        let context = Context::start(config)?;

        #[cfg(any(windows, target_os = "linux", target_os = "macos"))]
        {
            if !context.read_only {
                let flusher_pagecache = context.pagecache.clone();
                let flusher = context.flush_every_ms.map(move |fem| {
                    flusher::Flusher::new(
                        "log flusher".to_owned(),
                        flusher_pagecache,
                        fem,
                    )
                });
                *context._flusher.lock() = flusher;
            }
        }

        // create or open the default tree
        let guard = pin();
        let default =
            meta::open_tree(&context, DEFAULT_TREE_ID.to_vec(), &guard)?;

        let ret = Self {
            context: context.clone(),
            default,
            tenants: Arc::new(RwLock::new(FastMap8::default())),
        };

        let mut tenants = ret.tenants.write();

        for (id, root) in context.pagecache.meta(&guard)?.tenants() {
            let tree = Tree(Arc::new(TreeInner {
                tree_id: id.clone(),
                subscriptions: Subscriptions::default(),
                context: context.clone(),
                root: AtomicU64::new(root),
                concurrency_control: RwLock::new(()),
                merge_operator: RwLock::new(None),
            }));
            assert!(tenants.insert(id, tree).is_none());
        }

        drop(tenants);

        Ok(ret)
    }

    /// Open or create a new disk-backed Tree with its own keyspace,
    /// accessible from the `Db` via the provided identifier.
    pub fn open_tree<V: AsRef<[u8]>>(&self, name: V) -> Result<Tree> {
        let name = name.as_ref();
        let tenants = self.tenants.read();
        if let Some(tree) = tenants.get(name) {
            return Ok(tree.clone());
        }
        drop(tenants);

        let guard = pin();

        let mut tenants = self.tenants.write();

        // we need to check this again in case another
        // thread opened it concurrently.
        if let Some(tree) = tenants.get(name) {
            return Ok(tree.clone());
        }

        let tree = meta::open_tree(&self.context, name.to_vec(), &guard)?;

        assert!(tenants.insert(name.to_vec(), tree.clone()).is_none());

        Ok(tree)
    }

    /// Remove a disk-backed collection.
    pub fn drop_tree(&self, name: &[u8]) -> Result<bool> {
        if name == DEFAULT_TREE_ID {
            return Err(Error::Unsupported(
                "cannot remove the core structures".into(),
            ));
        }
        trace!("dropping tree {:?}", name,);

        let mut tenants = self.tenants.write();

        let tree = if let Some(tree) = tenants.remove(&*name) {
            tree
        } else {
            return Ok(false);
        };

        let guard = pin();

        let mut root_id =
            Some(self.context.pagecache.meta_pid_for_name(&name, &guard)?);

        let mut leftmost_chain: Vec<PageId> = vec![root_id.unwrap()];
        let mut cursor = root_id.unwrap();
        while let Some(view) = self.view_for_pid(cursor, &guard)? {
            if let Some(index) = view.data.index_ref() {
                let leftmost_child = index[0].1;
                leftmost_chain.push(leftmost_child);
                cursor = leftmost_child;
            } else {
                break;
            }
        }

        loop {
            let res = self
                .context
                .pagecache
                .cas_root_in_meta(&name, root_id, None, &guard)?;

            if let Err(actual_root) = res {
                root_id = actual_root;
            } else {
                break;
            }
        }

        tree.root.store(u64::max_value(), SeqCst);

        // drop writer lock
        drop(tenants);

        tree.gc_pages(leftmost_chain)?;

        guard.flush();

        Ok(true)
    }

    /// Returns the trees names saved in this Db.
    pub fn tree_names(&self) -> Vec<Vec<u8>> {
        let tenants = self.tenants.read();
        tenants.iter().map(|(name, _)| name.clone()).collect()
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.context.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<u64> {
        self.context.generate_id()
    }

    /// A database export method for all collections in the `Db`,
    /// for use in sled version upgrades. Can be used in combination
    /// with the `import` method below on a database running a later
    /// version.
    ///
    /// # Panics
    ///
    /// Panics if any IO problems occur while trying
    /// to perform the export.
    pub fn export(
        &self,
    ) -> Vec<(CollectionType, CollectionName, impl Iterator<Item = Vec<Vec<u8>>>)>
    {
        let tenants = self.tenants.read();

        let mut ret = vec![];

        for (name, tree) in tenants.iter() {
            ret.push((
                b"tree".to_vec(),
                name.to_vec(),
                tree.iter().map(|kv| {
                    let kv = kv.unwrap();
                    vec![kv.0.to_vec(), kv.1.to_vec()]
                }),
            ));
        }

        ret
    }

    /// Imports the collections from a previous database.
    ///
    /// # Panics
    ///
    /// Panics if any IO problems occur while trying
    /// to perform the import.
    pub fn import(
        &self,
        export: Vec<(
            CollectionType,
            CollectionName,
            impl Iterator<Item = Vec<Vec<u8>>>,
        )>,
    ) {
        for (collection_type, collection_name, collection_iter) in export {
            match collection_type {
                ref t if t == b"tree" => {
                    let tree = self
                        .open_tree(collection_name)
                        .expect("failed to open new tree during import");
                    for mut kv in collection_iter {
                        let v = kv
                            .pop()
                            .expect("failed to get value from tree export");
                        let k = kv
                            .pop()
                            .expect("failed to get key from tree export");
                        let old = tree.insert(k, v).expect(
                            "failed to insert value during tree import",
                        );
                        assert!(
                            old.is_none(),
                            "import is overwriting existing data"
                        );
                    }
                }
                other => panic!("unknown collection type {:?}", other),
            }
        }
    }

    /// Returns the CRC32 of all keys and values
    /// in this Db.
    ///
    /// This is O(N) and locks all underlying Trees
    /// for the duration of the entire scan.
    pub fn checksum(&self) -> Result<u32> {
        let tenants_mu = self.tenants.write();

        // we use a btreemap to ensure lexicographic
        // iteration over tree names to have consistent
        // checksums.
        let tenants: BTreeMap<_, _> = tenants_mu.iter().collect();

        let mut hasher = crc32fast::Hasher::new();
        let mut locks = vec![];

        for (_, tree) in tenants.iter() {
            locks.push(tree.concurrency_control.write());
        }

        for (name, tree) in tenants.iter() {
            hasher.update(name);

            let mut iter = tree.iter();
            let _ = self.concurrency_control.write();
            while let Some(kv_res) = iter.next_inner() {
                let (k, v) = kv_res?;
                hasher.update(&k);
                hasher.update(&v);
            }
        }

        Ok(hasher.finalize())
    }

    /// Traverses all files and calculates their total physical
    /// size, then traverses all pages and calculates their
    /// total logical size, then divides the physical size
    /// by the logical size.
    #[doc(hidden)]
    pub fn space_amplification(&self) -> Result<f64> {
        self.context.pagecache.space_amplification()
    }
}

/// These types provide the information that allows an entire
/// system to be exported and imported to facilitate
/// major upgrades. It is comprised entirely
/// of standard library types to be forward compatible.
/// NB this definitions are expensive to change, because
/// they impact the migration path.
type CollectionType = Vec<u8>;
type CollectionName = Vec<u8>;
<|endoftext|>


<commit_before>use find_folder;
use conrod::{
    Canvas, Colorable, Frameable, Positionable, Labelable, Sizeable, Theme, Ui, UiCell,
    Text, Widget, color
};
use piston_window::{G2d, Glyphs, Graphics, PistonWindow};

use game::Rustris;

pub type Backend = (<G2d<'static> as Graphics>::Texture, Glyphs);
pub type UI = Ui<Backend>;
pub type UICell<'a> = UiCell<'a, Backend>;

pub fn create_ui(window: &PistonWindow) -> UI {
    let assets = find_folder::Search::KidsThenParents(3, 5)
        .for_folder("assets").unwrap();
    let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
    UI::new(glyph_cache.unwrap(), theme)
}

pub fn set_ui(ref mut ui: UICell, game: &Rustris) {
    Canvas::new().flow_right(&[
        (LEFT_COLUMN, Canvas::new().color(color::LIGHT_ORANGE).pad(20.0)),
        (MIDDLE_COLUMN, Canvas::new().length(300.0)),
        (RIGHT_COLUMN, Canvas::new().color(color::LIGHT_ORANGE).pad(20.0)),
    ]).set(MASTER, ui);

    // Scoreboard
    Canvas::new().flow_down(&[
        (SCORE_CANVAS, Canvas::new().label("Score").label_color(color::WHITE)),
        (LEVEL_CANVAS, Canvas::new().label("Level").label_color(color::WHITE)),
        (LINES_CANVAS, Canvas::new().label("Lines").label_color(color::WHITE)),
    ]).w_h(150.0, 250.0)
      .mid_bottom_of(LEFT_COLUMN)
      .set(SCOREBOARD, ui);

    let stats = &game.stats;
    Text::new(&stats.get_score().to_string())
        .color(color::WHITE)
        .middle_of(SCORE_CANVAS)
        .set(SCORE, ui);
    Text::new(&stats.get_level().to_string())
        .color(color::WHITE)
        .middle_of(LEVEL_CANVAS)
        .set(LEVEL, ui);
    Text::new(&stats.get_lines().to_string())
        .color(color::WHITE)
        .middle_of(LINES_CANVAS)
        .set(LINES, ui);
}

widget_ids! {
    // Canvas IDs
    MASTER,
    LEFT_COLUMN,
    MIDDLE_COLUMN,
    RIGHT_COLUMN,

    // Scoreboard IDs
    SCOREBOARD,
    SCORE_CANVAS,
    LEVEL_CANVAS,
    LINES_CANVAS,
    SCORE,
    LEVEL,
    LINES
}
<commit_msg>a little nicer color for testing<commit_after>use find_folder;
use conrod::{
    Canvas, Colorable, Frameable, Positionable, Labelable, Sizeable, Theme, Ui, UiCell,
    Text, Widget, color
};
use piston_window::{G2d, Glyphs, Graphics, PistonWindow};

use game::Rustris;

pub type Backend = (<G2d<'static> as Graphics>::Texture, Glyphs);
pub type UI = Ui<Backend>;
pub type UICell<'a> = UiCell<'a, Backend>;

pub fn create_ui(window: &PistonWindow) -> UI {
    let assets = find_folder::Search::KidsThenParents(3, 5)
        .for_folder("assets").unwrap();
    let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
    UI::new(glyph_cache.unwrap(), theme)
}

pub fn set_ui(ref mut ui: UICell, game: &Rustris) {
    Canvas::new().flow_right(&[
        (LEFT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
        (MIDDLE_COLUMN, Canvas::new().length(300.0)),
        (RIGHT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
    ]).set(MASTER, ui);

    // Scoreboard
    Canvas::new().flow_down(&[
        (SCORE_CANVAS, Canvas::new().label("Score").label_color(color::WHITE)),
        (LEVEL_CANVAS, Canvas::new().label("Level").label_color(color::WHITE)),
        (LINES_CANVAS, Canvas::new().label("Lines").label_color(color::WHITE)),
    ]).w_h(150.0, 250.0)
      .mid_bottom_of(LEFT_COLUMN)
      .set(SCOREBOARD, ui);

    let stats = &game.stats;
    Text::new(&stats.get_score().to_string())
        .color(color::WHITE)
        .middle_of(SCORE_CANVAS)
        .set(SCORE, ui);
    Text::new(&stats.get_level().to_string())
        .color(color::WHITE)
        .middle_of(LEVEL_CANVAS)
        .set(LEVEL, ui);
    Text::new(&stats.get_lines().to_string())
        .color(color::WHITE)
        .middle_of(LINES_CANVAS)
        .set(LINES, ui);
}

widget_ids! {
    // Canvas IDs
    MASTER,
    LEFT_COLUMN,
    MIDDLE_COLUMN,
    RIGHT_COLUMN,

    // Scoreboard IDs
    SCOREBOARD,
    SCORE_CANVAS,
    LEVEL_CANVAS,
    LINES_CANVAS,
    SCORE,
    LEVEL,
    LINES
}
<|endoftext|>


<commit_before>/*
 * An example redis server accepting GET and SET requests
 * listening on 127.0.0.1:8000.
 *
 * You can test it with "redis-cli -p 8000".
 *
 * Copyright (c) 2014 by Michael Neumann
 *
 */

extern crate redis = "redis#0.1";
extern crate sync = "sync#0.10-pre";

use std::io::net::ip::SocketAddr;
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Listener,Acceptor,Writer};
use std::io::BufferedStream;
use std::task;
use std::hashmap::HashMap;
use sync::RWArc;

fn handle_connection(conn: TcpStream, shared_ht: RWArc<HashMap<~[u8],~[u8]>>) {
    debug!("Got connection");

    let mut io = BufferedStream::new(conn);

    loop {
        match redis::parse(&mut io).unwrap() {
            redis::List(ref lst) => {
                match lst.get(0) {
                    Some(redis::Data(ref command)) => {
                        if command == bytes!("GET") {
                            match (lst.len(), lst.get(1)) {
                                (2, Some(redis::Data(key))) => {
                                    debug!("GET: {:s}", std::str::from_utf8(key).unwrap());
                                    let mut cwr = redis::CommandWriter::new();
                                    shared_ht.read(|ht| {
                                        match ht.find(&key) {
                                            Some(val) => {
                                                cwr.args(1);
                                                cwr.arg_bin(*val);
                                            }
                                            None => {
                                                cwr.nil();
                                            }
                                        }
                                    });
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else if command == bytes!("SET") {
                            match (lst.len(), lst.get(1), lst.get(2)) {
                                (3, redis::Data(key), redis::Data(val)) => {
                                    debug!("SET: {:s} {:?}", std::str::from_utf8(key).unwrap(), val);
                                    shared_ht.write(|ht| ht.insert(key.clone(), val.clone()));
                                    let mut cwr = redis::CommandWriter::new();
                                    cwr.status("OK");
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else {
                            /* fallthrough: error */
                        }
                    }
                    _ => { /* fallthrough: error */ }
                }
            }
            _ => { /* fallthrough: error */ }
        }

        /* error */
        let mut cwr = redis::CommandWriter::new();
        cwr.error("Invalid Command");
        cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
    }
}

fn main() {
    let addr: SocketAddr = from_str("127.0.0.1:8000").unwrap();
    let shared_ht = RWArc::new(HashMap::new());

    match TcpListener::bind(addr) {
        Ok(listener) => {
            match listener.listen() {
                Ok(ref mut acceptor) => {
                    loop {
                        match acceptor.accept() {
                            Ok(conn) => {
                                let ht = shared_ht.clone();
                                task::spawn(proc() {
                                    handle_connection(conn, ht)
                                });
                            }
                            Err(_) => {}
                        }
                    }
                }
                Err(_) => {}
            }
        }
        Err(_) => {}
    }
}
<commit_msg>Finally make it compile<commit_after>/*
 * An example redis server accepting GET and SET requests
 * listening on 127.0.0.1:8000.
 *
 * You can test it with "redis-cli -p 8000".
 *
 * Copyright (c) 2014 by Michael Neumann
 *
 */

extern crate redis = "redis#0.1";
extern crate sync = "sync#0.10-pre";

use std::io::net::ip::SocketAddr;
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Listener,Acceptor,Writer};
use std::io::BufferedStream;
use std::task;
use std::hashmap::HashMap;
use sync::RWArc;

fn handle_connection(conn: TcpStream, shared_ht: RWArc<HashMap<~[u8],~[u8]>>) {
    debug!("Got connection");

    let mut io = BufferedStream::new(conn);

    loop {
        match redis::parse(&mut io).unwrap() {
            redis::List(ref lst) => {
                match lst.get(0) {
                    Some(&redis::Data(ref command)) => {
                        if command.as_slice() == bytes!("GET") {
                            match (lst.len(), lst.get(1)) {
                                (2, Some(&redis::Data(ref key))) => {
                                    debug!("GET: {:s}", std::str::from_utf8(key.as_slice()).unwrap());
                                    let mut cwr = redis::CommandWriter::new();
                                    shared_ht.read(|ht| {
                                        match ht.find(key) {
                                            Some(val) => {
                                                cwr.args(1);
                                                cwr.arg_bin(*val);
                                            }
                                            None => {
                                                cwr.nil();
                                            }
                                        }
                                    });
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else if command.as_slice() == bytes!("SET") {
                            match (lst.len(), lst.get(1), lst.get(2)) {
                                (3, Some(&redis::Data(ref key)), Some(&redis::Data(ref val))) => {
                                    debug!("SET: {:s} {:?}", std::str::from_utf8(key.as_slice()).unwrap(), val);
                                    shared_ht.write(|ht| ht.insert(key.clone(), val.clone()));
                                    let mut cwr = redis::CommandWriter::new();
                                    cwr.status("OK");
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else {
                            /* fallthrough: error */
                        }
                    }
                    _ => { /* fallthrough: error */ }
                }
            }
            _ => { /* fallthrough: error */ }
        }

        /* error */
        let mut cwr = redis::CommandWriter::new();
        cwr.error("Invalid Command");
        cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
    }
}

fn main() {
    let addr: SocketAddr = from_str("127.0.0.1:8000").unwrap();
    let shared_ht = RWArc::new(HashMap::new());

    match TcpListener::bind(addr) {
        Ok(listener) => {
            match listener.listen() {
                Ok(ref mut acceptor) => {
                    loop {
                        match acceptor.accept() {
                            Ok(conn) => {
                                let ht = shared_ht.clone();
                                task::spawn(proc() {
                                    handle_connection(conn, ht)
                                });
                            }
                            Err(_) => {}
                        }
                    }
                }
                Err(_) => {}
            }
        }
        Err(_) => {}
    }
}
<|endoftext|>


<commit_before>use stdlib::value::{Value, VUndefined, ResultValue, to_value};
use std::gc::Gc;

/// Create a new boolean
pub fn make_boolean(_:Vec<Value>, _:Value, _:Value, this:Value) -> ResultValue {
	Ok(box VUndefined)
}
/// Create a new `Boolean` object
pub fn _create(global: Value) -> Value {
	let boolean = to_value(make_boolean);
	boolean
}
/// Initialise the global object with the `Error` object
pub fn init(global:Value) {
	let global_ptr = global.borrow();
	global_ptr.set_field_slice("Boolean", _create(global));
}<commit_msg>Allocate a box in Boolean on the GC instead of the heap<commit_after>use stdlib::value::{Value, VUndefined, ResultValue, to_value};
use std::gc::GC;

/// Create a new boolean
pub fn make_boolean(_:Vec<Value>, _:Value, _:Value, this:Value) -> ResultValue {
	Ok(box(GC) VUndefined)
}
/// Create a new `Boolean` object
pub fn _create(global: Value) -> Value {
	let boolean = to_value(make_boolean);
	boolean
}
/// Initialise the global object with the `Boolean` object
pub fn init(global:Value) {
	let global_ptr = global.borrow();
	global_ptr.set_field_slice("Boolean", _create(global));
}<|endoftext|>


<commit_before>use super::{FromRequest, Request};

macro_rules! reqwest_impl {
    { $C:ty, $B:ty } => {
        // By default reqwest won't allow us to build a request without a base URI, ie:
        //
        // https://a_host
        //
        impl<URI: ToString> FromRequest<(&$C, URI)> for $B {
            fn from_request(r: Request, params: (&$C, URI)) -> Self {
                let (uri, body) = r.parameters.uri_and_body(r.path);
                let (client, uri_base) = params;
                let uri = uri_base.to_string() + uri.as_ref();

                let rb = client.request(r.method, uri.as_str()).headers(r.headers);

                match body {
                    Some(body) => rb.body(body.to_owned()),
                    _ => rb
                }
            }
        }
    }
}

#[cfg(feature = "reqwest-async")]
reqwest_impl!(reqwest::r#async::Client, reqwest::r#async::RequestBuilder);
#[cfg(feature = "reqwest-sync")]
reqwest_impl!(reqwest::Client, reqwest::RequestBuilder);
<commit_msg>reqwest: avoid cloning a request's body unnecessarily<commit_after>use super::{FromRequest, Request};

macro_rules! reqwest_impl {
    { $C:ty, $B:ty } => {
        // By default reqwest won't allow us to build a request without a base URI, ie:
        //
        // https://a_host
        //
        impl<URI: ToString> FromRequest<(&$C, URI)> for $B {
            fn from_request(r: Request, params: (&$C, URI)) -> Self {
                let (uri, body) = r.parameters.uri_and_body(r.path);
                let (client, uri_base) = params;
                let uri = uri_base.to_string() + uri.as_ref();

                let rb = client.request(r.method, uri.as_str()).headers(r.headers);

                match body {
                    // when there is a body just consume it from the request's
                    // parameters to avoid cloning it unnecessarily.
                    Some(_) => rb.body(r.parameters.into_inner()),
                    _ => rb
                }
            }
        }
    }
}

#[cfg(feature = "reqwest-async")]
reqwest_impl!(reqwest::r#async::Client, reqwest::r#async::RequestBuilder);
#[cfg(feature = "reqwest-sync")]
reqwest_impl!(reqwest::Client, reqwest::RequestBuilder);
<|endoftext|>


<commit_before>/* diosix debug console output code
 *
 * (c) Chris Williams, 2019-2020.
 *
 * See LICENSE for usage and copying.
 */

/* to avoid warnings about super::hardware when qemuprint is active */
#![allow(unused_imports)]

use super::error::Cause;
use core::fmt;
use spin::Mutex;
use alloc::string::String;
use super::hardware;

lazy_static!
{
    pub static ref DEBUG_LOCK: Mutex<bool> = Mutex::new(false);
    static ref DEBUG_QUEUE: Mutex<String> = Mutex::new(String::new());
}

/* top level debug macros */
/* useful messages */
#[macro_export]
macro_rules! hvlog
{
    ($fmt:expr) => (hvprintln!("[+] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[+] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* bad news: bug detection, failures, etc. */
#[macro_export]
macro_rules! hvalert
{
    ($fmt:expr) => (hvprintln!("[!] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[!] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* only output if debug build is enabled */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebug
{
    ($fmt:expr) => (hvprintln!("[?] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[?] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebug
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* don't include any metadata nor add a newline */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebugraw
{
    ($fmt:expr) => (hvprint!("{}", $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebugraw
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* low-level macros for hypervisor-only hvprintln and hvprint debug output routines */
macro_rules! hvprintln
{
    ($fmt:expr) => (hvprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt, "\n"), $($arg)*));
}

macro_rules! hvprint
{
    ($($arg:tt)*) =>
    ({
        use core::fmt::Write;
        {
            /* we do this little lock dance to ensure the lock isn't immediately dropped by rust */
            let mut lock = $crate::debug::DEBUG_LOCK.lock();
            *lock = true;

            unsafe { $crate::debug::CONSOLE.write_fmt(format_args!($($arg)*)).unwrap(); }
        }
    });
}

macro_rules! debughousekeeper
{
    () => ($crate::debug::drain_queue());
}

/* create a generic debug console writer */
pub struct ConsoleWriter;
pub static mut CONSOLE: ConsoleWriter = ConsoleWriter {};

impl fmt::Write for ConsoleWriter
{
    #[cfg(not(feature = "qemuprint"))]
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        DEBUG_QUEUE.lock().push_str(s);
        Ok(())
    }

    #[cfg(feature = "qemuprint")]
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        /* force debug output to Qemu's serial port. useful for early debugging */
        for c in s.as_bytes()
        {
            /* FIXME: hardwired to the RISC-V Qemu serial port */
            unsafe { *(0x10000000 as *mut u8) = *c };
        }
        Ok(())
    }
}

/* attempt to empty queue out to the device-tree-defined debug port */
#[cfg(not(feature = "qemuprint"))]
pub fn drain_queue()
{
    let mut lock = DEBUG_LOCK.lock();
    *lock = true;

    let mut queue = DEBUG_QUEUE.lock();
    if hardware::write_debug_string(&queue) == true
    {
        queue.clear();
    }
}

#[cfg(feature = "qemuprint")]
pub fn drain_queue() { }<commit_msg>Don't block if queue cannot be drained<commit_after>/* diosix debug console output code
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* to avoid warnings about super::hardware when qemuprint is active */
#![allow(unused_imports)]

use super::error::Cause;
use core::fmt;
use spin::Mutex;
use alloc::string::String;
use super::hardware;

lazy_static!
{
    pub static ref DEBUG_LOCK: Mutex<bool> = Mutex::new(false);
    static ref DEBUG_QUEUE: Mutex<String> = Mutex::new(String::new());
}

/* top level debug macros */
/* useful messages */
#[macro_export]
macro_rules! hvlog
{
    ($fmt:expr) => (hvprintln!("[+] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[+] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* bad news: bug detection, failures, etc. */
#[macro_export]
macro_rules! hvalert
{
    ($fmt:expr) => (hvprintln!("[!] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[!] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* only output if debug build is enabled */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebug
{
    ($fmt:expr) => (hvprintln!("[?] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[?] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebug
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* don't include any metadata nor add a newline */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebugraw
{
    ($fmt:expr) => (hvprint!("{}", $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebugraw
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* low-level macros for hypervisor-only hvprintln and hvprint debug output routines */
macro_rules! hvprintln
{
    ($fmt:expr) => (hvprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt, "\n"), $($arg)*));
}

macro_rules! hvprint
{
    ($($arg:tt)*) =>
    ({
        use core::fmt::Write;
        {
            let mut hvprint_lock = $crate::debug::DEBUG_LOCK.lock();
            *hvprint_lock = true;

            unsafe { $crate::debug::CONSOLE.write_fmt(format_args!($($arg)*)).unwrap(); }
        }
    });
}

macro_rules! debughousekeeper
{
    () => ($crate::debug::drain_queue());
}

/* create a generic debug console writer */
pub struct ConsoleWriter;
pub static mut CONSOLE: ConsoleWriter = ConsoleWriter {};

impl fmt::Write for ConsoleWriter
{
    #[cfg(not(feature = "qemuprint"))]
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        DEBUG_QUEUE.lock().push_str(s);
        Ok(())
    }

    #[cfg(feature = "qemuprint")]
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        /* force debug output to Qemu's serial port. useful for early debugging */
        for c in s.as_bytes()
        {
            /* FIXME: hardwired to the RISC-V Qemu serial port */
            unsafe { *(0x10000000 as *mut u8) = *c };
        }
        Ok(())
    }
}

/* attempt to empty queue out to the device-tree-defined debug port */
#[cfg(not(feature = "qemuprint"))]
pub fn drain_queue()
{
    /* don't block if we can't write at this time */
    if let Some(mut debug_lock) = DEBUG_LOCK.try_lock()
    {
        *debug_lock = true;
        if let Some(mut debug_queue) = DEBUG_QUEUE.try_lock()
        {
            if hardware::write_debug_string(&debug_queue) == true
            {
                debug_queue.clear();
            }
        }
    }
}

#[cfg(feature = "qemuprint")]
pub fn drain_queue() { }<|endoftext|>


<commit_before>use std::sync::mpsc::{Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;
use std::time::Instant;
use super::entry::Entry;
use super::storage::Storage;

///
/// Minimum duration between expiration checks in seconds
///
const CHECK_INTERVAL: u64 = 1;

///
/// Receive timeout for incoming messages in milliseconds
///
const RECV_TIMEOUT: u64 = 500;

pub trait Listener: Send {
    fn on_expired(&self, entry: Entry);
    fn on_tick(&self) {}
}

#[derive(Debug)]
pub enum Command {
    AddEntry(Entry),
    RemoveEntry(Entry),
}

pub struct Worker {
    storage: Storage,
    receiver: Receiver<Command>,
    listener: Box<Listener>,
    last_checked: Option<Instant>,
}

pub fn spawn(storage: Storage,
             receiver: Receiver<Command>,
             listener: Box<Listener>)
             -> thread::JoinHandle<()> {
    thread::spawn(move || {
        let worker = Worker::new(storage, receiver, listener);

        worker.run();
    })
}

impl Worker {
    pub fn new(storage: Storage, receiver: Receiver<Command>, listener: Box<Listener>) -> Worker {
        Worker {
            storage,
            receiver,
            listener,
            last_checked: None,
        }
    }

    pub fn run(mut self) -> thread::JoinHandle<()> {
        self.check_expired();

        loop {
            let incoming = self.receiver
                .recv_timeout(Duration::from_millis(RECV_TIMEOUT));

            match incoming {
                Err(err) => self.handle_error(err),
                Ok(command) => self.handle_command(command),
            }

            if self.needs_checking() {
                self.listener.on_tick();
                self.check_expired();
            }
        }
    }

    fn handle_error(&self, err: RecvTimeoutError) {
        match err {
            RecvTimeoutError::Timeout => {}
            RecvTimeoutError::Disconnected => panic!("channel disconnected"),
        }
    }

    fn handle_command(&mut self, command: Command) {
        match command {
            Command::AddEntry(entry) => {
                self.storage.add_entry(entry);
            }
            Command::RemoveEntry(entry) => {
                self.storage.remove_entry(&entry);
            }
        }
    }

    fn check_expired(&mut self) {
        self.last_checked = Some(Instant::now());

        for entry in self.storage.expired_entries() {
            self.listener.on_expired(entry);
            self.storage.remove_entry(&entry);
        }
    }

    fn needs_checking(&self) -> bool {
        match self.last_checked {
            None => true,
            Some(value) => {
                return value.elapsed().as_secs() >= CHECK_INTERVAL;
            }
        }
    }
}
<commit_msg>Remove incorrect return<commit_after>use std::sync::mpsc::{Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;
use std::time::Instant;
use super::entry::Entry;
use super::storage::Storage;

///
/// Minimum duration between expiration checks in seconds
///
const CHECK_INTERVAL: u64 = 1;

///
/// Receive timeout for incoming messages in milliseconds
///
const RECV_TIMEOUT: u64 = 500;

pub trait Listener: Send {
    fn on_expired(&self, entry: Entry);
    fn on_tick(&self) {}
}

#[derive(Debug)]
pub enum Command {
    AddEntry(Entry),
    RemoveEntry(Entry),
}

pub struct Worker {
    storage: Storage,
    receiver: Receiver<Command>,
    listener: Box<Listener>,
    last_checked: Option<Instant>,
}

pub fn spawn(storage: Storage,
             receiver: Receiver<Command>,
             listener: Box<Listener>)
             -> thread::JoinHandle<()> {
    thread::spawn(move || {
        let worker = Worker::new(storage, receiver, listener);

        worker.run();
    })
}

impl Worker {
    pub fn new(storage: Storage, receiver: Receiver<Command>, listener: Box<Listener>) -> Worker {
        Worker {
            storage,
            receiver,
            listener,
            last_checked: None,
        }
    }

    pub fn run(mut self) {
        self.check_expired();

        loop {
            let incoming = self.receiver
                .recv_timeout(Duration::from_millis(RECV_TIMEOUT));

            match incoming {
                Err(err) => self.handle_error(err),
                Ok(command) => self.handle_command(command),
            }

            if self.needs_checking() {
                self.listener.on_tick();
                self.check_expired();
            }
        }
    }

    fn handle_error(&self, err: RecvTimeoutError) {
        match err {
            RecvTimeoutError::Timeout => {}
            RecvTimeoutError::Disconnected => panic!("channel disconnected"),
        }
    }

    fn handle_command(&mut self, command: Command) {
        match command {
            Command::AddEntry(entry) => {
                self.storage.add_entry(entry);
            }
            Command::RemoveEntry(entry) => {
                self.storage.remove_entry(&entry);
            }
        }
    }

    fn check_expired(&mut self) {
        self.last_checked = Some(Instant::now());

        for entry in self.storage.expired_entries() {
            self.listener.on_expired(entry);
            self.storage.remove_entry(&entry);
        }
    }

    fn needs_checking(&self) -> bool {
        match self.last_checked {
            None => true,
            Some(value) => {
                return value.elapsed().as_secs() >= CHECK_INTERVAL;
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(stage0)]
use prelude::v1::*;

use ops::{Add, Sub, Mul, Div};
use sys::time::SteadyTime;

const NANOS_PER_SEC: u32 = 1_000_000_000;
const NANOS_PER_MILLI: u32 = 1_000_000;
const MILLIS_PER_SEC: u64 = 1_000;

/// A duration type to represent a span of time, typically used for system
/// timeouts.
///
/// Each duration is composed of a number of seconds and nanosecond precision.
/// APIs binding a system timeout will typically round up the nanosecond
/// precision if the underlying system does not support that level of precision.
///
/// Durations implement many common traits, including `Add`, `Sub`, and other
/// ops traits. Currently a duration may only be inspected for its number of
/// seconds and its nanosecond precision.
///
/// # Examples
///
/// ```
/// #![feature(duration)]
/// use std::time::Duration;
///
/// let five_seconds = Duration::new(5, 0);
/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
///
/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5);
/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5);
///
/// let ten_millis = Duration::from_millis(10);
/// ```
#[stable(feature = "duration", since = "1.3.0")]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Duration {
    secs: u64,
    nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
}

impl Duration {
    /// Crates a new `Duration` from the specified number of seconds and
    /// additional nanosecond precision.
    ///
    /// If the nanoseconds is greater than 1 billion (the number of nanoseconds
    /// in a second), then it will carry over into the seconds provided.
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn new(secs: u64, nanos: u32) -> Duration {
        let secs = secs + (nanos / NANOS_PER_SEC) as u64;
        let nanos = nanos % NANOS_PER_SEC;
        Duration { secs: secs, nanos: nanos }
    }

    /// Runs a closure, returning the duration of time it took to run the
    /// closure.
    #[unstable(feature = "duration_span",
               reason = "unsure if this is the right API or whether it should \
                         wait for a more general \"moment in time\" \
                         abstraction")]
    pub fn span<F>(f: F) -> Duration where F: FnOnce() {
        let start = SteadyTime::now();
        f();
        &SteadyTime::now() - &start
    }

    /// Creates a new `Duration` from the specified number of seconds.
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn from_secs(secs: u64) -> Duration {
        Duration { secs: secs, nanos: 0 }
    }

    /// Creates a new `Duration` from the specified number of milliseconds.
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn from_millis(millis: u64) -> Duration {
        let secs = millis / MILLIS_PER_SEC;
        let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI;
        Duration { secs: secs, nanos: nanos }
    }

    /// Returns the number of whole seconds represented by this duration.
    ///
    /// The extra precision represented by this duration is ignored (e.g. extra
    /// nanoseconds are not represented in the returned value).
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn as_secs(&self) -> u64 { self.secs }

    #[deprecated(reason = "renamed to `as_secs`", since = "1.3.0")]
    #[unstable(feature = "duration_deprecated")]
    /// Returns the number of whole seconds represented by this duration.
    ///
    /// The extra precision represented by this duration is ignored (e.g. extra
    /// nanoseconds are not represented in the returned value).
    pub fn secs(&self) -> u64 { self.as_secs() }

    /// Returns the nanosecond precision represented by this duration.
    ///
    /// This method does **not** return the length of the duration when
    /// represented by nanoseconds. The returned number always represents a
    /// fractional portion of a second (e.g. it is less than one billion).
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn subsec_nanos(&self) -> u32 { self.nanos }

    #[deprecated(reason = "renamed to `subsec_nanos`", since = "1.3.0")]
    #[unstable(feature = "duration_deprecated")]
    /// Returns the nanosecond precision represented by this duration.
    ///
    /// This method does **not** return the length of the duration when
    /// represented by nanoseconds. The returned number always represents a
    /// fractional portion of a second (e.g. it is less than one billion).
    pub fn extra_nanos(&self) -> u32 { self.subsec_nanos() }
}

impl Add for Duration {
    type Output = Duration;

    fn add(self, rhs: Duration) -> Duration {
        let mut secs = self.secs.checked_add(rhs.secs)
                           .expect("overflow when adding durations");
        let mut nanos = self.nanos + rhs.nanos;
        if nanos >= NANOS_PER_SEC {
            nanos -= NANOS_PER_SEC;
            secs = secs.checked_add(1).expect("overflow when adding durations");
        }
        debug_assert!(nanos < NANOS_PER_SEC);
        Duration { secs: secs, nanos: nanos }
    }
}

impl Sub for Duration {
    type Output = Duration;

    fn sub(self, rhs: Duration) -> Duration {
        let mut secs = self.secs.checked_sub(rhs.secs)
                           .expect("overflow when subtracting durations");
        let nanos = if self.nanos >= rhs.nanos {
            self.nanos - rhs.nanos
        } else {
            secs = secs.checked_sub(1)
                       .expect("overflow when subtracting durations");
            self.nanos + NANOS_PER_SEC - rhs.nanos
        };
        debug_assert!(nanos < NANOS_PER_SEC);
        Duration { secs: secs, nanos: nanos }
    }
}

impl Mul<u32> for Duration {
    type Output = Duration;

    fn mul(self, rhs: u32) -> Duration {
        // Multiply nanoseconds as u64, because it cannot overflow that way.
        let total_nanos = self.nanos as u64 * rhs as u64;
        let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
        let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
        let secs = self.secs.checked_mul(rhs as u64)
                       .and_then(|s| s.checked_add(extra_secs))
                       .expect("overflow when multiplying duration");
        debug_assert!(nanos < NANOS_PER_SEC);
        Duration { secs: secs, nanos: nanos }
    }
}

impl Div<u32> for Duration {
    type Output = Duration;

    fn div(self, rhs: u32) -> Duration {
        let secs = self.secs / (rhs as u64);
        let carry = self.secs - secs * (rhs as u64);
        let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
        let nanos = self.nanos / rhs + (extra_nanos as u32);
        debug_assert!(nanos < NANOS_PER_SEC);
        Duration { secs: secs, nanos: nanos }
    }
}

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

    #[test]
    fn creation() {
        assert!(Duration::from_secs(1) != Duration::from_secs(0));
        assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
                   Duration::from_secs(3));
        assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
                   Duration::new(4, 10 * 1_000_000));
        assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
    }

    #[test]
    fn secs() {
        assert_eq!(Duration::new(0, 0).as_secs(), 0);
        assert_eq!(Duration::from_secs(1).as_secs(), 1);
        assert_eq!(Duration::from_millis(999).as_secs(), 0);
        assert_eq!(Duration::from_millis(1001).as_secs(), 1);
    }

    #[test]
    fn nanos() {
        assert_eq!(Duration::new(0, 0).subsec_nanos(), 0);
        assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
        assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
        assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
        assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
        assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
    }

    #[test]
    fn add() {
        assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
                   Duration::new(0, 1));
        assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
                   Duration::new(1, 1));
    }

    #[test]
    fn sub() {
        assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
                   Duration::new(0, 1));
        assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
                   Duration::new(0, 1));
        assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
                   Duration::new(0, 999_999_999));
    }

    #[test] #[should_panic]
    fn sub_bad1() {
        Duration::new(0, 0) - Duration::new(0, 1);
    }

    #[test] #[should_panic]
    fn sub_bad2() {
        Duration::new(0, 0) - Duration::new(1, 0);
    }

    #[test]
    fn mul() {
        assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
        assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
        assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
        assert_eq!(Duration::new(0, 500_000_001) * 4000,
                   Duration::new(2000, 4000));
    }

    #[test]
    fn div() {
        assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
        assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
        assert_eq!(Duration::new(99, 999_999_000) / 100,
                   Duration::new(0, 999_999_990));
    }
}
<commit_msg>Fix doc test<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(stage0)]
use prelude::v1::*;

use ops::{Add, Sub, Mul, Div};
use sys::time::SteadyTime;

const NANOS_PER_SEC: u32 = 1_000_000_000;
const NANOS_PER_MILLI: u32 = 1_000_000;
const MILLIS_PER_SEC: u64 = 1_000;

/// A duration type to represent a span of time, typically used for system
/// timeouts.
///
/// Each duration is composed of a number of seconds and nanosecond precision.
/// APIs binding a system timeout will typically round up the nanosecond
/// precision if the underlying system does not support that level of precision.
///
/// Durations implement many common traits, including `Add`, `Sub`, and other
/// ops traits. Currently a duration may only be inspected for its number of
/// seconds and its nanosecond precision.
///
/// # Examples
///
/// ```
/// use std::time::Duration;
///
/// let five_seconds = Duration::new(5, 0);
/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
///
/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5);
/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5);
///
/// let ten_millis = Duration::from_millis(10);
/// ```
#[stable(feature = "duration", since = "1.3.0")]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Duration {
    secs: u64,
    nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
}

impl Duration {
    /// Crates a new `Duration` from the specified number of seconds and
    /// additional nanosecond precision.
    ///
    /// If the nanoseconds is greater than 1 billion (the number of nanoseconds
    /// in a second), then it will carry over into the seconds provided.
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn new(secs: u64, nanos: u32) -> Duration {
        let secs = secs + (nanos / NANOS_PER_SEC) as u64;
        let nanos = nanos % NANOS_PER_SEC;
        Duration { secs: secs, nanos: nanos }
    }

    /// Runs a closure, returning the duration of time it took to run the
    /// closure.
    #[unstable(feature = "duration_span",
               reason = "unsure if this is the right API or whether it should \
                         wait for a more general \"moment in time\" \
                         abstraction")]
    pub fn span<F>(f: F) -> Duration where F: FnOnce() {
        let start = SteadyTime::now();
        f();
        &SteadyTime::now() - &start
    }

    /// Creates a new `Duration` from the specified number of seconds.
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn from_secs(secs: u64) -> Duration {
        Duration { secs: secs, nanos: 0 }
    }

    /// Creates a new `Duration` from the specified number of milliseconds.
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn from_millis(millis: u64) -> Duration {
        let secs = millis / MILLIS_PER_SEC;
        let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI;
        Duration { secs: secs, nanos: nanos }
    }

    /// Returns the number of whole seconds represented by this duration.
    ///
    /// The extra precision represented by this duration is ignored (e.g. extra
    /// nanoseconds are not represented in the returned value).
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn as_secs(&self) -> u64 { self.secs }

    #[deprecated(reason = "renamed to `as_secs`", since = "1.3.0")]
    #[unstable(feature = "duration_deprecated")]
    /// Returns the number of whole seconds represented by this duration.
    ///
    /// The extra precision represented by this duration is ignored (e.g. extra
    /// nanoseconds are not represented in the returned value).
    pub fn secs(&self) -> u64 { self.as_secs() }

    /// Returns the nanosecond precision represented by this duration.
    ///
    /// This method does **not** return the length of the duration when
    /// represented by nanoseconds. The returned number always represents a
    /// fractional portion of a second (e.g. it is less than one billion).
    #[stable(feature = "duration", since = "1.3.0")]
    pub fn subsec_nanos(&self) -> u32 { self.nanos }

    #[deprecated(reason = "renamed to `subsec_nanos`", since = "1.3.0")]
    #[unstable(feature = "duration_deprecated")]
    /// Returns the nanosecond precision represented by this duration.
    ///
    /// This method does **not** return the length of the duration when
    /// represented by nanoseconds. The returned number always represents a
    /// fractional portion of a second (e.g. it is less than one billion).
    pub fn extra_nanos(&self) -> u32 { self.subsec_nanos() }
}

impl Add for Duration {
    type Output = Duration;

    fn add(self, rhs: Duration) -> Duration {
        let mut secs = self.secs.checked_add(rhs.secs)
                           .expect("overflow when adding durations");
        let mut nanos = self.nanos + rhs.nanos;
        if nanos >= NANOS_PER_SEC {
            nanos -= NANOS_PER_SEC;
            secs = secs.checked_add(1).expect("overflow when adding durations");
        }
        debug_assert!(nanos < NANOS_PER_SEC);
        Duration { secs: secs, nanos: nanos }
    }
}

impl Sub for Duration {
    type Output = Duration;

    fn sub(self, rhs: Duration) -> Duration {
        let mut secs = self.secs.checked_sub(rhs.secs)
                           .expect("overflow when subtracting durations");
        let nanos = if self.nanos >= rhs.nanos {
            self.nanos - rhs.nanos
        } else {
            secs = secs.checked_sub(1)
                       .expect("overflow when subtracting durations");
            self.nanos + NANOS_PER_SEC - rhs.nanos
        };
        debug_assert!(nanos < NANOS_PER_SEC);
        Duration { secs: secs, nanos: nanos }
    }
}

impl Mul<u32> for Duration {
    type Output = Duration;

    fn mul(self, rhs: u32) -> Duration {
        // Multiply nanoseconds as u64, because it cannot overflow that way.
        let total_nanos = self.nanos as u64 * rhs as u64;
        let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
        let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
        let secs = self.secs.checked_mul(rhs as u64)
                       .and_then(|s| s.checked_add(extra_secs))
                       .expect("overflow when multiplying duration");
        debug_assert!(nanos < NANOS_PER_SEC);
        Duration { secs: secs, nanos: nanos }
    }
}

impl Div<u32> for Duration {
    type Output = Duration;

    fn div(self, rhs: u32) -> Duration {
        let secs = self.secs / (rhs as u64);
        let carry = self.secs - secs * (rhs as u64);
        let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
        let nanos = self.nanos / rhs + (extra_nanos as u32);
        debug_assert!(nanos < NANOS_PER_SEC);
        Duration { secs: secs, nanos: nanos }
    }
}

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

    #[test]
    fn creation() {
        assert!(Duration::from_secs(1) != Duration::from_secs(0));
        assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
                   Duration::from_secs(3));
        assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
                   Duration::new(4, 10 * 1_000_000));
        assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
    }

    #[test]
    fn secs() {
        assert_eq!(Duration::new(0, 0).as_secs(), 0);
        assert_eq!(Duration::from_secs(1).as_secs(), 1);
        assert_eq!(Duration::from_millis(999).as_secs(), 0);
        assert_eq!(Duration::from_millis(1001).as_secs(), 1);
    }

    #[test]
    fn nanos() {
        assert_eq!(Duration::new(0, 0).subsec_nanos(), 0);
        assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
        assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
        assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
        assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
        assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
    }

    #[test]
    fn add() {
        assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
                   Duration::new(0, 1));
        assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
                   Duration::new(1, 1));
    }

    #[test]
    fn sub() {
        assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
                   Duration::new(0, 1));
        assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
                   Duration::new(0, 1));
        assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
                   Duration::new(0, 999_999_999));
    }

    #[test] #[should_panic]
    fn sub_bad1() {
        Duration::new(0, 0) - Duration::new(0, 1);
    }

    #[test] #[should_panic]
    fn sub_bad2() {
        Duration::new(0, 0) - Duration::new(1, 0);
    }

    #[test]
    fn mul() {
        assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
        assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
        assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
        assert_eq!(Duration::new(0, 500_000_001) * 4000,
                   Duration::new(2000, 4000));
    }

    #[test]
    fn div() {
        assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
        assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
        assert_eq!(Duration::new(99, 999_999_000) / 100,
                   Duration::new(0, 999_999_990));
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate ipc_channel;
extern crate test;

/// Allows doing multiple inner iterations per bench.iter() run.
///
/// This is mostly to amortise the overhead of spawning a thread in the benchmark
/// when sending larger messages (that might be fragmented).
///
/// Note that you need to compensate the displayed results
/// for the proportionally longer runs yourself,
/// as the benchmark framework doesn't know about the inner iterations...
const ITERATIONS: usize = 1;

mod platform {
    extern crate crossbeam;

    use ipc_channel::platform;
    use ITERATIONS;

    use std::sync::{mpsc, Mutex};
    use test;

    #[bench]
    fn create_channel(b: &mut test::Bencher) {
        b.iter(|| {
            for _ in 0..ITERATIONS {
                platform::channel().unwrap();
            }
        });
    }

    fn bench_transfer_data(b: &mut test::Bencher, size: usize) {
        let data: Vec<u8> = (0..size).map(|i| (i % 251) as u8).collect();
        let (tx, rx) = platform::channel().unwrap();

        let (wait_tx, wait_rx) = mpsc::channel();
        let wait_rx = Mutex::new(wait_rx);

        if size > platform::OsIpcSender::get_max_fragment_size() {
            b.iter(|| {
                crossbeam::scope(|scope| {
                    let tx = tx.clone();
                    scope.spawn(|| {
                        let wait_rx = wait_rx.lock().unwrap();
                        let tx = tx;
                        for _ in 0..ITERATIONS {
                            tx.send(&data, vec![], vec![]).unwrap();
                            if ITERATIONS > 1 {
                                // Prevent beginning of the next send
                                // from overlapping with receive of last fragment,
                                // as otherwise results of runs with a large tail fragment
                                // are significantly skewed.
                                wait_rx.recv().unwrap();
                            }
                        }
                    });
                    for _ in 0..ITERATIONS {
                        rx.recv().unwrap();
                        if ITERATIONS > 1 {
                            wait_tx.send(()).unwrap();
                        }
                    }
                    // For reasons mysterious to me,
                    // not returning a value *from every branch*
                    // adds some 100 ns or so of overhead to all results --
                    // which is quite significant for very short tests...
                    0
                })
            });
        } else {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    tx.send(&data, vec![], vec![]).unwrap();
                    rx.recv().unwrap();
                }
                0
            });
        }
    }

    #[bench]
    fn transfer_data_00_1(b: &mut test::Bencher) {
        bench_transfer_data(b, 1);
    }
    #[bench]
    fn transfer_data_01_2(b: &mut test::Bencher) {
        bench_transfer_data(b, 2);
    }
    #[bench]
    fn transfer_data_02_4(b: &mut test::Bencher) {
        bench_transfer_data(b, 4);
    }
    #[bench]
    fn transfer_data_03_8(b: &mut test::Bencher) {
        bench_transfer_data(b, 8);
    }
    #[bench]
    fn transfer_data_04_16(b: &mut test::Bencher) {
        bench_transfer_data(b, 16);
    }
    #[bench]
    fn transfer_data_05_32(b: &mut test::Bencher) {
        bench_transfer_data(b, 32);
    }
    #[bench]
    fn transfer_data_06_64(b: &mut test::Bencher) {
        bench_transfer_data(b, 64);
    }
    #[bench]
    fn transfer_data_07_128(b: &mut test::Bencher) {
        bench_transfer_data(b, 128);
    }
    #[bench]
    fn transfer_data_08_256(b: &mut test::Bencher) {
        bench_transfer_data(b, 256);
    }
    #[bench]
    fn transfer_data_09_512(b: &mut test::Bencher) {
        bench_transfer_data(b, 512);
    }
    #[bench]
    fn transfer_data_10_1k(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024);
    }
    #[bench]
    fn transfer_data_11_2k(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024);
    }
    #[bench]
    fn transfer_data_12_4k(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024);
    }
    #[bench]
    fn transfer_data_13_8k(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024);
    }
    #[bench]
    fn transfer_data_14_16k(b: &mut test::Bencher) {
        bench_transfer_data(b, 16 * 1024);
    }
    #[bench]
    fn transfer_data_15_32k(b: &mut test::Bencher) {
        bench_transfer_data(b, 32 * 1024);
    }
    #[bench]
    fn transfer_data_16_64k(b: &mut test::Bencher) {
        bench_transfer_data(b, 64 * 1024);
    }
    #[bench]
    fn transfer_data_17_128k(b: &mut test::Bencher) {
        bench_transfer_data(b, 128 * 1024);
    }
    #[bench]
    fn transfer_data_18_256k(b: &mut test::Bencher) {
        bench_transfer_data(b, 256 * 1024);
    }
    #[bench]
    fn transfer_data_19_512k(b: &mut test::Bencher) {
        bench_transfer_data(b, 512 * 1024);
    }
    #[bench]
    fn transfer_data_20_1m(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_21_2m(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_22_4m(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_23_8m(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024 * 1024);
    }
}

mod ipc {
    mod receiver_set {
        use ipc_channel::ipc::{self, IpcReceiverSet};
        use ITERATIONS;

        use test;

        // Benchmark selecting over a set of `n` receivers,
        // with `to_send` of them actually having pending data.
        fn bench_send_on_m_of_n(b: &mut test::Bencher, to_send: usize, n: usize) {
            let mut senders = Vec::with_capacity(n);
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..n {
                let (tx, rx) = ipc::channel().unwrap();
                rx_set.add(rx).unwrap();
                senders.push(tx);
            }
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    for tx in senders.iter().take(to_send) {
                        tx.send(()).unwrap();
                    }
                    let mut received = 0;
                    while received < to_send {
                        received += rx_set.select().unwrap().len();
                    }
                }
            });
        }

        #[bench]
        fn send_on_1_of_1(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 1, 1);
        }

        #[bench]
        fn send_on_1_of_5(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 1, 5);
        }

        #[bench]
        fn send_on_2_of_5(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 2, 5);
        }

        #[bench]
        fn send_on_5_of_5(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 5, 5);
        }

        #[bench]
        fn send_on_1_of_20(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 1, 20);
        }

        #[bench]
        fn send_on_5_of_20(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 5, 20);
        }

        #[bench]
        fn send_on_20_of_20(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 20, 20);
        }

        #[bench]
        fn send_on_1_of_100(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 1, 100);
        }

        #[bench]
        fn send_on_5_of_100(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 5, 100);
        }
        #[bench]
        fn send_on_20_of_100(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 20, 100);
        }

        #[bench]
        fn send_on_100_of_100(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 100, 100);
        }

        fn create_set_of_n(n: usize) -> IpcReceiverSet {
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..n {
                let (_, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
            }
            rx_set
        }

        #[bench]
        fn create_and_destroy_empty_set(b: &mut test::Bencher) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    create_set_of_n(0);
                }
            });
        }

        #[bench]
        fn create_and_destroy_set_of_1(b: &mut test::Bencher) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    create_set_of_n(1);
                }
            });
        }

        #[bench]
        fn create_and_destroy_set_of_10(b: &mut test::Bencher) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    create_set_of_n(10);
                }
            });
        }

        #[bench]
        fn create_and_destroy_set_of_100(b: &mut test::Bencher) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    create_set_of_n(100);
                }
            });
        }

        // Benchmark performance of removing closed receivers from set.
        // This also includes the time for adding receivers,
        // as there is no way to measure the removing in isolation.
        fn bench_remove_closed(b: &mut test::Bencher, n: usize) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    // We could keep adding/removing senders to the same set,
                    // instead of creating a new one in each iteration.
                    // However, this would actually make the results harder to compare...
                    let mut rx_set = create_set_of_n(n);

                    let mut dropped_count = 0;
                    while dropped_count < n {
                        // On `select()`, receivers with a "ClosedChannel" event will be closed,
                        // and automatically dropped from the set.
                        dropped_count += rx_set.select().unwrap().len();
                    }
                }
            });
        }

        #[bench]
        fn add_and_remove_1_closed_receivers(b: &mut test::Bencher) {
            bench_remove_closed(b, 1);
        }

        #[bench]
        fn add_and_remove_10_closed_receivers(b: &mut test::Bencher) {
            bench_remove_closed(b, 10);
        }

        #[bench]
        fn add_and_remove_100_closed_receivers(b: &mut test::Bencher) {
            bench_remove_closed(b, 100);
        }
    }
}
<commit_msg>Benchmarks: Add benchmarks for channel transfer<commit_after>#![feature(test)]

extern crate ipc_channel;
extern crate test;

/// Allows doing multiple inner iterations per bench.iter() run.
///
/// This is mostly to amortise the overhead of spawning a thread in the benchmark
/// when sending larger messages (that might be fragmented).
///
/// Note that you need to compensate the displayed results
/// for the proportionally longer runs yourself,
/// as the benchmark framework doesn't know about the inner iterations...
const ITERATIONS: usize = 1;

mod platform {
    extern crate crossbeam;

    use ipc_channel::platform;
    use ITERATIONS;

    use std::sync::{mpsc, Mutex};
    use test;

    #[bench]
    fn create_channel(b: &mut test::Bencher) {
        b.iter(|| {
            for _ in 0..ITERATIONS {
                platform::channel().unwrap();
            }
        });
    }

    fn bench_transfer_data(b: &mut test::Bencher, size: usize) {
        let data: Vec<u8> = (0..size).map(|i| (i % 251) as u8).collect();
        let (tx, rx) = platform::channel().unwrap();

        let (wait_tx, wait_rx) = mpsc::channel();
        let wait_rx = Mutex::new(wait_rx);

        if size > platform::OsIpcSender::get_max_fragment_size() {
            b.iter(|| {
                crossbeam::scope(|scope| {
                    let tx = tx.clone();
                    scope.spawn(|| {
                        let wait_rx = wait_rx.lock().unwrap();
                        let tx = tx;
                        for _ in 0..ITERATIONS {
                            tx.send(&data, vec![], vec![]).unwrap();
                            if ITERATIONS > 1 {
                                // Prevent beginning of the next send
                                // from overlapping with receive of last fragment,
                                // as otherwise results of runs with a large tail fragment
                                // are significantly skewed.
                                wait_rx.recv().unwrap();
                            }
                        }
                    });
                    for _ in 0..ITERATIONS {
                        rx.recv().unwrap();
                        if ITERATIONS > 1 {
                            wait_tx.send(()).unwrap();
                        }
                    }
                    // For reasons mysterious to me,
                    // not returning a value *from every branch*
                    // adds some 100 ns or so of overhead to all results --
                    // which is quite significant for very short tests...
                    0
                })
            });
        } else {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    tx.send(&data, vec![], vec![]).unwrap();
                    rx.recv().unwrap();
                }
                0
            });
        }
    }

    #[bench]
    fn transfer_data_00_1(b: &mut test::Bencher) {
        bench_transfer_data(b, 1);
    }
    #[bench]
    fn transfer_data_01_2(b: &mut test::Bencher) {
        bench_transfer_data(b, 2);
    }
    #[bench]
    fn transfer_data_02_4(b: &mut test::Bencher) {
        bench_transfer_data(b, 4);
    }
    #[bench]
    fn transfer_data_03_8(b: &mut test::Bencher) {
        bench_transfer_data(b, 8);
    }
    #[bench]
    fn transfer_data_04_16(b: &mut test::Bencher) {
        bench_transfer_data(b, 16);
    }
    #[bench]
    fn transfer_data_05_32(b: &mut test::Bencher) {
        bench_transfer_data(b, 32);
    }
    #[bench]
    fn transfer_data_06_64(b: &mut test::Bencher) {
        bench_transfer_data(b, 64);
    }
    #[bench]
    fn transfer_data_07_128(b: &mut test::Bencher) {
        bench_transfer_data(b, 128);
    }
    #[bench]
    fn transfer_data_08_256(b: &mut test::Bencher) {
        bench_transfer_data(b, 256);
    }
    #[bench]
    fn transfer_data_09_512(b: &mut test::Bencher) {
        bench_transfer_data(b, 512);
    }
    #[bench]
    fn transfer_data_10_1k(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024);
    }
    #[bench]
    fn transfer_data_11_2k(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024);
    }
    #[bench]
    fn transfer_data_12_4k(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024);
    }
    #[bench]
    fn transfer_data_13_8k(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024);
    }
    #[bench]
    fn transfer_data_14_16k(b: &mut test::Bencher) {
        bench_transfer_data(b, 16 * 1024);
    }
    #[bench]
    fn transfer_data_15_32k(b: &mut test::Bencher) {
        bench_transfer_data(b, 32 * 1024);
    }
    #[bench]
    fn transfer_data_16_64k(b: &mut test::Bencher) {
        bench_transfer_data(b, 64 * 1024);
    }
    #[bench]
    fn transfer_data_17_128k(b: &mut test::Bencher) {
        bench_transfer_data(b, 128 * 1024);
    }
    #[bench]
    fn transfer_data_18_256k(b: &mut test::Bencher) {
        bench_transfer_data(b, 256 * 1024);
    }
    #[bench]
    fn transfer_data_19_512k(b: &mut test::Bencher) {
        bench_transfer_data(b, 512 * 1024);
    }
    #[bench]
    fn transfer_data_20_1m(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_21_2m(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_22_4m(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_23_8m(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024 * 1024);
    }
}

mod ipc {
    use ipc_channel::ipc;
    use ITERATIONS;

    use test;

    #[bench]
    fn transfer_empty(b: &mut test::Bencher) {
        let (tx, rx) = ipc::channel().unwrap();
        b.iter(|| {
            for _ in 0..ITERATIONS {
                tx.send(()).unwrap();
                rx.recv().unwrap()
            }
        });
    }

    fn bench_transfer_senders(b: &mut test::Bencher, count: usize) {
        let (main_tx, main_rx) = ipc::channel().unwrap();
        let transfer_txs: Vec<_> = (0..count).map(|_| ipc::channel::<()>().unwrap())
                                             .map(|(tx, _)| tx).collect();
        let mut transfer_txs = Some(transfer_txs);
        b.iter(|| {
            for _ in 0..ITERATIONS {
                main_tx.send(transfer_txs.take().unwrap()).unwrap();
                transfer_txs = Some(main_rx.recv().unwrap());
            }
        });
    }

    #[bench]
    fn transfer_senders_00(b: &mut test::Bencher) {
        bench_transfer_senders(b, 0);
    }

    #[bench]
    fn transfer_senders_01(b: &mut test::Bencher) {
        bench_transfer_senders(b, 1);
    }

    #[bench]
    fn transfer_senders_08(b: &mut test::Bencher) {
        bench_transfer_senders(b, 8);
    }

    #[bench]
    fn transfer_senders_64(b: &mut test::Bencher) {
        bench_transfer_senders(b, 64);
    }

    fn bench_transfer_receivers(b: &mut test::Bencher, count: usize) {
        let (main_tx, main_rx) = ipc::channel().unwrap();
        let transfer_rxs: Vec<_> = (0..count).map(|_| ipc::channel::<()>().unwrap())
                                             .map(|(_, rx)| rx).collect();
        let mut transfer_rxs = Some(transfer_rxs);
        b.iter(|| {
            for _ in 0..ITERATIONS {
                main_tx.send(transfer_rxs.take().unwrap()).unwrap();
                transfer_rxs = Some(main_rx.recv().unwrap());
            }
        });
    }

    #[bench]
    fn transfer_receivers_00(b: &mut test::Bencher) {
        bench_transfer_receivers(b, 0);
    }

    #[bench]
    fn transfer_receivers_01(b: &mut test::Bencher) {
        bench_transfer_receivers(b, 1);
    }

    #[bench]
    fn transfer_receivers_08(b: &mut test::Bencher) {
        bench_transfer_receivers(b, 8);
    }

    #[bench]
    fn transfer_receivers_64(b: &mut test::Bencher) {
        bench_transfer_receivers(b, 64);
    }

    mod receiver_set {
        use ipc_channel::ipc::{self, IpcReceiverSet};
        use ITERATIONS;

        use test;

        // Benchmark selecting over a set of `n` receivers,
        // with `to_send` of them actually having pending data.
        fn bench_send_on_m_of_n(b: &mut test::Bencher, to_send: usize, n: usize) {
            let mut senders = Vec::with_capacity(n);
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..n {
                let (tx, rx) = ipc::channel().unwrap();
                rx_set.add(rx).unwrap();
                senders.push(tx);
            }
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    for tx in senders.iter().take(to_send) {
                        tx.send(()).unwrap();
                    }
                    let mut received = 0;
                    while received < to_send {
                        received += rx_set.select().unwrap().len();
                    }
                }
            });
        }

        #[bench]
        fn send_on_1_of_1(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 1, 1);
        }

        #[bench]
        fn send_on_1_of_5(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 1, 5);
        }

        #[bench]
        fn send_on_2_of_5(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 2, 5);
        }

        #[bench]
        fn send_on_5_of_5(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 5, 5);
        }

        #[bench]
        fn send_on_1_of_20(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 1, 20);
        }

        #[bench]
        fn send_on_5_of_20(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 5, 20);
        }

        #[bench]
        fn send_on_20_of_20(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 20, 20);
        }

        #[bench]
        fn send_on_1_of_100(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 1, 100);
        }

        #[bench]
        fn send_on_5_of_100(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 5, 100);
        }
        #[bench]
        fn send_on_20_of_100(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 20, 100);
        }

        #[bench]
        fn send_on_100_of_100(b: &mut test::Bencher) {
            bench_send_on_m_of_n(b, 100, 100);
        }

        fn create_set_of_n(n: usize) -> IpcReceiverSet {
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..n {
                let (_, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
            }
            rx_set
        }

        #[bench]
        fn create_and_destroy_empty_set(b: &mut test::Bencher) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    create_set_of_n(0);
                }
            });
        }

        #[bench]
        fn create_and_destroy_set_of_1(b: &mut test::Bencher) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    create_set_of_n(1);
                }
            });
        }

        #[bench]
        fn create_and_destroy_set_of_10(b: &mut test::Bencher) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    create_set_of_n(10);
                }
            });
        }

        #[bench]
        fn create_and_destroy_set_of_100(b: &mut test::Bencher) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    create_set_of_n(100);
                }
            });
        }

        // Benchmark performance of removing closed receivers from set.
        // This also includes the time for adding receivers,
        // as there is no way to measure the removing in isolation.
        fn bench_remove_closed(b: &mut test::Bencher, n: usize) {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    // We could keep adding/removing senders to the same set,
                    // instead of creating a new one in each iteration.
                    // However, this would actually make the results harder to compare...
                    let mut rx_set = create_set_of_n(n);

                    let mut dropped_count = 0;
                    while dropped_count < n {
                        // On `select()`, receivers with a "ClosedChannel" event will be closed,
                        // and automatically dropped from the set.
                        dropped_count += rx_set.select().unwrap().len();
                    }
                }
            });
        }

        #[bench]
        fn add_and_remove_1_closed_receivers(b: &mut test::Bencher) {
            bench_remove_closed(b, 1);
        }

        #[bench]
        fn add_and_remove_10_closed_receivers(b: &mut test::Bencher) {
            bench_remove_closed(b, 10);
        }

        #[bench]
        fn add_and_remove_100_closed_receivers(b: &mut test::Bencher) {
            bench_remove_closed(b, 100);
        }
    }
}
<|endoftext|>