<commit_before>#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    use anyhow::Context as _;
    use futures::StreamExt as _;
    use rusoto_sqs::Sqs as _;

    let config = encoder::load_config()?;
    let sqs_client = rusoto_sqs::SqsClient::new(Default::default());
    let stop_path = std::path::Path::new("/tmp/stop-encode.txt");
    let base_dir = std::path::Path::new(&config.encoder.base_dir);

    loop {
        if stop_path.exists() {
            break;
        }
        let resp = sqs_client
            .receive_message(rusoto_sqs::ReceiveMessageRequest {
                queue_url: config.sqs.queue_url.clone(),
                wait_time_seconds: Some(5),
                visibility_timeout: Some(60),
                ..Default::default()
            })
            .await
            .context("failed to call sqs:ReceiveMessage")?;
        if let Some(messages) = resp.messages {
            let message = messages.into_iter().next().unwrap();
            let fname = message.body.expect("SQS message body is missing");
            let message_id = message.message_id.expect("SQS message_id is missing");
            let receipt_handle = message
                .receipt_handle
                .expect("SQS receipt_handle is missing");
            println!("[message_id={}] {}", message_id, fname);

            let ts_path = base_dir.join(format!("{}.ts", fname));
            if ts_path.exists() {
                let interval = tokio::time::interval(tokio::time::Duration::from_secs(60))
                    .map(|_| futures::future::Either::Left(()));
                let encode = futures::stream::once(encoder::encode(&config, ts_path))
                    .map(|result| futures::future::Either::Right(result));
                tokio::pin!(encode);
                let mut stream = futures::stream::select(interval, encode);

                while let Some(item) = stream.next().await {
                    match item {
                        futures::future::Either::Left(_) => {
                            let result = sqs_client
                                .change_message_visibility(
                                    rusoto_sqs::ChangeMessageVisibilityRequest {
                                        queue_url: config.sqs.queue_url.clone(),
                                        receipt_handle: receipt_handle.clone(),
                                        visibility_timeout: 70,
                                    },
                                )
                                .await;
                            if let Err(e) = result {
                                eprintln!("Failed to change message visibility: {:?}", e);
                            }
                        }
                        futures::future::Either::Right(result) => {
                            match result {
                                Ok(_) => {
                                    sqs_client
                                        .delete_message(rusoto_sqs::DeleteMessageRequest {
                                            queue_url: config.sqs.queue_url.clone(),
                                            receipt_handle,
                                        })
                                        .await
                                        .context("failed to call sqs:DeleteMessage")?;
                                }
                                Err(e) => {
                                    eprintln!("encode failed: {:?}", e);
                                }
                            }
                            break;
                        }
                    }
                }
            } else {
                let mp4_path = base_dir.join(format!("{}.mp4", fname));
                if mp4_path.exists() {
                    println!(
                        "{} is already encoded to {}",
                        ts_path.display(),
                        mp4_path.display()
                    );
                    sqs_client
                        .delete_message(rusoto_sqs::DeleteMessageRequest {
                            queue_url: config.sqs.queue_url.clone(),
                            receipt_handle,
                        })
                        .await
                        .context("failed to call sqs:DeleteMessage")?;
                } else {
                    println!("{} does not exist", ts_path.display());
                }
            }
        } else {
            break;
        }
    }

    Ok(())
}
<commit_msg>Retry DeleteMessage<commit_after>#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    use anyhow::Context as _;
    use futures::StreamExt as _;
    use rusoto_sqs::Sqs as _;

    let config = encoder::load_config()?;
    let sqs_client = rusoto_sqs::SqsClient::new(Default::default());
    let stop_path = std::path::Path::new("/tmp/stop-encode.txt");
    let base_dir = std::path::Path::new(&config.encoder.base_dir);

    loop {
        if stop_path.exists() {
            break;
        }
        let resp = sqs_client
            .receive_message(rusoto_sqs::ReceiveMessageRequest {
                queue_url: config.sqs.queue_url.clone(),
                wait_time_seconds: Some(5),
                visibility_timeout: Some(60),
                ..Default::default()
            })
            .await
            .context("failed to call sqs:ReceiveMessage")?;
        if let Some(messages) = resp.messages {
            let message = messages.into_iter().next().unwrap();
            let fname = message.body.expect("SQS message body is missing");
            let message_id = message.message_id.expect("SQS message_id is missing");
            let receipt_handle = message
                .receipt_handle
                .expect("SQS receipt_handle is missing");
            println!("[message_id={}] {}", message_id, fname);

            let ts_path = base_dir.join(format!("{}.ts", fname));
            if ts_path.exists() {
                let interval = tokio::time::interval(tokio::time::Duration::from_secs(60))
                    .map(|_| futures::future::Either::Left(()));
                let encode = futures::stream::once(encoder::encode(&config, ts_path))
                    .map(|result| futures::future::Either::Right(result));
                tokio::pin!(encode);
                let mut stream = futures::stream::select(interval, encode);

                while let Some(item) = stream.next().await {
                    match item {
                        futures::future::Either::Left(_) => {
                            let result = sqs_client
                                .change_message_visibility(
                                    rusoto_sqs::ChangeMessageVisibilityRequest {
                                        queue_url: config.sqs.queue_url.clone(),
                                        receipt_handle: receipt_handle.clone(),
                                        visibility_timeout: 70,
                                    },
                                )
                                .await;
                            if let Err(e) = result {
                                eprintln!("Failed to change message visibility: {:?}", e);
                            }
                        }
                        futures::future::Either::Right(result) => {
                            match result {
                                Ok(_) => {
                                    delete_message_with_retry(
                                        &sqs_client,
                                        &config.sqs.queue_url,
                                        &receipt_handle,
                                    )
                                    .await?;
                                }
                                Err(e) => {
                                    eprintln!("encode failed: {:?}", e);
                                }
                            }
                            break;
                        }
                    }
                }
            } else {
                let mp4_path = base_dir.join(format!("{}.mp4", fname));
                if mp4_path.exists() {
                    println!(
                        "{} is already encoded to {}",
                        ts_path.display(),
                        mp4_path.display()
                    );
                    delete_message_with_retry(&sqs_client, &config.sqs.queue_url, &receipt_handle)
                        .await?;
                } else {
                    println!("{} does not exist", ts_path.display());
                }
            }
        } else {
            break;
        }
    }

    Ok(())
}

async fn delete_message_with_retry<Sqs>(
    sqs_client: &Sqs,
    queue_url: &str,
    receipt_handle: &str,
) -> Result<(), anyhow::Error>
where
    Sqs: rusoto_sqs::Sqs,
{
    for i in 0..3 {
        match sqs_client
            .delete_message(rusoto_sqs::DeleteMessageRequest {
                queue_url: queue_url.to_owned(),
                receipt_handle: receipt_handle.to_owned(),
            })
            .await
        {
            Ok(_) => {
                return Ok(());
            }
            Err(e) => {
                eprintln!("[{}] failed to call sqs:DeleteMessage: {}", i, e);
            }
        }
    }
    Err(anyhow::anyhow!("sqs:DeleteMessage failed"))
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::c_str::CString;
use std::io::process::{Command, ProcessOutput, InheritFd};
use std::collections::HashMap;

use util::{ProcessError, process_error};

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: CString,
    args: Vec<String>,
    path: Vec<String>,
    env: HashMap<String, String>,
    cwd: Path
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", self.program.as_str().unwrap_or("<not-utf8>")));

        if self.args.len() > 0 {
            try!(write!(f, " {}", self.args.connect(" ")));
        }

        write!(f, "`")
    }
}

// TODO: Upstream a Windows/Posix branch to Rust proper
#[cfg(unix)]
static PATH_SEP : &'static str = ":";
#[cfg(windows)]
static PATH_SEP : &'static str = ";";

impl ProcessBuilder {
    pub fn arg<T: Str>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.as_slice().to_string());
        self
    }

    pub fn args<T: Str>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args = arguments.iter().map(|a| a.as_slice().to_string()).collect();
        self
    }

    pub fn get_args<'a>(&'a self) -> &'a [String] {
        self.args.as_slice()
    }

    pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
        // For now, just convert to a string, but we should do something better
        self.path.unshift(path.display().to_string());
        self
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder {
        match val {
            Some(v) => {
                self.env.insert(key.to_string(), v.to_string());
            },
            None => {
                self.env.remove(&key.to_string());
            }
        }

        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command
            .env_set_all(self.build_env().as_slice())
            .stdout(InheritFd(1))
            .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let mut command = self.build_command();
        command.env_set_all(self.build_env().as_slice());

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_bytes_no_nul());
        command.args(self.args.as_slice()).cwd(&self.cwd);
        command
    }

    fn debug_string(&self) -> String {
        let program = self.program.as_str().unwrap_or("<not-utf8>");
        if self.args.len() == 0 {
            program.to_string()
        } else {
            format!("{} {}", program, self.args.connect(" "))
        }
    }

    fn build_env(&self) -> Vec<(String, String)> {
        let mut ret = Vec::new();

        for (key, val) in self.env.iter() {
            // Skip path
            if key.as_slice() != "PATH" {
                ret.push((key.clone(), val.clone()));
            }
        }

        match self.build_path() {
            Some(path) => ret.push(("PATH".to_string(), path)),
            _ => ()
        }

        ret.as_slice().to_owned()
    }

    fn build_path(&self) -> Option<String> {
        let path = self.path.connect(PATH_SEP);

        match self.env.find_equiv(&("PATH")) {
            Some(existing) => {
                if self.path.is_empty() {
                    Some(existing.clone())
                } else {
                    Some(format!("{}{}{}", existing, PATH_SEP, path))
                }
            },
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(path)
                }
            }
        }
    }
}

pub fn process<T: ToCStr>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_c_str(),
        args: vec!(),
        path: vec!(),
        cwd: os::getcwd(),
        env: os::env().move_iter().collect()
    }
}
<commit_msg>fix deprecated usage<commit_after>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::c_str::CString;
use std::io::process::{Command, ProcessOutput, InheritFd};
use std::collections::HashMap;

use util::{ProcessError, process_error};

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: CString,
    args: Vec<String>,
    path: Vec<String>,
    env: HashMap<String, String>,
    cwd: Path
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", self.program.as_str().unwrap_or("<not-utf8>")));

        if self.args.len() > 0 {
            try!(write!(f, " {}", self.args.connect(" ")));
        }

        write!(f, "`")
    }
}

// TODO: Upstream a Windows/Posix branch to Rust proper
#[cfg(unix)]
static PATH_SEP : &'static str = ":";
#[cfg(windows)]
static PATH_SEP : &'static str = ";";

impl ProcessBuilder {
    pub fn arg<T: Str>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.as_slice().to_string());
        self
    }

    pub fn args<T: Str>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args = arguments.iter().map(|a| a.as_slice().to_string()).collect();
        self
    }

    pub fn get_args<'a>(&'a self) -> &'a [String] {
        self.args.as_slice()
    }

    pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
        // For now, just convert to a string, but we should do something better
        self.path.unshift(path.display().to_string());
        self
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder {
        match val {
            Some(v) => {
                self.env.insert(key.to_string(), v.to_string());
            },
            None => {
                self.env.remove(&key.to_string());
            }
        }

        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command
            .env_set_all(self.build_env().as_slice())
            .stdout(InheritFd(1))
            .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let mut command = self.build_command();
        command.env_set_all(self.build_env().as_slice());

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_bytes_no_nul());
        command.args(self.args.as_slice()).cwd(&self.cwd);
        command
    }

    fn debug_string(&self) -> String {
        let program = self.program.as_str().unwrap_or("<not-utf8>");
        if self.args.len() == 0 {
            program.to_string()
        } else {
            format!("{} {}", program, self.args.connect(" "))
        }
    }

    fn build_env(&self) -> Vec<(String, String)> {
        let mut ret = Vec::new();

        for (key, val) in self.env.iter() {
            // Skip path
            if key.as_slice() != "PATH" {
                ret.push((key.clone(), val.clone()));
            }
        }

        match self.build_path() {
            Some(path) => ret.push(("PATH".to_string(), path)),
            _ => ()
        }

        ret.to_vec()
    }

    fn build_path(&self) -> Option<String> {
        let path = self.path.connect(PATH_SEP);

        match self.env.find_equiv(&("PATH")) {
            Some(existing) => {
                if self.path.is_empty() {
                    Some(existing.clone())
                } else {
                    Some(format!("{}{}{}", existing, PATH_SEP, path))
                }
            },
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(path)
                }
            }
        }
    }
}

pub fn process<T: ToCStr>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_c_str(),
        args: vec!(),
        path: vec!(),
        cwd: os::getcwd(),
        env: os::env().move_iter().collect()
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use assign::assign;
use isahc::{HttpClient, ReadResponseExt};
use semver::Version;
use serde::{de::IgnoredAny, Deserialize};
use toml_edit::{value, Document};
use xshell::{cmd, pushd, read_file, write_file};

use crate::{util::ask_yes_no, Metadata, Result};

const CRATESIO_API: &str = "https://crates.io/api/v1/crates";

/// A cargo package.
#[derive(Clone, Debug, Deserialize)]
pub struct Package {
    /// The package name
    pub name: String,

    /// The package version.
    pub version: Version,

    /// The package's manifest path.
    pub manifest_path: PathBuf,

    /// A map of the package dependencies.
    #[serde(default)]
    pub dependencies: Vec<Dependency>,
}

impl Package {
    /// Update the version of this crate.
    pub fn update_version(&mut self, version: &Version) -> Result<()> {
        println!("Updating {} to version {}…", self.name, version);

        let mut document = read_file(&self.manifest_path)?.parse::<Document>()?;

        document["package"]["version"] = value(version.to_string());

        write_file(&self.manifest_path, document.to_string())?;

        self.version = version.clone();

        Ok(())
    }

    /// Update the version of this crate in dependant crates' manifests, with the given version
    /// prefix.
    pub(crate) fn update_dependants(&self, metadata: &Metadata) -> Result<()> {
        for package in metadata.packages.iter().filter(|p| {
            p.manifest_path.starts_with(&metadata.workspace_root)
                && p.dependencies.iter().any(|d| d.name == self.name)
        }) {
            println!("Updating dependency in {} crate…", package.name);

            let mut document = read_file(&package.manifest_path)?.parse::<Document>()?;

            for dependency in package.dependencies.iter().filter(|d| d.name == self.name) {
                let version = if self.version.is_prerelease() || self.name.ends_with("-macros") {
                    format!("={}", self.version)
                } else {
                    self.version.to_string()
                };

                let kind = match dependency.kind {
                    Some(DependencyKind::Dev) => "dev-dependencies",
                    Some(DependencyKind::Build) => "build-dependencies",
                    None => "dependencies",
                };

                document[kind][&self.name]["version"] = value(version.as_str());
            }

            write_file(&package.manifest_path, document.to_string())?;
        }

        Ok(())
    }

    /// Get the changes for the version. If `update` is `true`, update the changelog for the release
    /// of the given version.
    pub fn changes(&self, update: bool) -> Result<String> {
        let mut changelog_path = self.manifest_path.clone();
        changelog_path.set_file_name("CHANGELOG.md");

        let changelog = read_file(&changelog_path)?;
        let version = assign!(self.version.clone(), { pre: vec![], build: vec![] });

        if !changelog.starts_with(&format!("# {}\n", version))
            && !changelog.starts_with(&format!("# {} (unreleased)\n", version))
            && !changelog.starts_with("# [unreleased]\n")
        {
            return Err("Could not find version title in changelog".into());
        };

        let changes_start = match changelog.find('\n') {
            Some(p) => p + 1,
            None => {
                return Err("Could not find end of version title in changelog".into());
            }
        };

        let changes_end = match changelog[changes_start..].find("\n# ") {
            Some(p) => changes_start + p,
            None => changelog.len(),
        };

        let changes = match changelog[changes_start..changes_end].trim() {
            s if s.is_empty() => "No changes for this version",
            s => s,
        };

        if update {
            let changelog = format!(
                "# [unreleased]\n\n# {}\n\n{}\n{}",
                self.version,
                changes,
                &changelog[changes_end..]
            );

            write_file(&changelog_path, changelog)?;
        }

        Ok(changes.to_owned())
    }

    /// Check if the current version of the crate is published on crates.io.
    pub fn is_published(&self, client: &HttpClient) -> Result<bool> {
        let response: CratesIoCrate =
            client.get(format!("{}/{}/{}", CRATESIO_API, self.name, self.version))?.json()?;

        Ok(response.version.is_some())
    }

    /// Publish this package on crates.io.
    pub fn publish(&self, client: &HttpClient) -> Result<bool> {
        println!("Publishing {} {} on crates.io…", self.name, self.version);
        let _dir = pushd(&self.manifest_path.parent().unwrap())?;

        if self.is_published(client)? {
            if ask_yes_no("This version is already published. Skip this step and continue?")? {
                Ok(false)
            } else {
                Err("Release interrupted by user.".into())
            }
        } else {
            cmd!("cargo publish").run()?;
            Ok(true)
        }
    }
}

/// A cargo package dependency.
#[derive(Clone, Debug, Deserialize)]
pub struct Dependency {
    /// The package name.
    pub name: String,

    /// The kind of the dependency.
    pub kind: Option<DependencyKind>,
}

/// The kind of a cargo package dependency.
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum DependencyKind {
    /// A dev dependency.
    Dev,

    /// A build dependency.
    Build,
}

/// A crate from the `GET /crates/{crate}` endpoint of crates.io.
#[derive(Deserialize)]
struct CratesIoCrate {
    version: Option<IgnoredAny>,
}
<commit_msg>xtask: Fix dependency version writing on non-child macro crates in release cmd<commit_after>use std::path::PathBuf;

use assign::assign;
use isahc::{HttpClient, ReadResponseExt};
use semver::Version;
use serde::{de::IgnoredAny, Deserialize};
use toml_edit::{value, Document};
use xshell::{cmd, pushd, read_file, write_file};

use crate::{util::ask_yes_no, Metadata, Result};

const CRATESIO_API: &str = "https://crates.io/api/v1/crates";

/// A cargo package.
#[derive(Clone, Debug, Deserialize)]
pub struct Package {
    /// The package name
    pub name: String,

    /// The package version.
    pub version: Version,

    /// The package's manifest path.
    pub manifest_path: PathBuf,

    /// A map of the package dependencies.
    #[serde(default)]
    pub dependencies: Vec<Dependency>,
}

impl Package {
    /// Update the version of this crate.
    pub fn update_version(&mut self, version: &Version) -> Result<()> {
        println!("Updating {} to version {}…", self.name, version);

        let mut document = read_file(&self.manifest_path)?.parse::<Document>()?;

        document["package"]["version"] = value(version.to_string());

        write_file(&self.manifest_path, document.to_string())?;

        self.version = version.clone();

        Ok(())
    }

    /// Update the version of this crate in dependant crates' manifests, with the given version
    /// prefix.
    pub(crate) fn update_dependants(&self, metadata: &Metadata) -> Result<()> {
        for package in metadata.packages.iter().filter(|p| {
            p.manifest_path.starts_with(&metadata.workspace_root)
                && p.dependencies.iter().any(|d| d.name == self.name)
        }) {
            println!("Updating dependency in {} crate…", package.name);

            let mut document = read_file(&package.manifest_path)?.parse::<Document>()?;

            let version = if self.version.is_prerelease()
                || self.name.strip_suffix("-macros") == Some(&package.name)
            {
                format!("={}", self.version)
            } else {
                self.version.to_string()
            };

            for dependency in package.dependencies.iter().filter(|d| d.name == self.name) {
                let kind = match dependency.kind {
                    Some(DependencyKind::Dev) => "dev-dependencies",
                    Some(DependencyKind::Build) => "build-dependencies",
                    None => "dependencies",
                };

                document[kind][&self.name]["version"] = value(version.as_str());
            }

            write_file(&package.manifest_path, document.to_string())?;
        }

        Ok(())
    }

    /// Get the changes for the version. If `update` is `true`, update the changelog for the release
    /// of the given version.
    pub fn changes(&self, update: bool) -> Result<String> {
        let mut changelog_path = self.manifest_path.clone();
        changelog_path.set_file_name("CHANGELOG.md");

        let changelog = read_file(&changelog_path)?;
        let version = assign!(self.version.clone(), { pre: vec![], build: vec![] });

        if !changelog.starts_with(&format!("# {}\n", version))
            && !changelog.starts_with(&format!("# {} (unreleased)\n", version))
            && !changelog.starts_with("# [unreleased]\n")
        {
            return Err("Could not find version title in changelog".into());
        };

        let changes_start = match changelog.find('\n') {
            Some(p) => p + 1,
            None => {
                return Err("Could not find end of version title in changelog".into());
            }
        };

        let changes_end = match changelog[changes_start..].find("\n# ") {
            Some(p) => changes_start + p,
            None => changelog.len(),
        };

        let changes = match changelog[changes_start..changes_end].trim() {
            s if s.is_empty() => "No changes for this version",
            s => s,
        };

        if update {
            let changelog = format!(
                "# [unreleased]\n\n# {}\n\n{}\n{}",
                self.version,
                changes,
                &changelog[changes_end..]
            );

            write_file(&changelog_path, changelog)?;
        }

        Ok(changes.to_owned())
    }

    /// Check if the current version of the crate is published on crates.io.
    pub fn is_published(&self, client: &HttpClient) -> Result<bool> {
        let response: CratesIoCrate =
            client.get(format!("{}/{}/{}", CRATESIO_API, self.name, self.version))?.json()?;

        Ok(response.version.is_some())
    }

    /// Publish this package on crates.io.
    pub fn publish(&self, client: &HttpClient) -> Result<bool> {
        println!("Publishing {} {} on crates.io…", self.name, self.version);
        let _dir = pushd(&self.manifest_path.parent().unwrap())?;

        if self.is_published(client)? {
            if ask_yes_no("This version is already published. Skip this step and continue?")? {
                Ok(false)
            } else {
                Err("Release interrupted by user.".into())
            }
        } else {
            cmd!("cargo publish").run()?;
            Ok(true)
        }
    }
}

/// A cargo package dependency.
#[derive(Clone, Debug, Deserialize)]
pub struct Dependency {
    /// The package name.
    pub name: String,

    /// The kind of the dependency.
    pub kind: Option<DependencyKind>,
}

/// The kind of a cargo package dependency.
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum DependencyKind {
    /// A dev dependency.
    Dev,

    /// A build dependency.
    Build,
}

/// A crate from the `GET /crates/{crate}` endpoint of crates.io.
#[derive(Deserialize)]
struct CratesIoCrate {
    version: Option<IgnoredAny>,
}
<|endoftext|>


<commit_before>use std::collections::hash_map::{HashMap, RandomState};
#[cfg(feature = "display")]
use std::fmt::Display;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use {Command, Error, Record};

/// A group of records or histories.
pub struct Group<K: Hash + Eq, V, S = RandomState> {
    group: HashMap<K, V, S>,
    active: Option<K>,
    signal: Option<Box<FnMut(Option<&K>) + Send + Sync + 'static>>,
}

impl<K: Hash + Eq, V> Group<K, V, RandomState> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<K, V, RandomState> {
        Group {
            group: HashMap::new(),
            active: None,
            signal: None,
        }
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Group<K, V, S> {
    /// Returns a builder for a group.
    #[inline]
    pub fn builder() -> GroupBuilder<K, V, S> {
        GroupBuilder {
            group: PhantomData,
            capacity: 0,
            signal: None,
        }
    }

    /// Reserves capacity for at least `additional` more items.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.group.reserve(additional);
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.group.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.group.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.group.is_empty()
    }

    /// Sets how the signal should be handled when the state changes.
    #[inline]
    pub fn set_signal(&mut self, f: impl FnMut(Option<&K>) + Send + Sync + 'static) {
        self.signal = Some(Box::new(f));
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.group.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.group.remove(k)
    }

    /// Gets a reference to the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active
            .as_ref()
            .and_then(|active| self.group.get(active))
    }

    /// Gets a mutable reference to the current active item in the group.
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut V> {
        let group = &mut self.group;
        self.active
            .as_ref()
            .and_then(move |active| group.get_mut(active))
    }

    /// Sets the current active item in the group to `k`.
    ///
    /// Returns `None` if the item was successfully set, otherwise `k` is returned.
    #[inline]
    pub fn set(&mut self, k: impl Into<Option<K>>) -> Option<K> {
        match k.into() {
            Some(k) => {
                if self.group.contains_key(&k) {
                    if self.active.as_ref().map_or(false, |a| a != &k) {
                        if let Some(ref mut f) = self.signal {
                            f(Some(&k))
                        }
                    }
                    self.active = Some(k);
                    None
                } else {
                    Some(k)
                }
            }
            None => {
                if self.active.is_some() {
                    self.active = None;
                    if let Some(ref mut f) = self.signal {
                        f(None);
                    }
                }
                None
            }
        }
    }
}

impl<K: Hash + Eq, R, S: BuildHasher> Group<K, Record<R>, S> {
    /// Calls the [`set_saved`] method on the active record.
    ///
    /// [`set_saved`]: record/struct.Record.html#method.set_saved
    #[inline]
    pub fn set_saved(&mut self, saved: bool) {
        self.get_mut().map(|record| record.set_saved(saved));
    }

    /// Calls the [`is_saved`] method on the active record.
    ///
    /// [`is_saved`]: record/struct.Record.html#method.is_saved
    #[inline]
    pub fn is_saved(&self) -> bool {
        self.get().map_or(false, |record| record.is_saved())
    }

    /// Calls the [`cursor`] method on the active record.
    ///
    /// [`cursor`]: record/struct.Record.html#method.cursor
    #[inline]
    pub fn cursor(&self) -> Option<usize> {
        self.get().map(|record| record.cursor())
    }

    /// Calls the [`set_cursor`] method on the active record.
    ///
    /// [`set_cursor`]: record/struct.Record.html#method.set_cursor
    #[inline]
    pub fn set_cursor(&mut self, cursor: usize) -> Option<Result<(), Error<R>>> {
        self.get_mut().and_then(|record| record.set_cursor(cursor))
    }

    /// Calls the [`apply`] method on the active record.
    ///
    /// [`apply`]: record/struct.Record.html#method.apply
    #[inline]
    pub fn apply(
        &mut self,
        cmd: impl Command<R> + 'static,
    ) -> Option<Result<impl Iterator<Item = Box<Command<R> + 'static>>, Error<R>>>
    where
        R: 'static,
    {
        self.get_mut().map(move |record| record.apply(cmd))
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Error<R>>> {
        self.get_mut().and_then(|record| record.undo())
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Error<R>>> {
        self.get_mut().and_then(|record| record.redo())
    }

    /// Calls the [`to_undo_string`] method on the active record.
    ///
    /// [`to_undo_string`]: record/struct.Record.html#method.to_undo_string
    #[inline]
    #[cfg(feature = "display")]
    pub fn to_undo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_undo_string())
    }

    /// Calls the [`to_redo_string`] method on the active record.
    ///
    /// [`to_redo_string`]: record/struct.Record.html#method.to_redo_string
    #[inline]
    #[cfg(feature = "display")]
    pub fn to_redo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_redo_string())
    }

    /// Returns an iterator over the records.
    #[inline]
    pub fn records(&self) -> impl Iterator<Item = &Record<R>> {
        self.group.values()
    }
}

impl<K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for Group<K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Group")
            .field("group", &self.group)
            .field("active", &self.active)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<K: Hash + Eq + Display, V: Display> Display for Group<K, V> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for (key, item) in &self.group {
            if self.active.as_ref().map_or(false, |a| a == key) {
                writeln!(f, "* {}:\n{}", key, item)?;
            } else {
                writeln!(f, "  {}:\n{}", key, item)?;
            }
        }
        Ok(())
    }
}

impl<K: Hash + Eq, V> Default for Group<K, V, RandomState> {
    #[inline]
    fn default() -> Group<K, V, RandomState> {
        Group::new()
    }
}

/// Builder for a group.
pub struct GroupBuilder<K: Hash + Eq, V, S: BuildHasher> {
    group: PhantomData<(K, V, S)>,
    capacity: usize,
    signal: Option<Box<FnMut(Option<&K>) + Send + Sync + 'static>>,
}

impl<K: Hash + Eq, V> GroupBuilder<K, V, RandomState> {
    /// Creates the group.
    #[inline]
    pub fn build(self) -> Group<K, V, RandomState> {
        self.build_with_hasher(Default::default())
    }
}

impl<K: Hash + Eq, V, S: BuildHasher> GroupBuilder<K, V, S> {
    /// Sets the specified [capacity] for the group.
    ///
    /// [capacity]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
    #[inline]
    pub fn capacity(mut self, capacity: usize) -> GroupBuilder<K, V, S> {
        self.capacity = capacity;
        self
    }

    /// Decides what should happen when the active stack changes.
    #[inline]
    pub fn signal<F>(
        mut self,
        f: impl FnMut(Option<&K>) + Send + Sync + 'static,
    ) -> GroupBuilder<K, V, S> {
        self.signal = Some(Box::new(f));
        self
    }

    /// Creates the group with the given hasher.
    #[inline]
    pub fn build_with_hasher(self, hasher: S) -> Group<K, V, S> {
        Group {
            group: HashMap::with_capacity_and_hasher(self.capacity, hasher),
            active: None,
            signal: self.signal,
        }
    }
}

impl<K: Hash + Eq, V, S: BuildHasher> Debug for GroupBuilder<K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("GroupBuilder")
            .field("group", &self.group)
            .field("capacity", &self.capacity)
            .finish()
    }
}
<commit_msg>Rename getters and setters for Group<commit_after>use std::collections::hash_map::{HashMap, RandomState};
#[cfg(feature = "display")]
use std::fmt::Display;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use {Command, Error, Record};

/// A group of records or histories.
pub struct Group<K: Hash + Eq, V, S = RandomState> {
    group: HashMap<K, V, S>,
    active: Option<K>,
    signal: Option<Box<FnMut(Option<&K>) + Send + Sync + 'static>>,
}

impl<K: Hash + Eq, V> Group<K, V, RandomState> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<K, V, RandomState> {
        Group {
            group: HashMap::new(),
            active: None,
            signal: None,
        }
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Group<K, V, S> {
    /// Returns a builder for a group.
    #[inline]
    pub fn builder() -> GroupBuilder<K, V, S> {
        GroupBuilder {
            group: PhantomData,
            capacity: 0,
            signal: None,
        }
    }

    /// Reserves capacity for at least `additional` more items.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.group.reserve(additional);
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.group.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.group.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.group.is_empty()
    }

    /// Sets how the signal should be handled when the state changes.
    #[inline]
    pub fn set_signal(&mut self, f: impl FnMut(Option<&K>) + Send + Sync + 'static) {
        self.signal = Some(Box::new(f));
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.group.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.group.remove(k)
    }

    /// Gets a reference to the current active item in the group.
    #[inline]
    pub fn active(&self) -> Option<&V> {
        self.active
            .as_ref()
            .and_then(|active| self.group.get(active))
    }

    /// Gets a mutable reference to the current active item in the group.
    #[inline]
    pub fn active_mut(&mut self) -> Option<&mut V> {
        let group = &mut self.group;
        self.active
            .as_ref()
            .and_then(move |active| group.get_mut(active))
    }

    /// Sets the current active item in the group to `k`.
    ///
    /// Returns `None` if the item was successfully set, otherwise `k` is returned.
    #[inline]
    pub fn set_active(&mut self, k: impl Into<Option<K>>) -> Option<K> {
        match k.into() {
            Some(k) => {
                if self.group.contains_key(&k) {
                    if self.active.as_ref().map_or(false, |a| a != &k) {
                        if let Some(ref mut f) = self.signal {
                            f(Some(&k))
                        }
                    }
                    self.active = Some(k);
                    None
                } else {
                    Some(k)
                }
            }
            None => {
                if self.active.is_some() {
                    self.active = None;
                    if let Some(ref mut f) = self.signal {
                        f(None);
                    }
                }
                None
            }
        }
    }
}

impl<K: Hash + Eq, R, S: BuildHasher> Group<K, Record<R>, S> {
    /// Calls the [`set_saved`] method on the active record.
    ///
    /// [`set_saved`]: record/struct.Record.html#method.set_saved
    #[inline]
    pub fn set_saved(&mut self, saved: bool) {
        self.active_mut().map(|record| record.set_saved(saved));
    }

    /// Calls the [`is_saved`] method on the active record.
    ///
    /// [`is_saved`]: record/struct.Record.html#method.is_saved
    #[inline]
    pub fn is_saved(&self) -> bool {
        self.active().map_or(false, |record| record.is_saved())
    }

    /// Calls the [`cursor`] method on the active record.
    ///
    /// [`cursor`]: record/struct.Record.html#method.cursor
    #[inline]
    pub fn cursor(&self) -> Option<usize> {
        self.active().map(|record| record.cursor())
    }

    /// Calls the [`set_cursor`] method on the active record.
    ///
    /// [`set_cursor`]: record/struct.Record.html#method.set_cursor
    #[inline]
    pub fn set_cursor(&mut self, cursor: usize) -> Option<Result<(), Error<R>>> {
        self.active_mut().and_then(|record| record.set_cursor(cursor))
    }

    /// Calls the [`apply`] method on the active record.
    ///
    /// [`apply`]: record/struct.Record.html#method.apply
    #[inline]
    pub fn apply(
        &mut self,
        cmd: impl Command<R> + 'static,
    ) -> Option<Result<impl Iterator<Item = Box<Command<R> + 'static>>, Error<R>>>
    where
        R: 'static,
    {
        self.active_mut().map(move |record| record.apply(cmd))
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Error<R>>> {
        self.active_mut().and_then(|record| record.undo())
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Error<R>>> {
        self.active_mut().and_then(|record| record.redo())
    }

    /// Calls the [`to_undo_string`] method on the active record.
    ///
    /// [`to_undo_string`]: record/struct.Record.html#method.to_undo_string
    #[inline]
    #[cfg(feature = "display")]
    pub fn to_undo_string(&self) -> Option<String> {
        self.active().and_then(|record| record.to_undo_string())
    }

    /// Calls the [`to_redo_string`] method on the active record.
    ///
    /// [`to_redo_string`]: record/struct.Record.html#method.to_redo_string
    #[inline]
    #[cfg(feature = "display")]
    pub fn to_redo_string(&self) -> Option<String> {
        self.active().and_then(|record| record.to_redo_string())
    }
}

impl<K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for Group<K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Group")
            .field("group", &self.group)
            .field("active", &self.active)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<K: Hash + Eq + Display, V: Display> Display for Group<K, V> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for (key, item) in &self.group {
            if self.active.as_ref().map_or(false, |a| a == key) {
                writeln!(f, "* {}:\n{}", key, item)?;
            } else {
                writeln!(f, "  {}:\n{}", key, item)?;
            }
        }
        Ok(())
    }
}

impl<K: Hash + Eq, V> Default for Group<K, V, RandomState> {
    #[inline]
    fn default() -> Group<K, V, RandomState> {
        Group::new()
    }
}

/// Builder for a group.
pub struct GroupBuilder<K: Hash + Eq, V, S: BuildHasher> {
    group: PhantomData<(K, V, S)>,
    capacity: usize,
    signal: Option<Box<FnMut(Option<&K>) + Send + Sync + 'static>>,
}

impl<K: Hash + Eq, V> GroupBuilder<K, V, RandomState> {
    /// Creates the group.
    #[inline]
    pub fn build(self) -> Group<K, V, RandomState> {
        self.build_with_hasher(Default::default())
    }
}

impl<K: Hash + Eq, V, S: BuildHasher> GroupBuilder<K, V, S> {
    /// Sets the specified [capacity] for the group.
    ///
    /// [capacity]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
    #[inline]
    pub fn capacity(mut self, capacity: usize) -> GroupBuilder<K, V, S> {
        self.capacity = capacity;
        self
    }

    /// Decides what should happen when the active stack changes.
    #[inline]
    pub fn signal<F>(
        mut self,
        f: impl FnMut(Option<&K>) + Send + Sync + 'static,
    ) -> GroupBuilder<K, V, S> {
        self.signal = Some(Box::new(f));
        self
    }

    /// Creates the group with the given hasher.
    #[inline]
    pub fn build_with_hasher(self, hasher: S) -> Group<K, V, S> {
        Group {
            group: HashMap::with_capacity_and_hasher(self.capacity, hasher),
            active: None,
            signal: self.signal,
        }
    }
}

impl<K: Hash + Eq, V, S: BuildHasher> Debug for GroupBuilder<K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("GroupBuilder")
            .field("group", &self.group)
            .field("capacity", &self.capacity)
            .finish()
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::net::{self, SocketAddr};
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::sync::{Arc, Barrier};
use std::thread;

use mio::net::TcpListener;
use mio::{Interests, Poll, Token};

mod util;

use util::{
    any_local_address, any_local_ipv6_address, assert_send, assert_sync, assert_would_block,
    expect_events, expect_no_events, init, init_with_poll, ExpectEvent,
};

const ID1: Token = Token(0);
const ID2: Token = Token(1);

#[test]
fn is_send_and_sync() {
    assert_send::<TcpListener>();
    assert_sync::<TcpListener>();
}

#[test]
fn tcp_listener() {
    smoke_test_tcp_listener(any_local_address());
}

#[test]
fn tcp_listener_ipv6() {
    smoke_test_tcp_listener(any_local_ipv6_address());
}

fn smoke_test_tcp_listener(addr: SocketAddr) {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(addr).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .expect("unable to register TCP listener");

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );

    // Expect a single connection.
    let (mut stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    // Expect the stream to be non-blocking.
    let mut buf = [0; 20];
    assert_would_block(stream.read(&mut buf));

    // Expect no more connections.
    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
fn ttl() {
    init();

    let listener = TcpListener::bind(any_local_address()).unwrap();

    const TTL: u32 = 10;
    listener.set_ttl(TTL).unwrap();
    assert_eq!(listener.ttl().unwrap(), TTL);
    assert!(listener.take_error().unwrap().is_none());
}

#[test]
#[cfg(unix)]
fn raw_fd() {
    init();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    let raw_fd1 = listener.as_raw_fd();
    let raw_fd2 = listener.into_raw_fd();
    assert_eq!(raw_fd1, raw_fd2);

    let listener = unsafe { TcpListener::from_raw_fd(raw_fd2) };
    assert_eq!(listener.as_raw_fd(), raw_fd1);
    assert_eq!(listener.local_addr().unwrap(), address);
}

#[test]
fn registering() {
    let (mut poll, mut events) = init_with_poll();

    let stream = TcpListener::bind(any_local_address()).unwrap();

    poll.registry()
        .register(&stream, ID1, Interests::READABLE)
        .expect("unable to register TCP listener");

    expect_no_events(&mut poll, &mut events);

    // NOTE: more tests are done in the smoke tests above.
}

#[test]
fn reregister() {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .unwrap();
    poll.registry()
        .reregister(&listener, ID2, Interests::READABLE)
        .unwrap();

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
#[cfg_attr(windows, ignore = "deregister doesn't work, see #1073")]
fn deregister() {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .unwrap();

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    poll.registry().deregister(&listener).unwrap();

    expect_no_events(&mut poll, &mut events);

    // Should still be able to accept the connection.
    let (stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
fn try_clone_same_poll() {
    let (mut poll, mut events) = init_with_poll();

    let listener1 = TcpListener::bind(any_local_address()).unwrap();
    let listener2 = listener1.try_clone().expect("unable to clone TCP listener");
    #[cfg(unix)]
    assert_ne!(listener1.as_raw_fd(), listener2.as_raw_fd());
    let address = listener1.local_addr().unwrap();
    assert_eq!(address, listener2.local_addr().unwrap());

    let barrier = Arc::new(Barrier::new(3));
    let thread_handle1 = start_connections(address, 1, barrier.clone());

    poll.registry()
        .register(&listener1, ID1, Interests::READABLE)
        .unwrap();
    poll.registry()
        .register(&listener2, ID2, Interests::READABLE)
        .unwrap();

    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(ID1, Interests::READABLE),
            ExpectEvent::new(ID2, Interests::READABLE),
        ],
    );

    let (stream, peer_address) = listener1.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    let thread_handle2 = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(ID1, Interests::READABLE),
            ExpectEvent::new(ID2, Interests::READABLE),
        ],
    );

    let (stream, peer_address) = listener2.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener1.accept());
    assert_would_block(listener2.accept());

    assert!(listener1.take_error().unwrap().is_none());
    assert!(listener2.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle1.join().expect("unable to join thread");
    thread_handle2.join().expect("unable to join thread");
}

#[test]
fn try_clone_different_poll() {
    let (mut poll1, mut events) = init_with_poll();
    let mut poll2 = Poll::new().unwrap();

    let listener1 = TcpListener::bind(any_local_address()).unwrap();
    let listener2 = listener1.try_clone().expect("unable to clone TCP listener");
    #[cfg(unix)]
    assert_ne!(listener1.as_raw_fd(), listener2.as_raw_fd());
    let address = listener1.local_addr().unwrap();
    assert_eq!(address, listener2.local_addr().unwrap());

    let barrier = Arc::new(Barrier::new(3));
    let thread_handle1 = start_connections(address, 1, barrier.clone());

    poll1
        .registry()
        .register(&listener1, ID1, Interests::READABLE)
        .unwrap();
    poll2
        .registry()
        .register(&listener2, ID2, Interests::READABLE)
        .unwrap();

    expect_events(
        &mut poll1,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );
    expect_events(
        &mut poll2,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener1.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    let thread_handle2 = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll1,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );
    expect_events(
        &mut poll2,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener2.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener1.accept());
    assert_would_block(listener2.accept());

    assert!(listener1.take_error().unwrap().is_none());
    assert!(listener2.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle1.join().expect("unable to join thread");
    thread_handle2.join().expect("unable to join thread");
}

/// Start `n_connections` connections to `address`. If a `barrier` is provided
/// it will wait on it after each connection is made before it is dropped.
fn start_connections(
    address: SocketAddr,
    n_connections: usize,
    barrier: Arc<Barrier>,
) -> thread::JoinHandle<()> {
    thread::spawn(move || {
        for _ in 0..n_connections {
            let conn = net::TcpStream::connect(address).unwrap();
            barrier.wait();
            drop(conn);
        }
    })
}
<commit_msg>Disable TcpListener::try_clone tests on Windows<commit_after>use std::io::Read;
use std::net::{self, SocketAddr};
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::sync::{Arc, Barrier};
use std::thread;

use mio::net::TcpListener;
use mio::{Interests, Poll, Token};

mod util;

use util::{
    any_local_address, any_local_ipv6_address, assert_send, assert_sync, assert_would_block,
    expect_events, expect_no_events, init, init_with_poll, ExpectEvent,
};

const ID1: Token = Token(0);
const ID2: Token = Token(1);

#[test]
fn is_send_and_sync() {
    assert_send::<TcpListener>();
    assert_sync::<TcpListener>();
}

#[test]
fn tcp_listener() {
    smoke_test_tcp_listener(any_local_address());
}

#[test]
fn tcp_listener_ipv6() {
    smoke_test_tcp_listener(any_local_ipv6_address());
}

fn smoke_test_tcp_listener(addr: SocketAddr) {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(addr).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .expect("unable to register TCP listener");

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );

    // Expect a single connection.
    let (mut stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    // Expect the stream to be non-blocking.
    let mut buf = [0; 20];
    assert_would_block(stream.read(&mut buf));

    // Expect no more connections.
    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
fn ttl() {
    init();

    let listener = TcpListener::bind(any_local_address()).unwrap();

    const TTL: u32 = 10;
    listener.set_ttl(TTL).unwrap();
    assert_eq!(listener.ttl().unwrap(), TTL);
    assert!(listener.take_error().unwrap().is_none());
}

#[test]
#[cfg(unix)]
fn raw_fd() {
    init();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    let raw_fd1 = listener.as_raw_fd();
    let raw_fd2 = listener.into_raw_fd();
    assert_eq!(raw_fd1, raw_fd2);

    let listener = unsafe { TcpListener::from_raw_fd(raw_fd2) };
    assert_eq!(listener.as_raw_fd(), raw_fd1);
    assert_eq!(listener.local_addr().unwrap(), address);
}

#[test]
fn registering() {
    let (mut poll, mut events) = init_with_poll();

    let stream = TcpListener::bind(any_local_address()).unwrap();

    poll.registry()
        .register(&stream, ID1, Interests::READABLE)
        .expect("unable to register TCP listener");

    expect_no_events(&mut poll, &mut events);

    // NOTE: more tests are done in the smoke tests above.
}

#[test]
fn reregister() {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .unwrap();
    poll.registry()
        .reregister(&listener, ID2, Interests::READABLE)
        .unwrap();

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
#[cfg_attr(windows, ignore = "deregister doesn't work, see #1073")]
fn deregister() {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .unwrap();

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    poll.registry().deregister(&listener).unwrap();

    expect_no_events(&mut poll, &mut events);

    // Should still be able to accept the connection.
    let (stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
#[cfg_attr(windows, ignore = "fails on Windows, see #1073")]
fn try_clone_same_poll() {
    let (mut poll, mut events) = init_with_poll();

    let listener1 = TcpListener::bind(any_local_address()).unwrap();
    let listener2 = listener1.try_clone().expect("unable to clone TCP listener");
    #[cfg(unix)]
    assert_ne!(listener1.as_raw_fd(), listener2.as_raw_fd());
    let address = listener1.local_addr().unwrap();
    assert_eq!(address, listener2.local_addr().unwrap());

    let barrier = Arc::new(Barrier::new(3));
    let thread_handle1 = start_connections(address, 1, barrier.clone());

    poll.registry()
        .register(&listener1, ID1, Interests::READABLE)
        .unwrap();
    poll.registry()
        .register(&listener2, ID2, Interests::READABLE)
        .unwrap();

    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(ID1, Interests::READABLE),
            ExpectEvent::new(ID2, Interests::READABLE),
        ],
    );

    let (stream, peer_address) = listener1.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    let thread_handle2 = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(ID1, Interests::READABLE),
            ExpectEvent::new(ID2, Interests::READABLE),
        ],
    );

    let (stream, peer_address) = listener2.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener1.accept());
    assert_would_block(listener2.accept());

    assert!(listener1.take_error().unwrap().is_none());
    assert!(listener2.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle1.join().expect("unable to join thread");
    thread_handle2.join().expect("unable to join thread");
}

#[test]
#[cfg_attr(windows, ignore = "fails on Windows, see #1073")]
fn try_clone_different_poll() {
    let (mut poll1, mut events) = init_with_poll();
    let mut poll2 = Poll::new().unwrap();

    let listener1 = TcpListener::bind(any_local_address()).unwrap();
    let listener2 = listener1.try_clone().expect("unable to clone TCP listener");
    #[cfg(unix)]
    assert_ne!(listener1.as_raw_fd(), listener2.as_raw_fd());
    let address = listener1.local_addr().unwrap();
    assert_eq!(address, listener2.local_addr().unwrap());

    let barrier = Arc::new(Barrier::new(3));
    let thread_handle1 = start_connections(address, 1, barrier.clone());

    poll1
        .registry()
        .register(&listener1, ID1, Interests::READABLE)
        .unwrap();
    poll2
        .registry()
        .register(&listener2, ID2, Interests::READABLE)
        .unwrap();

    expect_events(
        &mut poll1,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );
    expect_events(
        &mut poll2,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener1.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    let thread_handle2 = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll1,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );
    expect_events(
        &mut poll2,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener2.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener1.accept());
    assert_would_block(listener2.accept());

    assert!(listener1.take_error().unwrap().is_none());
    assert!(listener2.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle1.join().expect("unable to join thread");
    thread_handle2.join().expect("unable to join thread");
}

/// Start `n_connections` connections to `address`. If a `barrier` is provided
/// it will wait on it after each connection is made before it is dropped.
fn start_connections(
    address: SocketAddr,
    n_connections: usize,
    barrier: Arc<Barrier>,
) -> thread::JoinHandle<()> {
    thread::spawn(move || {
        for _ in 0..n_connections {
            let conn = net::TcpStream::connect(address).unwrap();
            barrier.wait();
            drop(conn);
        }
    })
}
<|endoftext|>


<commit_before>use krate::Crate;
use schema::badges;
use util::CargoResult;

use diesel::pg::{Pg, PgConnection};
use diesel::prelude::*;
use serde_json;
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case", tag = "badge_type", content = "attributes")]
pub enum Badge {
    TravisCi {
        repository: String,
        branch: Option<String>,
    },
    Appveyor {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    GitLab {
        repository: String,
        branch: Option<String>,
    },
    IsItMaintainedIssueResolution { repository: String },
    IsItMaintainedOpenIssues { repository: String },
    Codecov {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    Coveralls {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
}

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

impl Queryable<badges::SqlType, Pg> for Badge {
    type Row = (i32, String, serde_json::Value);

    fn build((_, badge_type, attributes): Self::Row) -> Self {
        let json = json!({"badge_type": badge_type, "attributes": attributes});
        serde_json::from_value(json).expect("Invalid CI badge in the database")
    }
}

impl Badge {
    pub fn encodable(self) -> EncodableBadge {
        serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap()
    }

    pub fn badge_type(&self) -> &'static str {
        match *self {
            Badge::TravisCi { .. } => "travis-ci",
            Badge::Appveyor { .. } => "appveyor",
            Badge::GitLab { .. } => "git-lab",
            Badge::IsItMaintainedIssueResolution { .. } => "is-it-maintained-issue-resolution",
            Badge::IsItMaintainedOpenIssues { .. } => "is-it-maintained-open-issues",
            Badge::Codecov { .. } => "codecov",
            Badge::Coveralls { .. } => "coveralls",
        }
    }

    pub fn update_crate<'a>(
        conn: &PgConnection,
        krate: &Crate,
        badges: Option<&'a HashMap<String, HashMap<String, String>>>,
    ) -> CargoResult<Vec<&'a str>> {
        use diesel::{insert, delete};

        #[derive(Insertable)]
        #[table_name = "badges"]
        struct NewBadge<'a> {
            crate_id: i32,
            badge_type: &'a str,
            attributes: serde_json::Value,
        }

        let mut invalid_badges = vec![];
        let mut new_badges = vec![];

        if let Some(badges) = badges {
            for (k, v) in badges {
                let attributes_json = serde_json::to_value(v).unwrap();

                let json = json!({"badge_type": k, "attributes": attributes_json});
                if serde_json::from_value::<Badge>(json).is_ok() {
                    new_badges.push(NewBadge {
                        crate_id: krate.id,
                        badge_type: &**k,
                        attributes: attributes_json,
                    });
                } else {
                    invalid_badges.push(&**k);
                }
            }
        }

        conn.transaction(|| {
            delete(badges::table.filter(badges::crate_id.eq(krate.id)))
                .execute(conn)?;
            insert(&new_badges).into(badges::table).execute(conn)?;
            Ok(invalid_badges)
        })
    }
}
<commit_msg>Remove unused method (badge_type)<commit_after>use krate::Crate;
use schema::badges;
use util::CargoResult;

use diesel::pg::{Pg, PgConnection};
use diesel::prelude::*;
use serde_json;
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case", tag = "badge_type", content = "attributes")]
pub enum Badge {
    TravisCi {
        repository: String,
        branch: Option<String>,
    },
    Appveyor {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    GitLab {
        repository: String,
        branch: Option<String>,
    },
    IsItMaintainedIssueResolution { repository: String },
    IsItMaintainedOpenIssues { repository: String },
    Codecov {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    Coveralls {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
}

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

impl Queryable<badges::SqlType, Pg> for Badge {
    type Row = (i32, String, serde_json::Value);

    fn build((_, badge_type, attributes): Self::Row) -> Self {
        let json = json!({"badge_type": badge_type, "attributes": attributes});
        serde_json::from_value(json).expect("Invalid CI badge in the database")
    }
}

impl Badge {
    pub fn encodable(self) -> EncodableBadge {
        serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap()
    }

    pub fn update_crate<'a>(
        conn: &PgConnection,
        krate: &Crate,
        badges: Option<&'a HashMap<String, HashMap<String, String>>>,
    ) -> CargoResult<Vec<&'a str>> {
        use diesel::{insert, delete};

        #[derive(Insertable)]
        #[table_name = "badges"]
        struct NewBadge<'a> {
            crate_id: i32,
            badge_type: &'a str,
            attributes: serde_json::Value,
        }

        let mut invalid_badges = vec![];
        let mut new_badges = vec![];

        if let Some(badges) = badges {
            for (k, v) in badges {
                let attributes_json = serde_json::to_value(v).unwrap();

                let json = json!({"badge_type": k, "attributes": attributes_json});
                if serde_json::from_value::<Badge>(json).is_ok() {
                    new_badges.push(NewBadge {
                        crate_id: krate.id,
                        badge_type: &**k,
                        attributes: attributes_json,
                    });
                } else {
                    invalid_badges.push(&**k);
                }
            }
        }

        conn.transaction(|| {
            delete(badges::table.filter(badges::crate_id.eq(krate.id)))
                .execute(conn)?;
            insert(&new_badges).into(badges::table).execute(conn)?;
            Ok(invalid_badges)
        })
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "nightly")]

mod rex_bench {
    extern crate test;
    use self::test::Bencher;

    #[bench]
    fn bench_code_chunks(b: &mut Bencher) {
        b.iter(|| {
            test::black_box(vec![1, 2, 3]);
        });
    }

}
<commit_msg>Simple benchmarking for view drawing<commit_after>#[cfg(feature = "nightly")]

mod rex_bench {
    extern crate test;
    use self::test::Bencher;
    use super::super::ui::view::HexEdit;
    use super::super::frontend::{Frontend, Event, Style, KeyPress};

    /// Represents an empty frontend, can be merged in the future with the mock frontend
    struct EmptyFrontend;

    impl Frontend for EmptyFrontend {
        fn clear(&self) {
        }

        fn present(&self) {
        }

        fn print_style(&self, x: usize, y: usize, style: Style, s: &str) {
            test::black_box((x, y, style, s));
        }

        fn print_char_style(&self, x: usize, y: usize, style: Style, c: char) {
            test::black_box((x, y, style, c));
        }

        fn print_slice_style(&self, x: usize, y: usize, style: Style, chars: &[char]) {
            test::black_box((x, y, style, chars));
        }

        fn set_cursor(&mut self, x: isize, y: isize) {
            test::black_box((x, y));
        }

        fn height(&self) -> usize {
            1024
        }

        fn width(&self) -> usize {
            1024
        }

        fn poll_event(&mut self) -> Event {
            panic!("Unimplemented!");
        }
    }

    #[bench]
    fn bench_code_chunks(b: &mut Bencher) {
        let mut edit: HexEdit = HexEdit::new();
        let mut frontend = EmptyFrontend;
        edit.open_vec((0..0x10000).map(|x| (x & 0xff) as u8).collect());

        b.iter(|| {
            edit.draw(&mut frontend);
        });
    }

}
<|endoftext|>


<commit_before>#[cfg(test)]
extern crate test;

use std::{fmt, rt};
use std::rand::{task_rng, Rng};
use std::sync::{Arc, TaskPool, RWLock, Semaphore};

#[cfg(test)]
use self::test::Bencher;

static LIVE_CELL: char = '@';
static DEAD_CELL: char = '.';

#[deriving(PartialEq, Eq, Clone)]
pub struct Board {
  board: Vec<bool>,
  survive: Vec<uint>,
  born: Vec<uint>,
  rows: uint,
  cols: uint
}

pub struct WorkerPool {
  pool: TaskPool<()>,
  size: uint
}

impl WorkerPool {
  pub fn new(size: uint) -> WorkerPool {
    WorkerPool {
      pool: TaskPool::new(size, || proc(_) {}),
      size: size
    }
  }

  pub fn new_with_default_size() -> WorkerPool {
    WorkerPool::new(rt::default_sched_threads())
  }
}

struct FutureBoard {
  board: Vec<Vec<bool>>,
  tasks_done: uint,
}

impl FutureBoard {
  fn cells(&self) -> Vec<bool> {
    self.board.as_slice().concat_vec()
  }
}

struct BoardAdvancer {
  board: Board,
  next_board: RWLock<FutureBoard>,
  done: Semaphore
}

impl BoardAdvancer {
  fn new(board: &Board, num_tasks: uint) -> BoardAdvancer {
    BoardAdvancer {
      board: board.clone(),
      next_board: RWLock::new(FutureBoard {
        board: Vec::from_elem(num_tasks, vec![]),
        tasks_done: 0
      }),
      done: Semaphore::new(0)
    }
  }

  fn advance(board: &Board, workers: &mut WorkerPool) -> Vec<bool> {
    let shared_board = Arc::new(BoardAdvancer::new(board, workers.size));
    let length = board.len();
    let all_tasks: Vec<uint> = range(0, length).collect();
    let tasks: Vec<&[uint]> = all_tasks.as_slice().chunks((length + workers.size - 1) / workers.size).collect();
    let task_count = tasks.clone().iter().len();

    for (i, task) in tasks.iter().enumerate() {
      let task_board = shared_board.clone();
      let task = task.to_vec();

      workers.pool.execute(proc(_) {
        let task_values = task.iter().map(|&idx|
          task_board.board.successor_cell(idx)
        ).collect::<Vec<bool>>();
        let mut task_results = task_board.next_board.write();
        *task_results.board.get_mut(i) = task_values;
        task_results.tasks_done += 1;
        if task_results.tasks_done == task_count { task_board.done.release(); }
      });

    };
    shared_board.done.acquire();
    shared_board.next_board.read().cells()
  }

}

impl Board {
  pub fn new(rows: uint, cols: uint) -> Board {
    let born = vec![3];
    let survive = vec![2, 3];

    Board::new_with_custom_rules(rows, cols, born, survive)
  }

  fn new_with_custom_rules(rows: uint, cols: uint, born: Vec<uint>, survive: Vec<uint>) -> Board {
    let new_board = Vec::from_elem(rows * cols, false);

    Board { board  : new_board,
            born   : born,
            survive: survive,
            rows   : rows,
            cols   : cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn next_board(&self, new_board: Vec<bool>) -> Board {
    assert!(new_board.len() == self.len());

    Board { board  : new_board,
            born   : self.born.clone(),
            survive: self.survive.clone(),
            rows   : self.rows,
            cols   : self.cols }
  }

  pub fn random(&self) -> Board {
    let board = task_rng().gen_iter::<bool>().take(self.len()).collect();

    self.next_board(board)
  }

  fn next_generation(&self) -> Board {
    let new_brd = Vec::from_fn(self.len(), |cell| self.successor_cell(cell));

    self.next_board(new_brd)
  }

  pub fn parallel_next_generation(&self, workers: &mut WorkerPool) -> Board {
    let new_brd = BoardAdvancer::advance(self, workers);

    self.next_board(new_brd)
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && self.board[y * self.cols + x]
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().filter(|&x| *x).count()
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      self.survive.contains(&neighbors)
    } else {
      self.born.contains(&neighbors)
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: Vec<&str> = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows[0].len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd: Option<Vec<bool>> = rows.concat().into_bytes()
      .move_iter().map(|c| match c as char {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      }).collect();

    match brd {
      Some(board) => Some(Board::new(row_cnt, col_cnt).next_board(board)),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> String {
      let chars: Vec<char> = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      String::from_chars(chars.as_slice())
    }

    let rows: Vec<String> = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
static test_boards: [&'static str, ..3] = [
  ".@.\n.@@\n.@@",
  "...\n@@@\n...",
  ".@.\n.@.\n.@."
];

#[cfg(test)]
fn testing_board(n: uint) -> Board {
  Board::from_str(test_boards[n]).unwrap()
}

#[test]
fn test_board_str_conversion() {
  assert_eq!(testing_board(0).to_string(), test_boards[0].to_string());
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert_eq!(brd.living_neighbors(0, 0), 2);
  assert_eq!(brd.living_neighbors(2, 2), 3);
}

#[test]
fn test_next_generation() {
  assert_eq!(testing_board(1).next_generation(), testing_board(2));
}

#[test]
fn test_parallel_next_generation() {
  let ref mut workers = WorkerPool::new_with_default_size();

  assert_eq!(testing_board(1).parallel_next_generation(workers), testing_board(2));
}

#[bench]
fn bench_random(b: &mut Bencher) {
  let brd = Board::new(200,200);
  b.iter(|| brd.random());
}

#[bench]
fn bench_ten_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10u) { brd = brd.next_generation() }

  );
}

#[bench]
fn bench_ten_parallel_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  let ref mut workers = WorkerPool::new_with_default_size();

  b.iter(|| {
    for _ in range(0,10u) { brd = brd.parallel_next_generation(workers) }
  });
}
<commit_msg>works on rust nightly again<commit_after>#[cfg(test)]
extern crate test;

use std::{fmt, rt};
use std::rand::{task_rng, Rng};
use std::sync::{Arc, TaskPool, RWLock, Semaphore};

#[cfg(test)]
use self::test::Bencher;

const LIVE_CELL: char = '@';
const DEAD_CELL: char = '.';

#[deriving(PartialEq, Eq, Clone)]
pub struct Board {
  board: Vec<bool>,
  survive: Vec<uint>,
  born: Vec<uint>,
  rows: uint,
  cols: uint
}

pub struct WorkerPool {
  pool: TaskPool<()>,
  size: uint
}

impl WorkerPool {
  pub fn new(size: uint) -> WorkerPool {
    WorkerPool {
      pool: TaskPool::new(size, || proc(_) {}),
      size: size
    }
  }

  pub fn new_with_default_size() -> WorkerPool {
    WorkerPool::new(rt::default_sched_threads())
  }
}

struct FutureBoard {
  board: Vec<Vec<bool>>,
  tasks_done: uint,
}

impl FutureBoard {
  fn cells(&self) -> Vec<bool> {
    self.board.as_slice().concat_vec()
  }
}

struct BoardAdvancer {
  board: Board,
  next_board: RWLock<FutureBoard>,
  done: Semaphore
}

impl BoardAdvancer {
  fn new(board: &Board, num_tasks: uint) -> BoardAdvancer {
    BoardAdvancer {
      board: board.clone(),
      next_board: RWLock::new(FutureBoard {
        board: Vec::from_elem(num_tasks, vec![]),
        tasks_done: 0
      }),
      done: Semaphore::new(0)
    }
  }

  fn advance(board: &Board, workers: &mut WorkerPool) -> Vec<bool> {
    let shared_board = Arc::new(BoardAdvancer::new(board, workers.size));
    let length = board.len();
    let all_tasks: Vec<uint> = range(0, length).collect();
    let tasks: Vec<&[uint]> = all_tasks.as_slice().chunks((length + workers.size - 1) / workers.size).collect();
    let task_count = tasks.clone().iter().len();

    for (i, task) in tasks.iter().enumerate() {
      let task_board = shared_board.clone();
      let task = task.to_vec();

      workers.pool.execute(proc(_) {
        let task_values = task.iter().map(|&idx|
          task_board.board.successor_cell(idx)
        ).collect::<Vec<bool>>();
        let mut task_results = task_board.next_board.write();
        *task_results.board.get_mut(i) = task_values;
        task_results.tasks_done += 1;
        if task_results.tasks_done == task_count { task_board.done.release(); }
      });

    };
    shared_board.done.acquire();
    shared_board.next_board.read().cells()
  }

}

impl Board {
  pub fn new(rows: uint, cols: uint) -> Board {
    let born = vec![3];
    let survive = vec![2, 3];

    Board::new_with_custom_rules(rows, cols, born, survive)
  }

  fn new_with_custom_rules(rows: uint, cols: uint, born: Vec<uint>, survive: Vec<uint>) -> Board {
    let new_board = Vec::from_elem(rows * cols, false);

    Board { board  : new_board,
            born   : born,
            survive: survive,
            rows   : rows,
            cols   : cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn next_board(&self, new_board: Vec<bool>) -> Board {
    assert!(new_board.len() == self.len());

    Board { board  : new_board,
            born   : self.born.clone(),
            survive: self.survive.clone(),
            rows   : self.rows,
            cols   : self.cols }
  }

  pub fn random(&self) -> Board {
    let board = task_rng().gen_iter::<bool>().take(self.len()).collect();

    self.next_board(board)
  }

  fn next_generation(&self) -> Board {
    let new_brd = Vec::from_fn(self.len(), |cell| self.successor_cell(cell));

    self.next_board(new_brd)
  }

  pub fn parallel_next_generation(&self, workers: &mut WorkerPool) -> Board {
    let new_brd = BoardAdvancer::advance(self, workers);

    self.next_board(new_brd)
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && self.board[y * self.cols + x]
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().filter(|&x| *x).count()
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      self.survive.contains(&neighbors)
    } else {
      self.born.contains(&neighbors)
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: Vec<&str> = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows[0].len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd: Option<Vec<bool>> = rows.concat().into_bytes()
      .into_iter().map(|c| match c as char {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      }).collect();

    match brd {
      Some(board) => Some(Board::new(row_cnt, col_cnt).next_board(board)),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> String {
      let chars: Vec<char> = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      String::from_chars(chars.as_slice())
    }

    let rows: Vec<String> = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
const TEST_BOARDS: [&'static str, ..3] = [
  ".@.\n.@@\n.@@",
  "...\n@@@\n...",
  ".@.\n.@.\n.@."
];

#[cfg(test)]
fn testing_board(n: uint) -> Board {
  Board::from_str(TEST_BOARDS[n]).unwrap()
}

#[test]
fn test_board_str_conversion() {
  assert_eq!(testing_board(0).to_string(), TEST_BOARDS[0].to_string());
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert_eq!(brd.living_neighbors(0, 0), 2);
  assert_eq!(brd.living_neighbors(2, 2), 3);
}

#[test]
fn test_next_generation() {
  assert_eq!(testing_board(1).next_generation(), testing_board(2));
}

#[test]
fn test_parallel_next_generation() {
  let ref mut workers = WorkerPool::new_with_default_size();

  assert_eq!(testing_board(1).parallel_next_generation(workers), testing_board(2));
}

#[bench]
fn bench_random(b: &mut Bencher) {
  let brd = Board::new(200,200);
  b.iter(|| brd.random());
}

#[bench]
fn bench_ten_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10u) { brd = brd.next_generation() }

  );
}

#[bench]
fn bench_ten_parallel_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  let ref mut workers = WorkerPool::new_with_default_size();

  b.iter(|| {
    for _ in range(0,10u) { brd = brd.parallel_next_generation(workers) }
  });
}
<|endoftext|>