<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::path::{Path, PathBuf};
use std::process::Command;

use devicemapper::{Bytes, DmDevice, DM, IEC, SECTOR_SIZE, Sectors, ThinDev, ThinDevId, ThinStatus,
                   ThinPoolDev};

use nix::sys::statvfs::statvfs;
use nix::sys::statvfs::vfs::Statvfs;

use super::super::engine::{Filesystem, HasName, HasUuid};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::FilesystemUuid;

use super::serde_structs::{FilesystemSave, Recordable};

/// TODO: confirm that 256 MiB leaves enough time for stratisd to respond and extend before
/// the filesystem is out of space.
pub const FILESYSTEM_LOWATER: Sectors = Sectors(256 * IEC::Mi / (SECTOR_SIZE as u64)); // = 256 MiB

#[derive(Debug)]
pub struct StratFilesystem {
    fs_id: FilesystemUuid,
    name: String,
    thin_dev: ThinDev,
}

pub enum FilesystemStatus {
    Good,
    XfsGrowFailed,
    ThinDevExtendFailed,
    Failed,
}

impl StratFilesystem {
    /// Create a StratFilesystem on top of the given ThinDev.
    pub fn initialize(fs_id: FilesystemUuid,
                      name: &str,
                      thin_dev: ThinDev)
                      -> EngineResult<StratFilesystem> {
        let fs = StratFilesystem::setup(fs_id, name, thin_dev);

        create_fs(fs.devnode().as_path())?;
        Ok(fs)
    }

    /// Build a StratFilesystem that includes the ThinDev and related info.
    pub fn setup(fs_id: FilesystemUuid, name: &str, thin_dev: ThinDev) -> StratFilesystem {
        StratFilesystem {
            fs_id: fs_id,
            name: name.to_owned(),
            thin_dev: thin_dev,
        }
    }

    /// check if filesystem is getting full and needs to be extended
    /// TODO: deal with the thindev in a Fail state.
    pub fn check(&mut self, dm: &DM) -> EngineResult<FilesystemStatus> {
        match self.thin_dev.status(dm)? {
            ThinStatus::Good(_) => {
                let mount_point = self.get_mount_point()?;
                let (fs_total_bytes, fs_total_used_bytes) = fs_usage(&mount_point)?;
                let free_bytes = fs_total_bytes - fs_total_used_bytes;
                if free_bytes.sectors() < FILESYSTEM_LOWATER {
                    let extend_size = self.extend_size(self.thin_dev.size());
                    if self.thin_dev.extend(dm, extend_size).is_err() {
                        return Ok(FilesystemStatus::ThinDevExtendFailed);
                    }
                    if xfs_growfs(&mount_point).is_err() {
                        return Ok(FilesystemStatus::XfsGrowFailed);
                    }
                }
                // TODO: periodically kick off fstrim?
            }
            ThinStatus::Fail => return Ok(FilesystemStatus::Failed),
        }
        Ok(FilesystemStatus::Good)
    }

    /// The thin id for the thin device that backs this filesystem.
    pub fn thin_id(&self) -> ThinDevId {
        self.thin_dev.id()
    }

    /// Return an extend size for the thindev under the filesystem
    /// TODO: returning the current size will double the space provisoned to
    /// the thin device.  We should determine if this is a reasonable value.
    fn extend_size(&self, current_size: Sectors) -> Sectors {
        current_size
    }

    /// Get the mount_point for this filesystem
    /// TODO Replace this code with something less brittle
    pub fn get_mount_point(&self) -> EngineResult<PathBuf> {
        let output = Command::new("df")
            .arg("--output=target")
            .arg(&self.devnode())
            .output()?;
        if output.status.success() {
            let output_str = String::from_utf8_lossy(&output.stdout);
            if let Some(mount_point) = output_str.lines().last() {
                return Ok(PathBuf::from(mount_point));
            }
        }
        let err_msg = format!("Failed to get filesystem mountpoint at {:?}",
                              self.devnode());
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }

    /// Tear down the filesystem.
    pub fn teardown(self, dm: &DM) -> EngineResult<()> {
        Ok(self.thin_dev.teardown(dm)?)
    }

    /// Set the name of this filesystem to name.
    pub fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    /// Destroy the filesystem.
    pub fn destroy(self, dm: &DM, thin_pool: &ThinPoolDev) -> EngineResult<()> {
        Ok(self.thin_dev.destroy(dm, thin_pool)?)
    }
}

impl HasName for StratFilesystem {
    fn name(&self) -> &str {
        &self.name
    }
}

impl HasUuid for StratFilesystem {
    fn uuid(&self) -> &FilesystemUuid {
        &self.fs_id
    }
}

impl Filesystem for StratFilesystem {
    fn devnode(&self) -> PathBuf {
        self.thin_dev.devnode()
    }
}

impl Recordable<FilesystemSave> for StratFilesystem {
    fn record(&self) -> FilesystemSave {
        FilesystemSave {
            name: self.name.clone(),
            uuid: self.fs_id,
            thin_id: self.thin_dev.id(),
            size: self.thin_dev.size(),
        }
    }
}

/// Return total bytes allocated to the filesystem, total bytes used by data/metadata
pub fn fs_usage(mount_point: &Path) -> EngineResult<(Bytes, Bytes)> {
    let mut stat = Statvfs::default();
    statvfs(mount_point, &mut stat)?;
    Ok((Bytes(stat.f_bsize * stat.f_blocks), Bytes(stat.f_bsize * (stat.f_blocks - stat.f_bfree))))
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> EngineResult<()> {
    if Command::new("xfs_growfs")
           .arg(mount_point)
           .arg("-d")
           .status()?
           .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to expand filesystem {:?}", mount_point);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path) -> EngineResult<()> {
    if Command::new("mkfs.xfs")
           .arg("-f")
           .arg(&devnode)
           .status()?
           .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to create new filesystem at {:?}", devnode);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}
<commit_msg>Make XFS be quiet when it makes a filesystem<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::path::{Path, PathBuf};
use std::process::Command;

use devicemapper::{Bytes, DmDevice, DM, IEC, SECTOR_SIZE, Sectors, ThinDev, ThinDevId, ThinStatus,
                   ThinPoolDev};

use nix::sys::statvfs::statvfs;
use nix::sys::statvfs::vfs::Statvfs;

use super::super::engine::{Filesystem, HasName, HasUuid};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::FilesystemUuid;

use super::serde_structs::{FilesystemSave, Recordable};

/// TODO: confirm that 256 MiB leaves enough time for stratisd to respond and extend before
/// the filesystem is out of space.
pub const FILESYSTEM_LOWATER: Sectors = Sectors(256 * IEC::Mi / (SECTOR_SIZE as u64)); // = 256 MiB

#[derive(Debug)]
pub struct StratFilesystem {
    fs_id: FilesystemUuid,
    name: String,
    thin_dev: ThinDev,
}

pub enum FilesystemStatus {
    Good,
    XfsGrowFailed,
    ThinDevExtendFailed,
    Failed,
}

impl StratFilesystem {
    /// Create a StratFilesystem on top of the given ThinDev.
    pub fn initialize(fs_id: FilesystemUuid,
                      name: &str,
                      thin_dev: ThinDev)
                      -> EngineResult<StratFilesystem> {
        let fs = StratFilesystem::setup(fs_id, name, thin_dev);

        create_fs(fs.devnode().as_path())?;
        Ok(fs)
    }

    /// Build a StratFilesystem that includes the ThinDev and related info.
    pub fn setup(fs_id: FilesystemUuid, name: &str, thin_dev: ThinDev) -> StratFilesystem {
        StratFilesystem {
            fs_id: fs_id,
            name: name.to_owned(),
            thin_dev: thin_dev,
        }
    }

    /// check if filesystem is getting full and needs to be extended
    /// TODO: deal with the thindev in a Fail state.
    pub fn check(&mut self, dm: &DM) -> EngineResult<FilesystemStatus> {
        match self.thin_dev.status(dm)? {
            ThinStatus::Good(_) => {
                let mount_point = self.get_mount_point()?;
                let (fs_total_bytes, fs_total_used_bytes) = fs_usage(&mount_point)?;
                let free_bytes = fs_total_bytes - fs_total_used_bytes;
                if free_bytes.sectors() < FILESYSTEM_LOWATER {
                    let extend_size = self.extend_size(self.thin_dev.size());
                    if self.thin_dev.extend(dm, extend_size).is_err() {
                        return Ok(FilesystemStatus::ThinDevExtendFailed);
                    }
                    if xfs_growfs(&mount_point).is_err() {
                        return Ok(FilesystemStatus::XfsGrowFailed);
                    }
                }
                // TODO: periodically kick off fstrim?
            }
            ThinStatus::Fail => return Ok(FilesystemStatus::Failed),
        }
        Ok(FilesystemStatus::Good)
    }

    /// The thin id for the thin device that backs this filesystem.
    pub fn thin_id(&self) -> ThinDevId {
        self.thin_dev.id()
    }

    /// Return an extend size for the thindev under the filesystem
    /// TODO: returning the current size will double the space provisoned to
    /// the thin device.  We should determine if this is a reasonable value.
    fn extend_size(&self, current_size: Sectors) -> Sectors {
        current_size
    }

    /// Get the mount_point for this filesystem
    /// TODO Replace this code with something less brittle
    pub fn get_mount_point(&self) -> EngineResult<PathBuf> {
        let output = Command::new("df")
            .arg("--output=target")
            .arg(&self.devnode())
            .output()?;
        if output.status.success() {
            let output_str = String::from_utf8_lossy(&output.stdout);
            if let Some(mount_point) = output_str.lines().last() {
                return Ok(PathBuf::from(mount_point));
            }
        }
        let err_msg = format!("Failed to get filesystem mountpoint at {:?}",
                              self.devnode());
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }

    /// Tear down the filesystem.
    pub fn teardown(self, dm: &DM) -> EngineResult<()> {
        Ok(self.thin_dev.teardown(dm)?)
    }

    /// Set the name of this filesystem to name.
    pub fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    /// Destroy the filesystem.
    pub fn destroy(self, dm: &DM, thin_pool: &ThinPoolDev) -> EngineResult<()> {
        Ok(self.thin_dev.destroy(dm, thin_pool)?)
    }
}

impl HasName for StratFilesystem {
    fn name(&self) -> &str {
        &self.name
    }
}

impl HasUuid for StratFilesystem {
    fn uuid(&self) -> &FilesystemUuid {
        &self.fs_id
    }
}

impl Filesystem for StratFilesystem {
    fn devnode(&self) -> PathBuf {
        self.thin_dev.devnode()
    }
}

impl Recordable<FilesystemSave> for StratFilesystem {
    fn record(&self) -> FilesystemSave {
        FilesystemSave {
            name: self.name.clone(),
            uuid: self.fs_id,
            thin_id: self.thin_dev.id(),
            size: self.thin_dev.size(),
        }
    }
}

/// Return total bytes allocated to the filesystem, total bytes used by data/metadata
pub fn fs_usage(mount_point: &Path) -> EngineResult<(Bytes, Bytes)> {
    let mut stat = Statvfs::default();
    statvfs(mount_point, &mut stat)?;
    Ok((Bytes(stat.f_bsize * stat.f_blocks), Bytes(stat.f_bsize * (stat.f_blocks - stat.f_bfree))))
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> EngineResult<()> {
    if Command::new("xfs_growfs")
           .arg(mount_point)
           .arg("-d")
           .status()?
           .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to expand filesystem {:?}", mount_point);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path) -> EngineResult<()> {
    if Command::new("mkfs.xfs")
           .arg("-f")
           .arg("-q")
           .arg(&devnode)
           .status()?
           .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to create new filesystem at {:?}", devnode);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}
<|endoftext|>


<commit_before>//! Plugin (SIP003)
//!
//! ```plain
//! +------------+                    +---------------------------+
//! |  SS Client +-- Local Loopback --+  Plugin Client (Tunnel)   +--+
//! +------------+                    +---------------------------+  |
//!                                                                  |
//!             Public Internet (Obfuscated/Transformed traffic) ==> |
//!                                                                  |
//! +------------+                    +---------------------------+  |
//! |  SS Server +-- Local Loopback --+  Plugin Server (Tunnel)   +--+
//! +------------+                    +---------------------------+
//! ```

use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener};

use subprocess::Popen;
use subprocess::Result as PopenResult;

use config::{Config, ServerAddr};

mod obfs_proxy;
mod ss_plugin;

/// Config for plugin
#[derive(Debug, Clone)]
pub struct PluginConfig {
    pub plugin: String,
    pub plugin_opt: Option<String>,
}

/// Mode of Plugin
#[derive(Debug, Clone, Copy)]
pub enum PluginMode {
    Server,
    Client,
}

/// Plugin holder
#[derive(Debug)]
pub struct Plugin {
    addr: ServerAddr,
    process: Popen,
}

impl Plugin {
    /// Get address of the plugin
    pub fn addr(&self) -> &ServerAddr {
        &self.addr
    }
}

impl Drop for Plugin {
    fn drop(&mut self) {
        debug!("Killing Plugin {:?}", self.process);
        let _ = self.process.terminate();
    }
}

/// Launch plugins in config
pub fn launch_plugin(config: &mut Config, mode: PluginMode) -> io::Result<Vec<Plugin>> {
    let mut plugins = Vec::new();

    for svr in &mut config.server {
        let mut svr_addr_opt = None;

        if let Some(c) = svr.plugin() {
            let loop_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
            let local_addr = SocketAddr::new(loop_ip, get_local_port()?);

            let svr_addr = match start_plugin(c, svr.addr(), &local_addr, mode) {
                Err(err) => {
                    panic!("Failed to start plugin \"{}\", err: {}", c.plugin, err);
                }
                Ok(p) => {
                    let svr_addr = ServerAddr::SocketAddr(local_addr);
                    plugins.push(Plugin { addr: svr_addr.clone(),
                                          process: p, });

                    // Replace addr with plugin
                    svr_addr
                }
            };

            match mode {
                PluginMode::Client => info!("Started plugin \"{}\" on {} <-> {}", c.plugin, local_addr, svr.addr()),
                PluginMode::Server => info!("Started plugin \"{}\" on {} <-> {}", c.plugin, svr.addr(), local_addr),
            }

            svr_addr_opt = Some(svr_addr); // Fuck borrow checker
        }

        if let Some(svr_addr) = svr_addr_opt {
            svr.set_addr(svr_addr);
        }
    }

    Ok(plugins)
}

fn start_plugin(plugin: &PluginConfig,
                remote: &ServerAddr,
                local: &SocketAddr,
                mode: PluginMode)
                -> PopenResult<Popen> {
    if plugin.plugin == "obfsproxy" {
        obfs_proxy::start_plugin(plugin, remote, local, mode)
    } else {
        ss_plugin::start_plugin(plugin, remote, local, mode)
    }
}

fn get_local_port() -> io::Result<u16> {
    let listener = TcpListener::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0))?;
    let addr = listener.local_addr()?;
    Ok(addr.port())
}

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

    #[test]
    fn generate_random_port() {
        let port = get_local_port().unwrap();
        println!("{:?}", port);
    }
}
<commit_msg>Plugin must be sendable<commit_after>//! Plugin (SIP003)
//!
//! ```plain
//! +------------+                    +---------------------------+
//! |  SS Client +-- Local Loopback --+  Plugin Client (Tunnel)   +--+
//! +------------+                    +---------------------------+  |
//!                                                                  |
//!             Public Internet (Obfuscated/Transformed traffic) ==> |
//!                                                                  |
//! +------------+                    +---------------------------+  |
//! |  SS Server +-- Local Loopback --+  Plugin Server (Tunnel)   +--+
//! +------------+                    +---------------------------+
//! ```

use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener};

use subprocess::Popen;
use subprocess::Result as PopenResult;

use config::{Config, ServerAddr};

mod obfs_proxy;
mod ss_plugin;

/// Config for plugin
#[derive(Debug, Clone)]
pub struct PluginConfig {
    pub plugin: String,
    pub plugin_opt: Option<String>,
}

/// Mode of Plugin
#[derive(Debug, Clone, Copy)]
pub enum PluginMode {
    Server,
    Client,
}

/// Plugin holder
#[derive(Debug)]
pub struct Plugin {
    addr: ServerAddr,
    process: Popen,
}

/// Plugin can always be sent between threads
/// It contains only a handle to subprocess.
unsafe impl Send for Plugin {}

impl Plugin {
    /// Get address of the plugin
    pub fn addr(&self) -> &ServerAddr {
        &self.addr
    }
}

impl Drop for Plugin {
    fn drop(&mut self) {
        debug!("Killing Plugin {:?}", self.process);
        let _ = self.process.terminate();
    }
}

/// Launch plugins in config
pub fn launch_plugin(config: &mut Config, mode: PluginMode) -> io::Result<Vec<Plugin>> {
    let mut plugins = Vec::new();

    for svr in &mut config.server {
        let mut svr_addr_opt = None;

        if let Some(c) = svr.plugin() {
            let loop_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
            let local_addr = SocketAddr::new(loop_ip, get_local_port()?);

            let svr_addr = match start_plugin(c, svr.addr(), &local_addr, mode) {
                Err(err) => {
                    panic!("Failed to start plugin \"{}\", err: {}", c.plugin, err);
                }
                Ok(p) => {
                    let svr_addr = ServerAddr::SocketAddr(local_addr);
                    plugins.push(Plugin { addr: svr_addr.clone(),
                                          process: p, });

                    // Replace addr with plugin
                    svr_addr
                }
            };

            match mode {
                PluginMode::Client => info!("Started plugin \"{}\" on {} <-> {}", c.plugin, local_addr, svr.addr()),
                PluginMode::Server => info!("Started plugin \"{}\" on {} <-> {}", c.plugin, svr.addr(), local_addr),
            }

            svr_addr_opt = Some(svr_addr); // Fuck borrow checker
        }

        if let Some(svr_addr) = svr_addr_opt {
            svr.set_addr(svr_addr);
        }
    }

    Ok(plugins)
}

fn start_plugin(plugin: &PluginConfig,
                remote: &ServerAddr,
                local: &SocketAddr,
                mode: PluginMode)
                -> PopenResult<Popen> {
    if plugin.plugin == "obfsproxy" {
        obfs_proxy::start_plugin(plugin, remote, local, mode)
    } else {
        ss_plugin::start_plugin(plugin, remote, local, mode)
    }
}

fn get_local_port() -> io::Result<u16> {
    let listener = TcpListener::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0))?;
    let addr = listener.local_addr()?;
    Ok(addr.port())
}

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

    #[test]
    fn generate_random_port() {
        let port = get_local_port().unwrap();
        println!("{:?}", port);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variable)]

use super::mode;
use super::string_utils;

#[deriving(Show)]
#[deriving(Clone)]
enum DOC {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Nest(uint, Box<Doc>),
    Text(String),
    Break(uint, uint),
    Newline,
    Group(Box<Doc>)
}

pub type Doc = DOC;

fn fitting(xs:&Vec<(uint,mode::Mode,Doc)>, left:uint) -> bool {
    if left as int >= 0 {
        match xs.as_slice() {
            [] => true,
            [(ref i, ref mode, ref doc), ref rest..] => match *doc {
                Nil => fitting(&rest.to_vec(), left),
                Append(ref x, ref y) => {
                    let mut ys = [(*i,*mode,*x.clone()), (*i,*mode,*y.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys,left)
                },
                Nest(j, ref x) => {
                    let mut ys = [(*i+j,*mode,*x.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys, left)
                },
                Text(ref str) => fitting(&rest.to_vec(), left - str.len()),
                Break(sp, _) => match *mode {
                    mode::Flat => fitting(&rest.to_vec(), left - sp),
                    mode::Break => true
                },
                Newline => true,
                Group(ref x) => {
                    let mut ys = [(*i,*mode, *x.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys, left)
                }
            }
        }
    }
    else {
        false
    }
}

fn prepend<A:Clone>(v: Vec<A>, x:A) -> Vec<A> {
    let mut res = v;
    res.insert(0,x);
    res
}

fn best(w:uint, s:Vec<String>, x:Doc) -> Vec<String> {
    fn go(w:uint, s:Vec<String>, k:uint, xs:Vec<(uint,mode::Mode,Doc)>) -> Vec<String> {
        match xs.as_slice() {
            [] => s.clone(),
            [(ref i, ref mode, ref doc), ref rest..] => match *doc {
                Nil => go(w, s, k, rest.to_vec()),
                Append(ref x, ref y) => {
                    let mut zs = [(*i, *mode, *x.clone()), (*i, *mode, *y.clone())].to_vec();
                    zs.push_all(*rest);
                    go(w, s, k, zs)
                },
                Nest(j, ref x) => {
                    let mut zs = [(*i + j, *mode, *x.clone())].to_vec();
                    zs.push_all(*rest);
                    go(w, s, k, zs)
                },
                Text(ref str) => go(w, prepend(s, str.clone()), k + str.len(), rest.to_vec()),
                Newline => go(w, prepend(s, string_utils::nl_space(*i)), *i, rest.to_vec()),
                Break(sp, off) => {
                    match *mode {
                        mode::Flat => go(w, prepend(s.clone(), string_utils::spaces(sp)), k + sp, rest.to_vec()),
                        mode::Break => go(w, prepend(s.clone(), string_utils::nl_space(i + off)), i + off, rest.to_vec())
                    }
                },
                Group(ref x) => {
                    match *mode {
                        mode::Flat => {
                            let mut zs = [(*i,mode::Flat,*x.clone())].to_vec();
                            zs.push_all(*rest);
                            go(w, s, k, zs)
                        },
                        mode::Break => {
                            let mut ys = [(*i,mode::Flat,*x.clone())].to_vec();
                            ys.push_all(*rest);
                            if fitting(&ys, w - k) {
                                go(w, s, k, ys)
                            } else {
                                let mut zs = [(*i,mode::Break,*x.clone())].to_vec();
                                zs.push_all(*rest);
                                go(w, s, k, zs)
                            }
                        }
                    }
                }
            }
        }
    }
    go(w, s, 0, [(0,mode::Break,x)].to_vec())
}

impl Doc {

    pub fn nil() -> Doc {
        Nil
    }

    pub fn append(&self, e:Doc) -> Doc {
        match *self {
            Nil => e,
            ref x => match e {
                Nil => x.clone(),
                y => Append(box x.clone(), box y)
            }
        }
    }

    pub fn nest(&self, i:uint) -> Doc {
        Nest(i, box self.clone())
    }

    pub fn text(str:String) -> Doc {
        Text(str)
    }

    pub fn str(str:&str) -> Doc {
        Text(String::from_str(str))
    }

    pub fn brk(space:uint, offset:uint) -> Doc {
        Break(space, offset)
    }

    pub fn newline() -> Doc {
        Newline
    }

    pub fn group(&self) -> Doc {
        Group(box self.clone())
    }

    pub fn concat(ds:&[Doc]) -> Doc {
        ds.iter().fold(Nil, |a, b| a.append(b.clone()))
    }

    pub fn int(i:int) -> Doc {
        Text(format!("{}", i))
    }

    pub fn char(c:char) -> Doc {
        Text(format!("{}", c))
    }

    pub fn bool(b:bool) -> Doc {
        let res = if b { "true" } else { "false" };
        Text(String::from_str(res))
    }

    pub fn to_string(&self, w:uint) -> String {
        let mut strs = best(w, Vec::new(), self.clone());
        strs.reverse();
        strs.push(String::from_str("\n"));
        strs.concat()
    }
}

<commit_msg>Remove unnecessary pragmas<commit_after>use super::mode;
use super::string_utils;

#[deriving(Show)]
#[deriving(Clone)]
enum DOC {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Nest(uint, Box<Doc>),
    Text(String),
    Break(uint, uint),
    Newline,
    Group(Box<Doc>)
}

pub type Doc = DOC;

fn fitting(xs:&Vec<(uint,mode::Mode,Doc)>, left:uint) -> bool {
    if left as int >= 0 {
        match xs.as_slice() {
            [] => true,
            [(ref i, ref mode, ref doc), ref rest..] => match *doc {
                Nil => fitting(&rest.to_vec(), left),
                Append(ref x, ref y) => {
                    let mut ys = [(*i,*mode,*x.clone()), (*i,*mode,*y.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys,left)
                },
                Nest(j, ref x) => {
                    let mut ys = [(*i+j,*mode,*x.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys, left)
                },
                Text(ref str) => fitting(&rest.to_vec(), left - str.len()),
                Break(sp, _) => match *mode {
                    mode::Flat => fitting(&rest.to_vec(), left - sp),
                    mode::Break => true
                },
                Newline => true,
                Group(ref x) => {
                    let mut ys = [(*i,*mode, *x.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys, left)
                }
            }
        }
    }
    else {
        false
    }
}

fn prepend<A:Clone>(v: Vec<A>, x:A) -> Vec<A> {
    let mut res = v;
    res.insert(0,x);
    res
}

fn best(w:uint, s:Vec<String>, x:Doc) -> Vec<String> {
    fn go(w:uint, s:Vec<String>, k:uint, xs:Vec<(uint,mode::Mode,Doc)>) -> Vec<String> {
        match xs.as_slice() {
            [] => s.clone(),
            [(ref i, ref mode, ref doc), ref rest..] => match *doc {
                Nil => go(w, s, k, rest.to_vec()),
                Append(ref x, ref y) => {
                    let mut zs = [(*i, *mode, *x.clone()), (*i, *mode, *y.clone())].to_vec();
                    zs.push_all(*rest);
                    go(w, s, k, zs)
                },
                Nest(j, ref x) => {
                    let mut zs = [(*i + j, *mode, *x.clone())].to_vec();
                    zs.push_all(*rest);
                    go(w, s, k, zs)
                },
                Text(ref str) => go(w, prepend(s, str.clone()), k + str.len(), rest.to_vec()),
                Newline => go(w, prepend(s, string_utils::nl_space(*i)), *i, rest.to_vec()),
                Break(sp, off) => {
                    match *mode {
                        mode::Flat => go(w, prepend(s.clone(), string_utils::spaces(sp)), k + sp, rest.to_vec()),
                        mode::Break => go(w, prepend(s.clone(), string_utils::nl_space(i + off)), i + off, rest.to_vec())
                    }
                },
                Group(ref x) => {
                    match *mode {
                        mode::Flat => {
                            let mut zs = [(*i,mode::Flat,*x.clone())].to_vec();
                            zs.push_all(*rest);
                            go(w, s, k, zs)
                        },
                        mode::Break => {
                            let mut ys = [(*i,mode::Flat,*x.clone())].to_vec();
                            ys.push_all(*rest);
                            if fitting(&ys, w - k) {
                                go(w, s, k, ys)
                            } else {
                                let mut zs = [(*i,mode::Break,*x.clone())].to_vec();
                                zs.push_all(*rest);
                                go(w, s, k, zs)
                            }
                        }
                    }
                }
            }
        }
    }
    go(w, s, 0, [(0,mode::Break,x)].to_vec())
}

impl Doc {

    pub fn nil() -> Doc {
        Nil
    }

    pub fn append(&self, e:Doc) -> Doc {
        match *self {
            Nil => e,
            ref x => match e {
                Nil => x.clone(),
                y => Append(box x.clone(), box y)
            }
        }
    }

    pub fn nest(&self, i:uint) -> Doc {
        Nest(i, box self.clone())
    }

    pub fn text(str:String) -> Doc {
        Text(str)
    }

    pub fn str(str:&str) -> Doc {
        Text(String::from_str(str))
    }

    pub fn brk(space:uint, offset:uint) -> Doc {
        Break(space, offset)
    }

    pub fn newline() -> Doc {
        Newline
    }

    pub fn group(&self) -> Doc {
        Group(box self.clone())
    }

    pub fn concat(ds:&[Doc]) -> Doc {
        ds.iter().fold(Nil, |a, b| a.append(b.clone()))
    }

    pub fn int(i:int) -> Doc {
        Text(format!("{}", i))
    }

    pub fn char(c:char) -> Doc {
        Text(format!("{}", c))
    }

    pub fn bool(b:bool) -> Doc {
        let res = if b { "true" } else { "false" };
        Text(String::from_str(res))
    }

    pub fn to_string(&self, w:uint) -> String {
        let mut strs = best(w, Vec::new(), self.clone());
        strs.reverse();
        strs.push(String::from_str("\n"));
        strs.concat()
    }
}
<|endoftext|>


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

pub use self::Doc::{
    Nil,
    Append,
    Group,
    Nest,
    Newline,
    Text,
};

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
enum Mode {
    Break,
    Flat,
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Doc<'a, B> {
    Nil,
    Append(B, B),
    Group(B),
    Nest(usize, B),
    Newline,
    Text(::std::borrow::Cow<'a, str>),
}

impl<'a, B> Doc<'a, B> {
    #[inline]
    pub fn render<'b, W: io::Write>(&'b self, width: usize, out: &mut W) -> io::Result<()>
    where B: Deref<Target = Doc<'b, B>>
    {
        best(self, width, out).and_then(|()| out.write_all(b"\n"))
    }
}

type Cmd<'a, B> = (usize, Mode, &'a Doc<'a, B>);

#[inline]
fn fitting<'a, B>(
    next: Cmd<'a, B>,
    bcmds: &Vec<Cmd<'a, B>>,
    fcmds: &mut Vec<Cmd<'a, B>>,
    mut rem: isize,
) -> bool
where B: Deref<Target = Doc<'a, B>>
{
    let mut bidx = bcmds.len();
    let mut fits = true;
    fcmds.clear(); // clear from previous calls from best
    fcmds.push(next);
    loop {
        if rem < 0 {
            fits = false;
            break;
        }
        match fcmds.pop() {
            None => {
                if bidx == 0 {
                    break;
                } else {
                    fcmds.push(bcmds[ bidx - 1 ]);
                    bidx -= 1;
                }
            },
            Some((ind, mode, doc)) => match doc {
                &Nil => {
                },
                &Append(ref ldoc, ref rdoc) => {
                    fcmds.push((ind, mode, rdoc));
                    fcmds.push((ind, mode, ldoc));
                },
                &Group(ref doc) => {
                    fcmds.push((ind, mode, doc));
                },
                &Nest(off, ref doc) => {
                    fcmds.push((ind + off, mode, doc));
                },
                &Newline => {
                    fits = true;
                },
                &Text(ref str) => {
                    rem -= str.len() as isize;
                },
            }
        }
    }
    fits
}

#[inline]
pub fn best<'a, W: io::Write, B>(
    doc: &'a Doc<'a, B>,
    width: usize,
    out: &mut W,
) -> io::Result<()>
where B: Deref<Target = Doc<'a, B>>
{
    let mut pos = 0usize;
    let mut bcmds = vec![(0usize, Mode::Break, doc)];
    let mut fcmds = vec![];
    while let Some((ind, mode, doc)) = bcmds.pop() {
        match doc {
            &Nil => {
            },
            &Append(ref ldoc, ref rdoc) => {
                bcmds.push((ind, mode, rdoc));
                bcmds.push((ind, mode, ldoc));
            },
            &Group(ref doc) => match mode {
                Mode::Flat => {
                    bcmds.push((ind, Mode::Flat, doc));
                },
                Mode::Break => {
                    let next = (ind, Mode::Flat, &**doc);
                    let rem = width as isize - pos as isize;
                    if fitting(next, &bcmds, &mut fcmds, rem) {
                        bcmds.push(next);
                    } else {
                        bcmds.push((ind, Mode::Break, doc));
                    }
                }
            },
            &Nest(off, ref doc) => {
                bcmds.push((ind + off, mode, doc));
            },
            &Newline => {
                const SPACES: [u8; 100] = [b' '; 100];
                try!(out.write_all(b"\n"));
                let mut inserted = 0;
                while inserted < ind {
                    let insert = cmp::min(100, ind - inserted);
                    inserted += insert;
                    try!(out.write_all(&SPACES[..insert]));
                }
                pos = ind;
            },
            &Text(ref s) => {
                try!(out.write_all(&s.as_bytes()));
                pos += s.len();
            },
        }
    }
    Ok(())
}
<commit_msg>Insert a space instead of newline when encountering the NewLine doc in flat mode<commit_after>use std::cmp;
use std::io;
use std::ops::Deref;

pub use self::Doc::{
    Nil,
    Append,
    Group,
    Nest,
    Newline,
    Text,
};

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
enum Mode {
    Break,
    Flat,
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Doc<'a, B> {
    Nil,
    Append(B, B),
    Group(B),
    Nest(usize, B),
    Newline,
    Text(::std::borrow::Cow<'a, str>),
}

impl<'a, B> Doc<'a, B> {
    #[inline]
    pub fn render<'b, W: io::Write>(&'b self, width: usize, out: &mut W) -> io::Result<()>
    where B: Deref<Target = Doc<'b, B>>
    {
        best(self, width, out).and_then(|()| out.write_all(b"\n"))
    }
}

type Cmd<'a, B> = (usize, Mode, &'a Doc<'a, B>);

#[inline]
fn fitting<'a, B>(
    next: Cmd<'a, B>,
    bcmds: &Vec<Cmd<'a, B>>,
    fcmds: &mut Vec<Cmd<'a, B>>,
    mut rem: isize,
) -> bool
where B: Deref<Target = Doc<'a, B>>
{
    let mut bidx = bcmds.len();
    let mut fits = true;
    fcmds.clear(); // clear from previous calls from best
    fcmds.push(next);
    loop {
        if rem < 0 {
            fits = false;
            break;
        }
        match fcmds.pop() {
            None => {
                if bidx == 0 {
                    break;
                } else {
                    fcmds.push(bcmds[ bidx - 1 ]);
                    bidx -= 1;
                }
            },
            Some((ind, mode, doc)) => match doc {
                &Nil => {
                },
                &Append(ref ldoc, ref rdoc) => {
                    fcmds.push((ind, mode, rdoc));
                    fcmds.push((ind, mode, ldoc));
                },
                &Group(ref doc) => {
                    fcmds.push((ind, mode, doc));
                },
                &Nest(off, ref doc) => {
                    fcmds.push((ind + off, mode, doc));
                },
                &Newline => {
                    fits = true;
                },
                &Text(ref str) => {
                    rem -= str.len() as isize;
                },
            }
        }
    }
    fits
}

#[inline]
pub fn best<'a, W: io::Write, B>(
    doc: &'a Doc<'a, B>,
    width: usize,
    out: &mut W,
) -> io::Result<()>
where B: Deref<Target = Doc<'a, B>>
{
    let mut pos = 0usize;
    let mut bcmds = vec![(0usize, Mode::Break, doc)];
    let mut fcmds = vec![];
    while let Some((ind, mode, doc)) = bcmds.pop() {
        match doc {
            &Nil => {
            },
            &Append(ref ldoc, ref rdoc) => {
                bcmds.push((ind, mode, rdoc));
                bcmds.push((ind, mode, ldoc));
            },
            &Group(ref doc) => match mode {
                Mode::Flat => {
                    bcmds.push((ind, Mode::Flat, doc));
                },
                Mode::Break => {
                    let next = (ind, Mode::Flat, &**doc);
                    let rem = width as isize - pos as isize;
                    if fitting(next, &bcmds, &mut fcmds, rem) {
                        bcmds.push(next);
                    } else {
                        bcmds.push((ind, Mode::Break, doc));
                    }
                }
            },
            &Nest(off, ref doc) => {
                bcmds.push((ind + off, mode, doc));
            },
            &Newline => {
                match mode {
                    Mode::Flat => {
                        try!(out.write_all(b" "));
                    },
                    Mode::Break => {
                        const SPACES: [u8; 100] = [b' '; 100];
                        try!(out.write_all(b"\n"));
                        let mut inserted = 0;
                        while inserted < ind {
                            let insert = cmp::min(100, ind - inserted);
                            inserted += insert;
                            try!(out.write_all(&SPACES[..insert]));
                        }
                    },
                }
                pos = ind;
            },
            &Text(ref s) => {
                try!(out.write_all(&s.as_bytes()));
                pos += s.len();
            },
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::io::buffered::BufferedStream;
use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::vec::bytes::push_bytes;

pub enum Result {
  Nil,
  Int(int),
  Data(~[u8]),
  List(~[Result]),
  Error(~str),
  Status(~str)
}

fn read_char(io: &mut BufferedStream<TcpStream>) -> char {
  match io.read_byte() {
    Some(ch) => ch as char,
    None     => fail!()
  }
}

fn parse_data(len: uint, io: &mut BufferedStream<TcpStream>) -> Result {
  let res =
    if (len > 0) {
      let bytes = io.read_bytes(len);
      assert!(bytes.len() == len);
      Data(bytes)
    } else {
      Data(~[])
    };
  assert!(io.read_byte() == Some(13));
  assert!(io.read_byte() == Some(10));
  return res;
}

fn parse_list(len: uint, io: &mut BufferedStream<TcpStream>) -> Result {
  List(std::vec::from_fn(len, |_| { parse_response(io) }))
}

fn parse_int_line(io: &mut BufferedStream<TcpStream>) -> int {
  let mut i: int = 0;
  let mut digits: uint = 0;
  let mut negative: bool = false;

  loop {
    let ch = read_char(io);
    match ch {
      '0' .. '9' => {
        digits += 1;
        i = (i * 10) + (ch as int - '0' as int);
        },
      '-' => {
        if negative { fail!() }
        negative = true
        },
      '\r' => {
        assert!(read_char(io) == '\n');
        break
        },
      '\n' => break,
      _ => fail!()
    }
  }

  if digits == 0 { fail!() }

  if negative { -i }
  else { i }
}

fn parse_n(io: &mut BufferedStream<TcpStream>, f: |uint, &mut BufferedStream<TcpStream>| -> Result) -> Result {
  match parse_int_line(io) {
    -1 => Nil,
    len if len >= 0 => f(len as uint, io),
    _ => fail!()
  }
}

fn parse_status(io: &mut BufferedStream<TcpStream>) -> Result {
  match io.read_line() {
    Some(line) => Status(line),
    None       => fail!()
  }
}

fn parse_error(io: &mut BufferedStream<TcpStream>) -> Result {
  match io.read_line() {
    Some(line) => Error(line),
    None       => fail!()
  }
}

fn parse_response(io: &mut BufferedStream<TcpStream>) -> Result {
  match read_char(io) {
    '$' => parse_n(io, parse_data),
    '*' => parse_n(io, parse_list),
    '+' => parse_status(io),
    '-' => parse_error(io),
    ':' => Int(parse_int_line(io)),
    _   => fail!()
  }
}

struct CommandWriter {
  buf: ~[u8]
}

impl CommandWriter {
  fn new() -> CommandWriter {
    CommandWriter { buf: ~[] }
  }

  fn args(&mut self, n: uint) {
    self.write_char('*');
    self.write_uint(n);
    self.write_crnl();
  }

  fn arg(&mut self, arg: &str) {
    self.write_char('$');
    self.write_uint(arg.len());
    self.write_crnl();
    self.write_str(arg);
    self.write_crnl();
  }

  fn write_crnl(&mut self) {
    self.write_byte(13);
    self.write_byte(10);
  }

  fn write_uint(&mut self, n: uint) {
    if n < 10 {
      self.write_byte('0' as u8 + (n as u8));
    }
    else {
      push_bytes(&mut self.buf, n.to_str().into_bytes());
    }
  }

  fn write_str(&mut self, s: &str) {
    push_bytes(&mut self.buf, s.as_bytes());
  }

  fn write_char(&mut self, s: char) {
    self.buf.push(s as u8);
  }

  fn write_byte(&mut self, b: u8) {
    self.buf.push(b);
  }

  fn with_buf<T>(&self, f: |&[u8]| -> T) -> T {
    f(self.buf.as_slice())
  }
}

fn execute(cmd: &[u8], io: &mut BufferedStream<TcpStream>) -> Result {
  io.write(cmd);
  io.flush();
  parse_response(io)
}

pub struct Redis<'a> {
  priv io: &'a mut BufferedStream<TcpStream>
}

impl<'a> Redis<'a> {
  pub fn get(&mut self, key: &str) -> Result {
    let mut cwr = CommandWriter::new();
    cwr.args(2);
    cwr.arg("GET");
    cwr.arg(key);
    cwr.with_buf(|cmd| execute(cmd, self.io))
  }

  pub fn set(&mut self, key: &str, val: &str) -> Result {
    let mut cwr = CommandWriter::new();
    cwr.args(3);
    cwr.arg("SET");
    cwr.arg(key);
    cwr.arg(val);
    cwr.with_buf(|cmd| execute(cmd, self.io))
  }
}

fn main() {
  let addr = from_str::<SocketAddr>("127.0.0.1:6379").unwrap();
  let tcp_stream = TcpStream::connect(addr).unwrap();
  let mut reader = BufferedStream::new(tcp_stream);
  let mut redis = Redis { io: &mut reader };

  //let x = redis.get("key");
  //println!("{:?}", x);

  for i in std::iter::range(1, 100_000) {
    redis.set("key", "abc");
  }
}
<commit_msg>Replace 13 with \r and 10 with \r<commit_after>use std::io::buffered::BufferedStream;
use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::vec::bytes::push_bytes;

pub enum Result {
  Nil,
  Int(int),
  Data(~[u8]),
  List(~[Result]),
  Error(~str),
  Status(~str)
}

fn read_char(io: &mut BufferedStream<TcpStream>) -> char {
  match io.read_byte() {
    Some(ch) => ch as char,
    None     => fail!()
  }
}

fn parse_data(len: uint, io: &mut BufferedStream<TcpStream>) -> Result {
  let res =
    if (len > 0) {
      let bytes = io.read_bytes(len);
      assert!(bytes.len() == len);
      Data(bytes)
    } else {
      Data(~[])
    };
  assert!(read_char(io) == '\r');
  assert!(read_char(io) == '\n');
  return res;
}

fn parse_list(len: uint, io: &mut BufferedStream<TcpStream>) -> Result {
  List(std::vec::from_fn(len, |_| { parse_response(io) }))
}

fn parse_int_line(io: &mut BufferedStream<TcpStream>) -> int {
  let mut i: int = 0;
  let mut digits: uint = 0;
  let mut negative: bool = false;

  loop {
    let ch = read_char(io);
    match ch {
      '0' .. '9' => {
        digits += 1;
        i = (i * 10) + (ch as int - '0' as int);
        },
      '-' => {
        if negative { fail!() }
        negative = true
        },
      '\r' => {
        assert!(read_char(io) == '\n');
        break
        },
      '\n' => break,
      _ => fail!()
    }
  }

  if digits == 0 { fail!() }

  if negative { -i }
  else { i }
}

fn parse_n(io: &mut BufferedStream<TcpStream>, f: |uint, &mut BufferedStream<TcpStream>| -> Result) -> Result {
  match parse_int_line(io) {
    -1 => Nil,
    len if len >= 0 => f(len as uint, io),
    _ => fail!()
  }
}

fn parse_status(io: &mut BufferedStream<TcpStream>) -> Result {
  match io.read_line() {
    Some(line) => Status(line),
    None       => fail!()
  }
}

fn parse_error(io: &mut BufferedStream<TcpStream>) -> Result {
  match io.read_line() {
    Some(line) => Error(line),
    None       => fail!()
  }
}

fn parse_response(io: &mut BufferedStream<TcpStream>) -> Result {
  match read_char(io) {
    '$' => parse_n(io, parse_data),
    '*' => parse_n(io, parse_list),
    '+' => parse_status(io),
    '-' => parse_error(io),
    ':' => Int(parse_int_line(io)),
    _   => fail!()
  }
}

struct CommandWriter {
  buf: ~[u8]
}

impl CommandWriter {
  fn new() -> CommandWriter {
    CommandWriter { buf: ~[] }
  }

  fn args(&mut self, n: uint) {
    self.write_char('*');
    self.write_uint(n);
    self.write_crnl();
  }

  fn arg(&mut self, arg: &str) {
    self.write_char('$');
    self.write_uint(arg.len());
    self.write_crnl();
    self.write_str(arg);
    self.write_crnl();
  }

  fn write_crnl(&mut self) {
    self.write_char('\r');
    self.write_char('\n');
  }

  fn write_uint(&mut self, n: uint) {
    if n < 10 {
      self.write_byte('0' as u8 + (n as u8));
    }
    else {
      push_bytes(&mut self.buf, n.to_str().into_bytes());
    }
  }

  fn write_str(&mut self, s: &str) {
    push_bytes(&mut self.buf, s.as_bytes());
  }

  fn write_char(&mut self, s: char) {
    self.buf.push(s as u8);
  }

  fn write_byte(&mut self, b: u8) {
    self.buf.push(b);
  }

  fn with_buf<T>(&self, f: |&[u8]| -> T) -> T {
    f(self.buf.as_slice())
  }
}

fn execute(cmd: &[u8], io: &mut BufferedStream<TcpStream>) -> Result {
  io.write(cmd);
  io.flush();
  parse_response(io)
}

pub struct Redis<'a> {
  priv io: &'a mut BufferedStream<TcpStream>
}

impl<'a> Redis<'a> {
  pub fn get(&mut self, key: &str) -> Result {
    let mut cwr = CommandWriter::new();
    cwr.args(2);
    cwr.arg("GET");
    cwr.arg(key);
    cwr.with_buf(|cmd| execute(cmd, self.io))
  }

  pub fn set(&mut self, key: &str, val: &str) -> Result {
    let mut cwr = CommandWriter::new();
    cwr.args(3);
    cwr.arg("SET");
    cwr.arg(key);
    cwr.arg(val);
    cwr.with_buf(|cmd| execute(cmd, self.io))
  }
}

fn main() {
  let addr = from_str::<SocketAddr>("127.0.0.1:6379").unwrap();
  let tcp_stream = TcpStream::connect(addr).unwrap();
  let mut reader = BufferedStream::new(tcp_stream);
  let mut redis = Redis { io: &mut reader };

  //let x = redis.get("key");
  //println!("{:?}", x);

  for i in std::iter::range(1, 100_000) {
    redis.set("key", "abc");
  }
}
<|endoftext|>


<commit_before>//! fixed-point numerical types

use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};

// shared between Fixed and F2Dot14
macro_rules! fixed_impl {
    ($name:ident, $bits:literal, $fract_bits:literal, $ty:ty) => {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
        #[doc = concat!(stringify!($bits), "-bit signed fixed point number with ", stringify!($fract_bits), " bits of fraction." )]
        pub struct $name($ty);
        impl $name {
            /// Minimum value.
            pub const MIN: Self = Self(<$ty>::MIN);

            /// Maximum value.
            pub const MAX: Self = Self(<$ty>::MAX);

            /// This type's smallest representable value
            pub const EPSILON: Self = Self(1);

            /// Representation of 0.0.
            pub const ZERO: Self = Self(0);

            /// Representation of 1.0.
            pub const ONE: Self = Self(1 << $fract_bits);

            const INT_MASK: $ty = !0 << $fract_bits;
            const ROUND: $ty = 1 << ($fract_bits - 1);
            const FRACT_BITS: usize = $fract_bits;

            //TODO: is this actually useful?
            /// Returns the nearest integer value.
            pub fn round(self) -> Self {
                Self(self.0.wrapping_add(Self::ROUND) & Self::INT_MASK)
            }

            /// Returns the absolute value of the number.
            pub fn abs(self) -> Self {
                Self(self.0.abs())
            }

            /// Returns the largest integer less than or equal to the number.
            pub fn floor(self) -> Self {
                Self(self.0 & Self::INT_MASK)
            }

            /// Returns the fractional part of the number.
            pub fn fract(self) -> Self {
                Self(self.0 - self.floor().0)
            }

            /// Wrapping addition.
            pub fn wrapping_add(self, other: Self) -> Self {
                Self(self.0.wrapping_add(other.0))
            }

            /// Saturating addition.
            pub fn saturating_add(self, other: Self) -> Self {
                Self(self.0.saturating_add(other.0))
            }

            /// Wrapping substitution.
            pub fn wrapping_sub(self, other: Self) -> Self {
                Self(self.0.wrapping_sub(other.0))
            }

            /// Saturating substitution.
            pub fn saturating_sub(self, other: Self) -> Self {
                Self(self.0.saturating_sub(other.0))
            }

            /// The representation of this number as a big-endian byte array.
            pub fn to_be_bytes(self) -> [u8; $bits / 8] {
                self.0.to_be_bytes()
            }
        }

        impl Add for $name {
            type Output = Self;
            #[inline(always)]
            fn add(self, other: Self) -> Self {
                // same overflow semantics as std: panic in debug, wrap in release
                Self(self.0 + other.0)
            }
        }

        impl AddAssign for $name {
            fn add_assign(&mut self, other: Self) {
                *self = *self + other;
            }
        }

        impl Sub for $name {
            type Output = Self;
            #[inline(always)]
            fn sub(self, other: Self) -> Self {
                Self(self.0 - other.0)
            }
        }

        impl SubAssign for $name {
            fn sub_assign(&mut self, other: Self) {
                *self = *self - other;
            }
        }
    };
}

/// impl float conversion methods.
///
/// We convert to different float types in order to ensure we can roundtrip
/// without floating point error.
macro_rules! float_conv {
    ($name:ident, $to:ident, $from:ident, $ty:ty) => {
        impl $name {
            #[doc = concat!("Creates a fixed point value from a", stringify!($ty), ".")]
            ///
            /// This operation is lossy; the float will be rounded to the nearest
            /// representable value.
            pub fn $from(x: $ty) -> Self {
                #[cfg(any(feature = "std", test))]
                return Self((x * Self::ONE.0 as $ty).round() as _);
                //NOTE: this behaviour is not exactly equivalent, but should be okay?
                //what matters is that we are rounding *away from zero*.
                #[cfg(all(not(feature = "std"), not(test)))]
                Self(
                    (x * Self::ONE as $ty + (0.5 * (-1.0 * x.is_sign_negative() as u8 as $ty)))
                        as _,
                )
            }

            #[doc = concat!("Returns the value as an ", stringify!($ty), ".")]
            ///
            /// This operation is lossless: all representable values can be
            /// round-tripped.
            pub fn $to(self) -> $ty {
                let int = ((self.0 & Self::INT_MASK) >> Self::FRACT_BITS) as $ty;
                let fract = (self.0 & !Self::INT_MASK) as $ty / Self::ONE.0 as $ty;
                int + fract
            }
        }

        //hack: we can losslessly go to float, so use those fmt impls
        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.$to().fmt(f)
            }
        }

        impl std::fmt::Debug for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.$to().fmt(f)
            }
        }
    };
}

fixed_impl!(F2Dot14, 16, 14, i16);
fixed_impl!(Fixed, 32, 16, i32);
float_conv!(F2Dot14, to_f32, from_f32, f32);
float_conv!(Fixed, to_f64, from_f64, f64);
crate::newtype_scalar!(F2Dot14, [u8; 2]);
crate::newtype_scalar!(Fixed, [u8; 4]);

impl F2Dot14 {
    /// Converts a 2.14 to 16.16 fixed point value.
    pub fn to_fixed(&self) -> Fixed {
        Fixed(self.0 as i32 * 4)
    }
}

impl Mul for Fixed {
    type Output = Self;
    #[inline(always)]
    fn mul(self, other: Self) -> Self::Output {
        let ab = self.0 as i64 * other.0 as i64;
        Self(((ab + 0x8000 - i64::from(ab < 0)) >> 16) as i32)
    }
}

impl MulAssign for Fixed {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs;
    }
}

impl Div for Fixed {
    type Output = Self;
    #[inline(always)]
    fn div(self, other: Self) -> Self::Output {
        let mut sign = 1;
        let mut a = self.0;
        let mut b = other.0;
        if a < 0 {
            a = -a;
            sign = -1;
        }
        if b < 0 {
            b = -b;
            sign = -sign;
        }
        let q = if b == 0 {
            0x7FFFFFFF
        } else {
            ((((a as u64) << 16) + ((b as u64) >> 1)) / (b as u64)) as u32
        };
        Self(if sign < 0 { -(q as i32) } else { q as i32 })
    }
}

impl DivAssign for Fixed {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs;
    }
}

impl Neg for Fixed {
    type Output = Self;
    #[inline(always)]
    fn neg(self) -> Self {
        Self(-self.0)
    }
}

#[cfg(test)]
mod tests {
    #![allow(overflowing_literals)] // we want to specify byte values directly
    use super::*;

    #[test]
    fn f2dot14_floats() {
        // Examples from https://docs.microsoft.com/en-us/typography/opentype/spec/otff#data-types
        assert_eq!(F2Dot14(0x7fff), F2Dot14::from_f32(1.999939));
        assert_eq!(F2Dot14(0x7000), F2Dot14::from_f32(1.75));
        assert_eq!(F2Dot14(0x0001), F2Dot14::from_f32(0.0000610356));
        assert_eq!(F2Dot14(0x0000), F2Dot14::from_f32(0.0));
        assert_eq!(F2Dot14(0xffff), F2Dot14::from_f32(-0.000061));
        assert_eq!(F2Dot14(0x8000), F2Dot14::from_f32(-2.0));
    }

    #[test]
    fn roundtrip_f2dot14() {
        for i in i16::MIN..=i16::MAX {
            let val = F2Dot14(i);
            assert_eq!(val, F2Dot14::from_f32(val.to_f32()));
        }
    }

    #[test]
    fn round_f2dot14() {
        assert_eq!(F2Dot14(0x7000).round(), F2Dot14::from_f32(-2.0));
        assert_eq!(F2Dot14(0x1F00).round(), F2Dot14::from_f32(0.0));
        assert_eq!(F2Dot14(0x2000).round(), F2Dot14::from_f32(1.0));
    }

    #[test]
    fn round_fixed() {
        //TODO: make good test cases
        assert_eq!(Fixed(0x0001_7FFE).round(), Fixed(0x0001_0000));
        assert_eq!(Fixed(0x0001_7FFF).round(), Fixed(0x0001_0000));
        assert_eq!(Fixed(0x0001_8000).round(), Fixed(0x0002_0000));
    }

    // disabled because it's slow; these were just for my edification anyway
    //#[test]
    //fn roundtrip_fixed() {
    //for i in i32::MIN..=i32::MAX {
    //let val = Fixed(i);
    //assert_eq!(val, Fixed::from_f64(val.to_f64()));
    //}
    //}

    #[test]
    fn fixed_floats() {
        assert_eq!(Fixed(0x7fff_0000), Fixed::from_f64(32767.));
        assert_eq!(Fixed(0x7000_0001), Fixed::from_f64(28672.00001525879));
        assert_eq!(Fixed(0x0001_0000), Fixed::from_f64(1.0));
        assert_eq!(Fixed(0x0000_0000), Fixed::from_f64(0.0));
        assert_eq!(
            Fixed(i32::from_be_bytes([0xff; 4])),
            Fixed::from_f64(-0.000015259)
        );
        assert_eq!(Fixed(0x7fff_ffff), Fixed::from_f64(32768.0));
    }
}
<commit_msg>fix gated test<commit_after>//! fixed-point numerical types

use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};

// shared between Fixed and F2Dot14
macro_rules! fixed_impl {
    ($name:ident, $bits:literal, $fract_bits:literal, $ty:ty) => {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
        #[doc = concat!(stringify!($bits), "-bit signed fixed point number with ", stringify!($fract_bits), " bits of fraction." )]
        pub struct $name($ty);
        impl $name {
            /// Minimum value.
            pub const MIN: Self = Self(<$ty>::MIN);

            /// Maximum value.
            pub const MAX: Self = Self(<$ty>::MAX);

            /// This type's smallest representable value
            pub const EPSILON: Self = Self(1);

            /// Representation of 0.0.
            pub const ZERO: Self = Self(0);

            /// Representation of 1.0.
            pub const ONE: Self = Self(1 << $fract_bits);

            const INT_MASK: $ty = !0 << $fract_bits;
            const ROUND: $ty = 1 << ($fract_bits - 1);
            const FRACT_BITS: usize = $fract_bits;

            //TODO: is this actually useful?
            /// Returns the nearest integer value.
            pub fn round(self) -> Self {
                Self(self.0.wrapping_add(Self::ROUND) & Self::INT_MASK)
            }

            /// Returns the absolute value of the number.
            pub fn abs(self) -> Self {
                Self(self.0.abs())
            }

            /// Returns the largest integer less than or equal to the number.
            pub fn floor(self) -> Self {
                Self(self.0 & Self::INT_MASK)
            }

            /// Returns the fractional part of the number.
            pub fn fract(self) -> Self {
                Self(self.0 - self.floor().0)
            }

            /// Wrapping addition.
            pub fn wrapping_add(self, other: Self) -> Self {
                Self(self.0.wrapping_add(other.0))
            }

            /// Saturating addition.
            pub fn saturating_add(self, other: Self) -> Self {
                Self(self.0.saturating_add(other.0))
            }

            /// Wrapping substitution.
            pub fn wrapping_sub(self, other: Self) -> Self {
                Self(self.0.wrapping_sub(other.0))
            }

            /// Saturating substitution.
            pub fn saturating_sub(self, other: Self) -> Self {
                Self(self.0.saturating_sub(other.0))
            }

            /// The representation of this number as a big-endian byte array.
            pub fn to_be_bytes(self) -> [u8; $bits / 8] {
                self.0.to_be_bytes()
            }
        }

        impl Add for $name {
            type Output = Self;
            #[inline(always)]
            fn add(self, other: Self) -> Self {
                // same overflow semantics as std: panic in debug, wrap in release
                Self(self.0 + other.0)
            }
        }

        impl AddAssign for $name {
            fn add_assign(&mut self, other: Self) {
                *self = *self + other;
            }
        }

        impl Sub for $name {
            type Output = Self;
            #[inline(always)]
            fn sub(self, other: Self) -> Self {
                Self(self.0 - other.0)
            }
        }

        impl SubAssign for $name {
            fn sub_assign(&mut self, other: Self) {
                *self = *self - other;
            }
        }
    };
}

/// impl float conversion methods.
///
/// We convert to different float types in order to ensure we can roundtrip
/// without floating point error.
macro_rules! float_conv {
    ($name:ident, $to:ident, $from:ident, $ty:ty) => {
        impl $name {
            #[doc = concat!("Creates a fixed point value from a", stringify!($ty), ".")]
            ///
            /// This operation is lossy; the float will be rounded to the nearest
            /// representable value.
            pub fn $from(x: $ty) -> Self {
                #[cfg(any(feature = "std", test))]
                return Self((x * Self::ONE.0 as $ty).round() as _);
                //NOTE: this behaviour is not exactly equivalent, but should be okay?
                //what matters is that we are rounding *away from zero*.
                #[cfg(all(not(feature = "std"), not(test)))]
                Self(
                    (x * Self::ONE.0 as $ty + (0.5 * (-1.0 * x.is_sign_negative() as u8 as $ty)))
                        as _,
                )
            }

            #[doc = concat!("Returns the value as an ", stringify!($ty), ".")]
            ///
            /// This operation is lossless: all representable values can be
            /// round-tripped.
            pub fn $to(self) -> $ty {
                let int = ((self.0 & Self::INT_MASK) >> Self::FRACT_BITS) as $ty;
                let fract = (self.0 & !Self::INT_MASK) as $ty / Self::ONE.0 as $ty;
                int + fract
            }
        }

        //hack: we can losslessly go to float, so use those fmt impls
        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.$to().fmt(f)
            }
        }

        impl std::fmt::Debug for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.$to().fmt(f)
            }
        }
    };
}

fixed_impl!(F2Dot14, 16, 14, i16);
fixed_impl!(Fixed, 32, 16, i32);
float_conv!(F2Dot14, to_f32, from_f32, f32);
float_conv!(Fixed, to_f64, from_f64, f64);
crate::newtype_scalar!(F2Dot14, [u8; 2]);
crate::newtype_scalar!(Fixed, [u8; 4]);

impl F2Dot14 {
    /// Converts a 2.14 to 16.16 fixed point value.
    pub fn to_fixed(&self) -> Fixed {
        Fixed(self.0 as i32 * 4)
    }
}

impl Mul for Fixed {
    type Output = Self;
    #[inline(always)]
    fn mul(self, other: Self) -> Self::Output {
        let ab = self.0 as i64 * other.0 as i64;
        Self(((ab + 0x8000 - i64::from(ab < 0)) >> 16) as i32)
    }
}

impl MulAssign for Fixed {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs;
    }
}

impl Div for Fixed {
    type Output = Self;
    #[inline(always)]
    fn div(self, other: Self) -> Self::Output {
        let mut sign = 1;
        let mut a = self.0;
        let mut b = other.0;
        if a < 0 {
            a = -a;
            sign = -1;
        }
        if b < 0 {
            b = -b;
            sign = -sign;
        }
        let q = if b == 0 {
            0x7FFFFFFF
        } else {
            ((((a as u64) << 16) + ((b as u64) >> 1)) / (b as u64)) as u32
        };
        Self(if sign < 0 { -(q as i32) } else { q as i32 })
    }
}

impl DivAssign for Fixed {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs;
    }
}

impl Neg for Fixed {
    type Output = Self;
    #[inline(always)]
    fn neg(self) -> Self {
        Self(-self.0)
    }
}

#[cfg(test)]
mod tests {
    #![allow(overflowing_literals)] // we want to specify byte values directly
    use super::*;

    #[test]
    fn f2dot14_floats() {
        // Examples from https://docs.microsoft.com/en-us/typography/opentype/spec/otff#data-types
        assert_eq!(F2Dot14(0x7fff), F2Dot14::from_f32(1.999939));
        assert_eq!(F2Dot14(0x7000), F2Dot14::from_f32(1.75));
        assert_eq!(F2Dot14(0x0001), F2Dot14::from_f32(0.0000610356));
        assert_eq!(F2Dot14(0x0000), F2Dot14::from_f32(0.0));
        assert_eq!(F2Dot14(0xffff), F2Dot14::from_f32(-0.000061));
        assert_eq!(F2Dot14(0x8000), F2Dot14::from_f32(-2.0));
    }

    #[test]
    fn roundtrip_f2dot14() {
        for i in i16::MIN..=i16::MAX {
            let val = F2Dot14(i);
            assert_eq!(val, F2Dot14::from_f32(val.to_f32()));
        }
    }

    #[test]
    fn round_f2dot14() {
        assert_eq!(F2Dot14(0x7000).round(), F2Dot14::from_f32(-2.0));
        assert_eq!(F2Dot14(0x1F00).round(), F2Dot14::from_f32(0.0));
        assert_eq!(F2Dot14(0x2000).round(), F2Dot14::from_f32(1.0));
    }

    #[test]
    fn round_fixed() {
        //TODO: make good test cases
        assert_eq!(Fixed(0x0001_7FFE).round(), Fixed(0x0001_0000));
        assert_eq!(Fixed(0x0001_7FFF).round(), Fixed(0x0001_0000));
        assert_eq!(Fixed(0x0001_8000).round(), Fixed(0x0002_0000));
    }

    // disabled because it's slow; these were just for my edification anyway
    //#[test]
    //fn roundtrip_fixed() {
    //for i in i32::MIN..=i32::MAX {
    //let val = Fixed(i);
    //assert_eq!(val, Fixed::from_f64(val.to_f64()));
    //}
    //}

    #[test]
    fn fixed_floats() {
        assert_eq!(Fixed(0x7fff_0000), Fixed::from_f64(32767.));
        assert_eq!(Fixed(0x7000_0001), Fixed::from_f64(28672.00001525879));
        assert_eq!(Fixed(0x0001_0000), Fixed::from_f64(1.0));
        assert_eq!(Fixed(0x0000_0000), Fixed::from_f64(0.0));
        assert_eq!(
            Fixed(i32::from_be_bytes([0xff; 4])),
            Fixed::from_f64(-0.000015259)
        );
        assert_eq!(Fixed(0x7fff_ffff), Fixed::from_f64(32768.0));
    }
}
<|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 test;

        fn gen_select_test(b: &mut test::Bencher, to_send: usize, n: usize) -> () {
            let mut active = Vec::with_capacity(to_send);
            let mut dormant = Vec::with_capacity(n - to_send);
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..to_send {
                let (tx, rx) = ipc::channel().unwrap();
                rx_set.add(rx).unwrap();
                active.push(tx);
            }
            for _ in to_send..n {
                let (tx, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
                dormant.push(tx);
            }
            b.iter(|| {
                for tx in active.iter() {
                    tx.send(()).unwrap();
                }
                let mut received = 0;
                while received < to_send {
                    for result in rx_set.select().unwrap().into_iter() {
                        let (_, _) = result.unwrap();
                        received += 1;
                    }
                }
            });
        }

        fn create_empty_set() -> Result<IpcReceiverSet, ()> {
            Ok(IpcReceiverSet::new().unwrap())
        }

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

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

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

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

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

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

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

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

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

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

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

        #[bench]
        fn create_and_destroy_empty_set(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_empty_set().unwrap();
            });
        }

        #[bench]
        fn create_and_destroy_set_of_10(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                add_n_rxs(&mut rx_set, 10);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_5(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                add_n_rxs(&mut rx_set, 5);
            });
        }

        #[bench]
        // Benchmark adding and removing closed receivers from the set
        fn add_and_remove_closed_receivers(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                {
                    {
                        let (_, rx) = ipc::channel::<()>().unwrap();
                        rx_set.add(rx).unwrap();
                    }
                    // On select Receivers with a "ClosedChannel" event
                    // will be closed
                    rx_set.select().unwrap();
                    let (_, rx) = ipc::channel::<()>().unwrap();
                    rx_set.add(rx).unwrap();
                }
            });
        }
    }
}
<commit_msg>Benchmarks: cleanup: Drop trivial helper function<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 {
    mod receiver_set {
        use ipc_channel::ipc::{self, IpcReceiverSet};
        use test;

        fn gen_select_test(b: &mut test::Bencher, to_send: usize, n: usize) -> () {
            let mut active = Vec::with_capacity(to_send);
            let mut dormant = Vec::with_capacity(n - to_send);
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..to_send {
                let (tx, rx) = ipc::channel().unwrap();
                rx_set.add(rx).unwrap();
                active.push(tx);
            }
            for _ in to_send..n {
                let (tx, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
                dormant.push(tx);
            }
            b.iter(|| {
                for tx in active.iter() {
                    tx.send(()).unwrap();
                }
                let mut received = 0;
                while received < to_send {
                    for result in rx_set.select().unwrap().into_iter() {
                        let (_, _) = result.unwrap();
                        received += 1;
                    }
                }
            });
        }

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

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

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

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

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

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

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

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

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

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

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

        #[bench]
        fn create_and_destroy_empty_set(b: &mut test::Bencher) -> () {
            b.iter(|| {
                IpcReceiverSet::new().unwrap();
            });
        }

        #[bench]
        fn create_and_destroy_set_of_10(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                add_n_rxs(&mut rx_set, 10);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_5(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                add_n_rxs(&mut rx_set, 5);
            });
        }

        #[bench]
        // Benchmark adding and removing closed receivers from the set
        fn add_and_remove_closed_receivers(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                {
                    {
                        let (_, rx) = ipc::channel::<()>().unwrap();
                        rx_set.add(rx).unwrap();
                    }
                    // On select Receivers with a "ClosedChannel" event
                    // will be closed
                    rx_set.select().unwrap();
                    let (_, rx) = ipc::channel::<()>().unwrap();
                    rx_set.add(rx).unwrap();
                }
            });
        }
    }
}
<|endoftext|>