<commit_before>// implements http://rosettacode.org/wiki/Zig-zag_matrix
// with the sorting indexes algorithm
// explained in the discussion page
// http://rosettacode.org/wiki/Talk:Zig-zag_matrix

#[deriving(Show, PartialEq, Eq)]
struct SortIndex {
    x:  uint,
    y:  uint
}

impl SortIndex {
    fn new(x:uint, y:uint) -> SortIndex {
        SortIndex{x:x, y:y}
    }
}

impl PartialOrd for SortIndex {
    fn lt(&self, other: &SortIndex) -> bool {
        if self.x + self.y == other.x + other.y {
            if (self.x + self.y) % 2 == 0 {
                self.x < other.x
            } else {
                self.y < other.y
            }
        } else {
            (self.x + self.y) < (other.x + other.y)
        }
    }
}

impl Ord for SortIndex {
    fn cmp(&self, other: &SortIndex) -> Ordering {
        if self < other { Less }
        else if self > other { Greater }
        else {Equal}
    }
}

fn zigzag(n:uint) -> Vec<Vec<uint>> {
    let mut l:Vec<SortIndex> = range(0u, n*n).map(|i| SortIndex::new(i%n,i/n)).collect();
    l.sort();

    let mut result : Vec<Vec<uint>> = Vec::from_elem(n, Vec::from_elem(n,0u));
    for t_ind in l.iter().zip(range(0,n*n)) {
        match t_ind {
            (&SortIndex{x,y},i) => *result.get_mut(y).get_mut(x) = i
        }
    }
    result
}

#[cfg(not(test))]
fn main() {
    println!("{}", zigzag(5));
}

#[test]
fn result() {
   let exp =vec![vec![0, 1, 5, 6, 14],
                 vec![2, 4, 7, 13, 15],
                 vec![3, 8, 12, 16, 21],
                 vec![9, 11, 17, 20, 22],
                 vec![10, 18, 19, 23, 24]];
    assert_eq!(zigzag(5), exp);
}<commit_msg>Used enumerate()<commit_after>// implements http://rosettacode.org/wiki/Zig-zag_matrix
// with the sorting indexes algorithm
// explained in the discussion page
// http://rosettacode.org/wiki/Talk:Zig-zag_matrix

#[deriving(Show, PartialEq, Eq)]
struct SortIndex {
    x:  uint,
    y:  uint
}

impl SortIndex {
    fn new(x:uint, y:uint) -> SortIndex {
        SortIndex{x:x, y:y}
    }
}

impl PartialOrd for SortIndex {
    fn lt(&self, other: &SortIndex) -> bool {
        if self.x + self.y == other.x + other.y {
            if (self.x + self.y) % 2 == 0 {
                self.x < other.x
            } else {
                self.y < other.y
            }
        } else {
            (self.x + self.y) < (other.x + other.y)
        }
    }
}

impl Ord for SortIndex {
    fn cmp(&self, other: &SortIndex) -> Ordering {
        if self < other { Less }
        else if self > other { Greater }
        else {Equal}
    }
}

fn zigzag(n:uint) -> Vec<Vec<uint>> {
    let mut l:Vec<SortIndex> = range(0u, n*n).map(|i| SortIndex::new(i%n,i/n)).collect();
    l.sort();

    let mut result : Vec<Vec<uint>> = Vec::from_elem(n, Vec::from_elem(n,0u));
    for t_ind in l.iter().enumerate() {
        let (i,&SortIndex{x,y}) = t_ind;
        *result.get_mut(y).get_mut(x) = i
    }
    result
}

#[cfg(not(test))]
fn main() {
    println!("{}", zigzag(5));
}

#[test]
fn result() {
   let exp =vec![vec![0,  1, 5, 6,14],
                 vec![2,  4, 7,13,15],
                 vec![3,  8,12,16,21],
                 vec![9, 11,17,20,22],
                 vec![10,18,19,23,24]];
    assert_eq!(zigzag(5), exp);
}
<|endoftext|>


<commit_before>use super::TestDatabase;
use crate::db::CratesIoData;
use crate::docbuilder::BuildResult;
use crate::utils::{Dependency, MetadataPackage, Target};
use failure::Error;

#[must_use = "FakeRelease does nothing until you call .create()"]
pub(crate) struct FakeRelease<'a> {
    db: &'a TestDatabase,
    package: MetadataPackage,
    build_result: BuildResult,
    /// name, content
    source_files: Vec<(&'a str, &'a [u8])>,
    /// name, content
    rustdoc_files: Vec<(&'a str, &'a [u8])>,
    doc_targets: Vec<String>,
    default_target: Option<&'a str>,
    cratesio_data: CratesIoData,
    has_docs: bool,
    has_examples: bool,
}

impl<'a> FakeRelease<'a> {
    pub(super) fn new(db: &'a TestDatabase) -> Self {
        FakeRelease {
            db,
            package: MetadataPackage {
                id: "fake-package-id".into(),
                name: "fake-package".into(),
                version: "1.0.0".into(),
                license: Some("MIT".into()),
                repository: Some("https://git.example.com".into()),
                homepage: Some("https://www.example.com".into()),
                description: Some("Fake package".into()),
                documentation: Some("https://docs.example.com".into()),
                dependencies: vec![Dependency {
                    name: "fake-dependency".into(),
                    req: "^1.0.0".into(),
                    kind: None,
                }],
                targets: vec![Target::dummy_lib("fake_package".into(), None)],
                readme: None,
                keywords: vec!["fake".into(), "package".into()],
                authors: vec!["Fake Person <fake@example.com>".into()],
            },
            build_result: BuildResult {
                rustc_version: "rustc 2.0.0-nightly (000000000 1970-01-01)".into(),
                docsrs_version: "docs.rs 1.0.0 (000000000 1970-01-01)".into(),
                build_log: "It works!".into(),
                successful: true,
            },
            source_files: Vec::new(),
            rustdoc_files: Vec::new(),
            doc_targets: Vec::new(),
            default_target: None,
            cratesio_data: CratesIoData {
                release_time: time::get_time(),
                yanked: false,
                downloads: 0,
                owners: Vec::new(),
            },
            has_docs: true,
            has_examples: false,
        }
    }

    pub(crate) fn name(mut self, new: &str) -> Self {
        self.package.name = new.into();
        self.package.id = format!("{}-id", new);
        self.package.targets[0].name = new.into();
        self
    }

    pub(crate) fn version(mut self, new: &str) -> Self {
        self.package.version = new.into();
        self
    }

    pub(crate) fn build_result_successful(mut self, new: bool) -> Self {
        self.build_result.successful = new;
        self
    }

    pub(crate) fn cratesio_data_yanked(mut self, new: bool) -> Self {
        self.cratesio_data.yanked = new;
        self
    }

    pub(crate) fn rustdoc_file(mut self, path: &'a str, data: &'a [u8]) -> Self {
        self.rustdoc_files.push((path, data));
        self
    }

    pub(crate) fn source_file(mut self, path: &'a str, data: &'a [u8]) -> Self {
        self.source_files.push((path, data));
        self
    }

    pub(crate) fn default_target(mut self, target: &'a str) -> Self {
        self = self.add_target(target);
        self.default_target = Some(target);
        self
    }

    pub(crate) fn add_target(mut self, target: &str) -> Self {
        self.doc_targets.push(target.into());
        self
    }

    pub(crate) fn binary(mut self, bin: bool) -> Self {
        self.has_docs = !bin;
        if bin {
            for target in self.package.targets.iter_mut() {
                target.crate_types = vec!["bin".into()];
            }
        }
        self
    }

    pub(crate) fn add_platform<S: Into<String>>(mut self, platform: S) -> Self {
        let platform = platform.into();
        let name = self.package.targets[0].name.clone();
        let target = Target::dummy_lib(name, Some(platform.clone()));
        self.package.targets.push(target);
        self.doc_targets.push(platform);
        self
    }

    pub(crate) fn create(self) -> Result<i32, Error> {
        use std::fs;
        use std::path::Path;

        let tempdir = tempdir::TempDir::new("docs.rs-fake")?;
        let package = self.package;
        let db = self.db;

        let upload_files = |prefix: &str, files: &[(&str, &[u8])], target: Option<&str>| {
            let mut path_prefix = tempdir.path().join(prefix);
            if let Some(target) = target {
                path_prefix.push(target);
            }
            fs::create_dir(&path_prefix)?;

            for (path, data) in files {
                // allow `src/main.rs`
                if let Some(parent) = Path::new(path).parent() {
                    fs::create_dir_all(path_prefix.join(parent))?;
                }
                let file = path_prefix.join(&path);
                log::debug!("writing file {}", file.display());
                fs::write(file, data)?;
            }

            let prefix = format!(
                "{}/{}/{}/{}",
                prefix,
                package.name,
                package.version,
                target.unwrap_or("")
            );
            log::debug!("adding directory {} from {}", prefix, path_prefix.display());
            crate::db::add_path_into_database(&db.conn(), &prefix, path_prefix)
        };

        let index = [&package.name, "index.html"].join("/");
        let mut rustdoc_files = self.rustdoc_files;
        if package.is_library() && !rustdoc_files.iter().any(|(path, _)| path == &index) {
            rustdoc_files.push((&index, b"default index content"));
        }
        for (source_path, data) in &self.source_files {
            if source_path.starts_with("src/") {
                let updated = ["src", &package.name, &source_path[4..]].join("/");
                rustdoc_files.push((Box::leak(Box::new(updated)), data));
            }
        }
        let rustdoc_meta = upload_files("rustdoc", &rustdoc_files, None)?;
        log::debug!("added rustdoc files {}", rustdoc_meta);
        let source_meta = upload_files("source", &self.source_files, None)?;
        log::debug!("added source files {}", source_meta);

        for target in &package.targets[1..] {
            let platform = target.src_path.as_ref().unwrap();
            upload_files("rustdoc", &rustdoc_files, Some(platform))?;
            log::debug!("added platform files for {}", platform);
        }

        let release_id = crate::db::add_package_into_database(
            &db.conn(),
            &package,
            tempdir.path(),
            &self.build_result,
            self.default_target.unwrap_or("x86_64-unknown-linux-gnu"),
            Some(source_meta),
            self.doc_targets,
            &self.cratesio_data,
            self.has_docs,
            self.has_examples,
        )?;
        crate::db::add_build_into_database(&db.conn(), release_id, &self.build_result)?;

        Ok(release_id)
    }
}

use crate::storage::{Blob, TIME_FMT};
use rusoto_s3::S3Client;
use rusoto_mock::{MockCredentialsProvider, MockRequestDispatcher};

pub(crate) struct FakeUpload {
    pub(crate) client: S3Client,
    pub(crate) bucket: &'static str,
}

impl FakeUpload {
    pub(crate) fn new(blob: Blob, bucket: &'static str) -> Self {

        let path = blob.path;
        let datetime = time::at_utc(blob.date_updated);
        let datestring = time::strftime(TIME_FMT, &datetime).unwrap();
        let dispatcher = MockRequestDispatcher::default()
            .with_body(&String::from_utf8(blob.content).unwrap())
            .with_header("Content-Type", &blob.mime)
            .with_header("Last-Modified", &datestring)
            .with_request_checker(move |req| {
                assert_eq!(req.path, format!("/{}/{}", bucket, path));
            });

        let client = S3Client::new_with(
            dispatcher,
            MockCredentialsProvider,
            Default::default()
        );
        Self { client, bucket }
    }
    pub(crate) fn not_found(path: &'static str, bucket: &'static str) -> Self {
        let dispatcher = MockRequestDispatcher::with_status(404)
            .with_request_checker(move |req| {
                assert_eq!(req.path, format!("/{}/{}", bucket, path));
            });
        let client = S3Client::new_with(
            dispatcher,
            MockCredentialsProvider,
            Default::default()
        );
        Self { client, bucket }
    }
}<commit_msg>Refactor out shared code<commit_after>use super::TestDatabase;
use crate::db::CratesIoData;
use crate::docbuilder::BuildResult;
use crate::utils::{Dependency, MetadataPackage, Target};
use failure::Error;

#[must_use = "FakeRelease does nothing until you call .create()"]
pub(crate) struct FakeRelease<'a> {
    db: &'a TestDatabase,
    package: MetadataPackage,
    build_result: BuildResult,
    /// name, content
    source_files: Vec<(&'a str, &'a [u8])>,
    /// name, content
    rustdoc_files: Vec<(&'a str, &'a [u8])>,
    doc_targets: Vec<String>,
    default_target: Option<&'a str>,
    cratesio_data: CratesIoData,
    has_docs: bool,
    has_examples: bool,
}

impl<'a> FakeRelease<'a> {
    pub(super) fn new(db: &'a TestDatabase) -> Self {
        FakeRelease {
            db,
            package: MetadataPackage {
                id: "fake-package-id".into(),
                name: "fake-package".into(),
                version: "1.0.0".into(),
                license: Some("MIT".into()),
                repository: Some("https://git.example.com".into()),
                homepage: Some("https://www.example.com".into()),
                description: Some("Fake package".into()),
                documentation: Some("https://docs.example.com".into()),
                dependencies: vec![Dependency {
                    name: "fake-dependency".into(),
                    req: "^1.0.0".into(),
                    kind: None,
                }],
                targets: vec![Target::dummy_lib("fake_package".into(), None)],
                readme: None,
                keywords: vec!["fake".into(), "package".into()],
                authors: vec!["Fake Person <fake@example.com>".into()],
            },
            build_result: BuildResult {
                rustc_version: "rustc 2.0.0-nightly (000000000 1970-01-01)".into(),
                docsrs_version: "docs.rs 1.0.0 (000000000 1970-01-01)".into(),
                build_log: "It works!".into(),
                successful: true,
            },
            source_files: Vec::new(),
            rustdoc_files: Vec::new(),
            doc_targets: Vec::new(),
            default_target: None,
            cratesio_data: CratesIoData {
                release_time: time::get_time(),
                yanked: false,
                downloads: 0,
                owners: Vec::new(),
            },
            has_docs: true,
            has_examples: false,
        }
    }

    pub(crate) fn name(mut self, new: &str) -> Self {
        self.package.name = new.into();
        self.package.id = format!("{}-id", new);
        self.package.targets[0].name = new.into();
        self
    }

    pub(crate) fn version(mut self, new: &str) -> Self {
        self.package.version = new.into();
        self
    }

    pub(crate) fn build_result_successful(mut self, new: bool) -> Self {
        self.build_result.successful = new;
        self
    }

    pub(crate) fn cratesio_data_yanked(mut self, new: bool) -> Self {
        self.cratesio_data.yanked = new;
        self
    }

    pub(crate) fn rustdoc_file(mut self, path: &'a str, data: &'a [u8]) -> Self {
        self.rustdoc_files.push((path, data));
        self
    }

    pub(crate) fn source_file(mut self, path: &'a str, data: &'a [u8]) -> Self {
        self.source_files.push((path, data));
        self
    }

    pub(crate) fn default_target(mut self, target: &'a str) -> Self {
        self = self.add_target(target);
        self.default_target = Some(target);
        self
    }

    pub(crate) fn add_target(mut self, target: &str) -> Self {
        self.doc_targets.push(target.into());
        self
    }

    pub(crate) fn binary(mut self, bin: bool) -> Self {
        self.has_docs = !bin;
        if bin {
            for target in self.package.targets.iter_mut() {
                target.crate_types = vec!["bin".into()];
            }
        }
        self
    }

    pub(crate) fn add_platform<S: Into<String>>(mut self, platform: S) -> Self {
        let platform = platform.into();
        let name = self.package.targets[0].name.clone();
        let target = Target::dummy_lib(name, Some(platform.clone()));
        self.package.targets.push(target);
        self.doc_targets.push(platform);
        self
    }

    pub(crate) fn create(self) -> Result<i32, Error> {
        use std::fs;
        use std::path::Path;

        let tempdir = tempdir::TempDir::new("docs.rs-fake")?;
        let package = self.package;
        let db = self.db;

        let upload_files = |prefix: &str, files: &[(&str, &[u8])], target: Option<&str>| {
            let mut path_prefix = tempdir.path().join(prefix);
            if let Some(target) = target {
                path_prefix.push(target);
            }
            fs::create_dir(&path_prefix)?;

            for (path, data) in files {
                // allow `src/main.rs`
                if let Some(parent) = Path::new(path).parent() {
                    fs::create_dir_all(path_prefix.join(parent))?;
                }
                let file = path_prefix.join(&path);
                log::debug!("writing file {}", file.display());
                fs::write(file, data)?;
            }

            let prefix = format!(
                "{}/{}/{}/{}",
                prefix,
                package.name,
                package.version,
                target.unwrap_or("")
            );
            log::debug!("adding directory {} from {}", prefix, path_prefix.display());
            crate::db::add_path_into_database(&db.conn(), &prefix, path_prefix)
        };

        let index = [&package.name, "index.html"].join("/");
        let mut rustdoc_files = self.rustdoc_files;
        if package.is_library() && !rustdoc_files.iter().any(|(path, _)| path == &index) {
            rustdoc_files.push((&index, b"default index content"));
        }
        for (source_path, data) in &self.source_files {
            if source_path.starts_with("src/") {
                let updated = ["src", &package.name, &source_path[4..]].join("/");
                rustdoc_files.push((Box::leak(Box::new(updated)), data));
            }
        }
        let rustdoc_meta = upload_files("rustdoc", &rustdoc_files, None)?;
        log::debug!("added rustdoc files {}", rustdoc_meta);
        let source_meta = upload_files("source", &self.source_files, None)?;
        log::debug!("added source files {}", source_meta);

        for target in &package.targets[1..] {
            let platform = target.src_path.as_ref().unwrap();
            upload_files("rustdoc", &rustdoc_files, Some(platform))?;
            log::debug!("added platform files for {}", platform);
        }

        let release_id = crate::db::add_package_into_database(
            &db.conn(),
            &package,
            tempdir.path(),
            &self.build_result,
            self.default_target.unwrap_or("x86_64-unknown-linux-gnu"),
            Some(source_meta),
            self.doc_targets,
            &self.cratesio_data,
            self.has_docs,
            self.has_examples,
        )?;
        crate::db::add_build_into_database(&db.conn(), release_id, &self.build_result)?;

        Ok(release_id)
    }
}

use crate::storage::{Blob, TIME_FMT};
use rusoto_s3::S3Client;
use rusoto_mock::{MockCredentialsProvider, MockRequestDispatcher};

pub(crate) struct FakeUpload {
    pub(crate) client: S3Client,
    pub(crate) bucket: &'static str,
}

impl FakeUpload {
    pub(crate) fn new(blob: Blob, bucket: &'static str) -> Self {
        let datetime = time::at_utc(blob.date_updated);
        let datestring = time::strftime(TIME_FMT, &datetime).unwrap();
        let dispatcher = MockRequestDispatcher::default()
            .with_body(&String::from_utf8(blob.content).unwrap())
            .with_header("Content-Type", &blob.mime)
            .with_header("Last-Modified", &datestring);
        Self::with_dispatcher(blob.path, bucket, dispatcher)
    }

    pub(crate) fn not_found(path: &'static str, bucket: &'static str) -> Self {
        Self::with_dispatcher(path, bucket, MockRequestDispatcher::with_status(404))
    }

    fn with_dispatcher<S>(path: S, bucket: &'static str, dispatcher: MockRequestDispatcher) -> Self
    where S: AsRef<str> + std::fmt::Display + Send + Sync + 'static {
        let dispatcher = dispatcher.with_request_checker(move |req| {
            assert_eq!(req.path, format!("/{}/{}", bucket, path));
        });
        let client = S3Client::new_with(
            dispatcher,
            MockCredentialsProvider,
            Default::default()
        );
        Self { client, bucket }
    }
}
<|endoftext|>


<commit_before>//! Exposes the `Iron` type, the main entrance point of the
//! `Iron` library.

use std::io::net::ip::{SocketAddr, IpAddr};

use http::server::{Server, Config};
use http::server::request::{Star, AbsoluteUri, AbsolutePath, Authority};

use super::middleware::Middleware;

use super::furnace::Furnace;
use super::furnace::stackfurnace::StackFurnace;

use super::response::Response;
use super::request::Request;

pub type ServerT = Iron<StackFurnace>;

/// The primary entrance point to `Iron`, a `struct` to instantiate a new server.
///
/// The server can be made with a specific `Furnace` (using `from_furnace`)
/// or with a new `Furnace` (using `new`). `Iron` is used to manage the server
/// processes:
/// `Iron.smelt` is used to add new `Ingot`s, and
/// `Iron.listen` is used to kick off a server process.
///
/// `Iron` contains the `Furnace` which holds the `Ingot`s necessary to run a server.
/// `Iron` is the main interface to adding `Ingot`s, and has `Furnace` as a
/// public field (for the sake of extensibility).
pub struct Iron<F> {
    /// The exposed internal field for storing `Furnace`.
    ///
    /// This is exposed for the sake of extensibility. It can be used to set
    /// furnace to implement your server's middleware stack with custom behavior.
    /// Most users will not need to touch `furnace`. This should only be used if you
    /// need custom handling of `Ingot`s. Normally, the default `IronFurnace` is
    /// sufficient.
    pub furnace: F,
    ip: Option<IpAddr>,
    port: Option<u16>
}

impl<F: Clone> Clone for Iron<F> {
    fn clone(&self) -> Iron<F> {
        Iron {
            furnace: self.furnace.clone(),
            ip: self.ip.clone(),
            port: self.port
        }
    }
}

impl<F: Furnace> Iron<F> {
    /// `smelt` a new `Ingot`.
    ///
    /// This adds an `Ingot` to the `Iron`'s `furnace`, so that any requests
    /// are passed through those `Ingot`s.
    ///
    /// `Iron.smelt` delegates to `iron.furnace.smelt`, so that any `Ingot`
    /// added is added to the `Iron` instance's `furnace`.
    pub fn smelt<M: Middleware>(&mut self, middleware: M) {
        self.furnace.smelt(middleware);
    }

    /// Kick off the server process.
    ///
    /// Call this once to begin listening for requests on the server.
    /// This is a blocking operation, and is the final op that should be called
    /// on the `Iron` instance. Once `listen` is called, requests will be
    /// handled as defined through the `Iron`'s `furnace`'s `Ingot`s.
    pub fn listen(mut self, ip: IpAddr, port: u16) {
        self.ip = Some(ip);
        self.port = Some(port);
        self.serve_forever();
    }

    /// Instantiate a new instance of `Iron`.
    ///
    /// This will create a new `Iron`, the base unit of the server.
    /// This creates an `Iron` with a default `furnace`, the `IronFurnace`.
    ///
    /// Custom furnaces can be used with `from_furnace`, instead of `new`.
    #[inline]
    pub fn new() -> Iron<F> {
        Iron {
            furnace: Furnace::new(),
            ip: None,
            port: None
        }
    }

    /// Instantiate a new instance of `Iron` from an existing `Furnace`.
    ///
    /// This will create a new `Iron` from a give `Furnace`.
    ///
    /// This `Furnace` *may already have `Ingot`s in it*. An empty default
    /// `Furnace` can be created more easily using `new`.
    ///
    /// The `Furnace` can also be configured to handle `Ingot`s differently than
    /// `IronFurnace`. For example, this can be used to implement a `Furnace`
    /// that logs debug messages as it serves requests.
    ///
    /// Most users will not need to touch `from_furnace`. This should only be
    /// used if you need custom handling of `Ingot`s. Normally, the default
    /// `IronFurnace` is sufficient.
    pub fn from_furnace<F>(furnace: F) -> Iron<F> {
        Iron {
            furnace: furnace,
            ip: None,
            port: None
        }
    }
}

/// This is unused but required for internal functionality.
///
/// This `impl` allows `Iron` to be used as a `Server` by
/// [rust-http]('https://github.com/chris-morgan/rust-http').
/// This is not used by users of this library.
impl<F: Furnace> Server for Iron<F> {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr {
            ip: self.ip.unwrap(),
            port: self.port.unwrap()
        } }
    }

    fn handle_request(&self, req: &Request, res: &mut Response) {
        let mut furnace = self.furnace.clone();
        furnace.forge(&mut copy_request(req), res, None);
    }
}

// Makes up for no Clone impl on Request objects.
fn copy_request(req: &Request) -> Request {
    Request {
        remote_addr: req.remote_addr,
        headers: req.headers.clone(),
        body: req.body.clone(),
        method: req.method.clone(),
        request_uri: match req.request_uri {
            Star => Star,
            AbsoluteUri(ref u) => AbsoluteUri(u.clone()),
            AbsolutePath(ref p) => AbsolutePath(p.clone()),
            Authority(ref s) => Authority(s.clone())
        },
        close_connection: req.close_connection,
        version: (1, 1)
    }
}

<commit_msg>(doc) Updated Iron for Middleware.<commit_after>//! Exposes the `Iron` type, the main entrance point of the
//! `Iron` library.

use std::io::net::ip::{SocketAddr, IpAddr};

use http::server::{Server, Config};
use http::server::request::{Star, AbsoluteUri, AbsolutePath, Authority};

use super::middleware::Middleware;

use super::furnace::Furnace;
use super::furnace::stackfurnace::StackFurnace;

use super::response::Response;
use super::request::Request;

pub type ServerT = Iron<StackFurnace>;

/// The primary entrance point to `Iron`, a `struct` to instantiate a new server.
///
/// The server can be made with a specific `Furnace` (using `from_furnace`)
/// or with a new `Furnace` (using `new`). `Iron` is used to manage the server
/// processes:
/// `Iron.smelt` is used to add new `Middleware`, and
/// `Iron.listen` is used to kick off a server process.
///
/// `Iron` contains the `Furnace` which holds the `Middleware` necessary to run a server.
/// `Iron` is the main interface to adding `Middleware`, and has `Furnace` as a
/// public field (for the sake of extensibility).
pub struct Iron<F> {
    /// This is exposed for the sake of extensibility. It can be used to set
    /// furnace to implement your server's middleware stack with custom behavior.
    /// Most users will not need to touch `furnace`. This should only be used if you
    /// need custom handling of `Middleware`. Normally, the default `StackFurnace` is
    /// sufficient.
    pub furnace: F,
    ip: Option<IpAddr>,
    port: Option<u16>
}

impl<F: Clone> Clone for Iron<F> {
    fn clone(&self) -> Iron<F> {
        Iron {
            furnace: self.furnace.clone(),
            ip: self.ip.clone(),
            port: self.port
        }
    }
}

impl<F: Furnace> Iron<F> {
    /// `smelt` a new `Middleware`.
    ///
    /// Adds `Middleware` to the `Iron's` `furnace`, so that any requests
    /// are passed through those `Middleware`.
    ///
    /// `Iron.smelt` delegates to `Iron.furnace.smelt`, so that any `Middleware`
    /// added is added to the `Iron` instance's `furnace`.
    pub fn smelt<M: Middleware>(&mut self, middleware: M) {
        self.furnace.smelt(middleware);
    }

    /// Kick off the server process.
    ///
    /// Call this once to begin listening for requests on the server.
    /// This is a blocking operation, and is the final op that should be called
    /// on the `Iron` instance. Once `listen` is called, requests will be
    /// handled as defined through the `Iron's` `furnace's` `Middleware`.
    pub fn listen(mut self, ip: IpAddr, port: u16) {
        self.ip = Some(ip);
        self.port = Some(port);
        self.serve_forever();
    }

    /// Instantiate a new instance of `Iron`.
    ///
    /// This will create a new `Iron`, the base unit of the server.
    /// This creates an `Iron` with a default `furnace`, the `StackFurnace`.
    ///
    /// Custom furnaces can be used with `from_furnace`, instead of `new`.
    #[inline]
    pub fn new() -> Iron<F> {
        Iron {
            furnace: Furnace::new(),
            ip: None,
            port: None
        }
    }

    /// Instantiate a new instance of `Iron` from an existing `Furnace`.
    ///
    /// This will create a new `Iron` from a give `Furnace`.
    ///
    /// This `Furnace` *may already have `Middleware` in it*. An empty default
    /// `Furnace` can be created more easily using `new`.
    ///
    /// The `Furnace` can also be configured to handle `Middleware` differently than
    /// `StackFurnace`. For example, this can be used to implement a `Furnace`
    /// that logs debug messages as it serves requests.
    ///
    /// Most users will not need to touch `from_furnace`. This should only be
    /// used if you need custom handling of `Middleware`.
    pub fn from_furnace<F>(furnace: F) -> Iron<F> {
        Iron {
            furnace: furnace,
            ip: None,
            port: None
        }
    }
}

/// Unused, but required for internal functionality.
///
/// This `impl` allows `Iron` to be used as a `Server` by
/// [rust-http]('https://github.com/chris-morgan/rust-http').
/// This is not used by users of this library.
impl<F: Furnace> Server for Iron<F> {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr {
            ip: self.ip.unwrap(),
            port: self.port.unwrap()
        } }
    }

    fn handle_request(&self, req: &Request, res: &mut Response) {
        let mut furnace = self.furnace.clone();
        furnace.forge(&mut copy_request(req), res, None);
    }
}

// Makes up for no Clone impl on Request objects.
fn copy_request(req: &Request) -> Request {
    Request {
        remote_addr: req.remote_addr,
        headers: req.headers.clone(),
        body: req.body.clone(),
        method: req.method.clone(),
        request_uri: match req.request_uri {
            Star => Star,
            AbsoluteUri(ref u) => AbsoluteUri(u.clone()),
            AbsolutePath(ref p) => AbsolutePath(p.clone()),
            Authority(ref s) => Authority(s.clone())
        },
        close_connection: req.close_connection,
        version: (1, 1)
    }
}

<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;

use filetime::{self, FileTime};
use lazy_static::lazy_static;

static CARGO_INTEGRATION_TEST_DIR: &'static str = "cit";

lazy_static! {
    static ref GLOBAL_ROOT: PathBuf = {
        let mut path = t!(env::current_exe());
        path.pop(); // chop off exe name
        path.pop(); // chop off 'debug'

        // If `cargo test` is run manually then our path looks like
        // `target/debug/foo`, in which case our `path` is already pointing at
        // `target`. If, however, `cargo test --target $target` is used then the
        // output is `target/$target/debug/foo`, so our path is pointing at
        // `target/$target`. Here we conditionally pop the `$target` name.
        if path.file_name().and_then(|s| s.to_str()) != Some("target") {
            path.pop();
        }

        path.push(CARGO_INTEGRATION_TEST_DIR);

        path.rm_rf();
        path.mkdir_p();

        path
    };

    static ref TEST_ROOTS: Mutex<HashMap<String, PathBuf>> = Default::default();
}

// We need to give each test a unique id. The test name could serve this
// purpose, but the `test` crate doesn't have a way to obtain the current test
// name.[*] Instead, we used the `cargo-test-macro` crate to automatically
// insert an init function for each test that sets the test name in a thread
// local variable.
//
// [*] It does set the thread name, but only when running concurrently. If not
// running concurrently, all tests are run on the main thread.
thread_local! {
    static TEST_ID: RefCell<Option<usize>> = RefCell::new(None);
}

pub struct TestIdGuard {
    _private: (),
}

pub fn init_root() -> TestIdGuard {
    static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

    let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
    TEST_ID.with(|n| *n.borrow_mut() = Some(id));

    let guard = TestIdGuard { _private: () };

    root().mkdir_p();

    guard
}

impl Drop for TestIdGuard {
    fn drop(&mut self) {
        TEST_ID.with(|n| *n.borrow_mut() = None);
    }
}

pub fn root() -> PathBuf {
    let id = TEST_ID.with(|n| {
        n.borrow().expect(
            "Tests must use the `#[cargo_test]` attribute in \
             order to be able to use the crate root.",
        )
    });
    GLOBAL_ROOT.join(&format!("t{}", id))
}

pub fn home() -> PathBuf {
    let mut path = root();
    path.push("home");
    path.mkdir_p();
    path
}

pub trait CargoPathExt {
    fn rm_rf(&self);
    fn mkdir_p(&self);

    fn move_into_the_past(&self) {
        self.move_in_time(|sec, nsec| (sec - 3600, nsec))
    }

    fn move_into_the_future(&self) {
        self.move_in_time(|sec, nsec| (sec + 3600, nsec))
    }

    fn move_in_time<F>(&self, travel_amount: F)
    where
        F: Fn(i64, u32) -> (i64, u32);

    fn is_symlink(&self) -> bool;
}

impl CargoPathExt for Path {
    /* Technically there is a potential race condition, but we don't
     * care all that much for our tests
     */
    fn rm_rf(&self) {
        if !self.exists() {
            return;
        }

        for file in t!(fs::read_dir(self)) {
            let file = t!(file);
            if file.file_type().map(|m| m.is_dir()).unwrap_or(false) {
                file.path().rm_rf();
            } else {
                // On windows we can't remove a readonly file, and git will
                // often clone files as readonly. As a result, we have some
                // special logic to remove readonly files on windows.
                do_op(&file.path(), "remove file", |p| fs::remove_file(p));
            }
        }
        do_op(self, "remove dir", |p| fs::remove_dir(p));
    }

    fn mkdir_p(&self) {
        fs::create_dir_all(self)
            .unwrap_or_else(|e| panic!("failed to mkdir_p {}: {}", self.display(), e))
    }

    fn move_in_time<F>(&self, travel_amount: F)
    where
        F: Fn(i64, u32) -> ((i64, u32)),
    {
        if self.is_file() {
            time_travel(self, &travel_amount);
        } else {
            recurse(self, &self.join("target"), &travel_amount);
        }

        fn recurse<F>(p: &Path, bad: &Path, travel_amount: &F)
        where
            F: Fn(i64, u32) -> ((i64, u32)),
        {
            if p.is_file() {
                time_travel(p, travel_amount)
            } else if !p.starts_with(bad) {
                for f in t!(fs::read_dir(p)) {
                    let f = t!(f).path();
                    recurse(&f, bad, travel_amount);
                }
            }
        }

        fn time_travel<F>(path: &Path, travel_amount: &F)
        where
            F: Fn(i64, u32) -> ((i64, u32)),
        {
            let stat = t!(path.metadata());

            let mtime = FileTime::from_last_modification_time(&stat);

            let (sec, nsec) = travel_amount(mtime.unix_seconds(), mtime.nanoseconds());
            let newtime = FileTime::from_unix_time(sec, nsec);

            // Sadly change_file_times has a failure mode where a readonly file
            // cannot have its times changed on windows.
            do_op(path, "set file times", |path| {
                filetime::set_file_times(path, newtime, newtime)
            });
        }
    }

    fn is_symlink(&self) -> bool {
        fs::symlink_metadata(self)
            .map(|m| m.file_type().is_symlink())
            .unwrap_or(false)
    }
}

fn do_op<F>(path: &Path, desc: &str, mut f: F)
where
    F: FnMut(&Path) -> io::Result<()>,
{
    match f(path) {
        Ok(()) => {}
        Err(ref e) if e.kind() == ErrorKind::PermissionDenied => {
            let mut p = t!(path.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(path, p));

            // Unix also requires the parent to not be readonly for example when
            // removing files
            let parent = path.parent().unwrap();
            let mut p = t!(parent.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(parent, p));

            f(path).unwrap_or_else(|e| {
                panic!("failed to {} {}: {}", desc, path.display(), e);
            })
        }
        Err(e) => {
            panic!("failed to {} {}: {}", desc, path.display(), e);
        }
    }
}
<commit_msg>Auto merge of #7042 - ehuss:no-global-rm-rf, r=alexcrichton<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;

use filetime::{self, FileTime};
use lazy_static::lazy_static;

static CARGO_INTEGRATION_TEST_DIR: &'static str = "cit";

lazy_static! {
    static ref GLOBAL_ROOT: PathBuf = {
        let mut path = t!(env::current_exe());
        path.pop(); // chop off exe name
        path.pop(); // chop off 'debug'

        // If `cargo test` is run manually then our path looks like
        // `target/debug/foo`, in which case our `path` is already pointing at
        // `target`. If, however, `cargo test --target $target` is used then the
        // output is `target/$target/debug/foo`, so our path is pointing at
        // `target/$target`. Here we conditionally pop the `$target` name.
        if path.file_name().and_then(|s| s.to_str()) != Some("target") {
            path.pop();
        }

        path.push(CARGO_INTEGRATION_TEST_DIR);
        path.mkdir_p();
        path
    };

    static ref TEST_ROOTS: Mutex<HashMap<String, PathBuf>> = Default::default();
}

// We need to give each test a unique id. The test name could serve this
// purpose, but the `test` crate doesn't have a way to obtain the current test
// name.[*] Instead, we used the `cargo-test-macro` crate to automatically
// insert an init function for each test that sets the test name in a thread
// local variable.
//
// [*] It does set the thread name, but only when running concurrently. If not
// running concurrently, all tests are run on the main thread.
thread_local! {
    static TEST_ID: RefCell<Option<usize>> = RefCell::new(None);
}

pub struct TestIdGuard {
    _private: (),
}

pub fn init_root() -> TestIdGuard {
    static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

    let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
    TEST_ID.with(|n| *n.borrow_mut() = Some(id));

    let guard = TestIdGuard { _private: () };

    let r = root();
    r.rm_rf();
    r.mkdir_p();

    guard
}

impl Drop for TestIdGuard {
    fn drop(&mut self) {
        TEST_ID.with(|n| *n.borrow_mut() = None);
    }
}

pub fn root() -> PathBuf {
    let id = TEST_ID.with(|n| {
        n.borrow().expect(
            "Tests must use the `#[cargo_test]` attribute in \
             order to be able to use the crate root.",
        )
    });
    GLOBAL_ROOT.join(&format!("t{}", id))
}

pub fn home() -> PathBuf {
    let mut path = root();
    path.push("home");
    path.mkdir_p();
    path
}

pub trait CargoPathExt {
    fn rm_rf(&self);
    fn mkdir_p(&self);

    fn move_into_the_past(&self) {
        self.move_in_time(|sec, nsec| (sec - 3600, nsec))
    }

    fn move_into_the_future(&self) {
        self.move_in_time(|sec, nsec| (sec + 3600, nsec))
    }

    fn move_in_time<F>(&self, travel_amount: F)
    where
        F: Fn(i64, u32) -> (i64, u32);

    fn is_symlink(&self) -> bool;
}

impl CargoPathExt for Path {
    /* Technically there is a potential race condition, but we don't
     * care all that much for our tests
     */
    fn rm_rf(&self) {
        if !self.exists() {
            return;
        }

        for file in t!(fs::read_dir(self)) {
            let file = t!(file);
            if file.file_type().map(|m| m.is_dir()).unwrap_or(false) {
                file.path().rm_rf();
            } else {
                // On windows we can't remove a readonly file, and git will
                // often clone files as readonly. As a result, we have some
                // special logic to remove readonly files on windows.
                do_op(&file.path(), "remove file", |p| fs::remove_file(p));
            }
        }
        do_op(self, "remove dir", |p| fs::remove_dir(p));
    }

    fn mkdir_p(&self) {
        fs::create_dir_all(self)
            .unwrap_or_else(|e| panic!("failed to mkdir_p {}: {}", self.display(), e))
    }

    fn move_in_time<F>(&self, travel_amount: F)
    where
        F: Fn(i64, u32) -> ((i64, u32)),
    {
        if self.is_file() {
            time_travel(self, &travel_amount);
        } else {
            recurse(self, &self.join("target"), &travel_amount);
        }

        fn recurse<F>(p: &Path, bad: &Path, travel_amount: &F)
        where
            F: Fn(i64, u32) -> ((i64, u32)),
        {
            if p.is_file() {
                time_travel(p, travel_amount)
            } else if !p.starts_with(bad) {
                for f in t!(fs::read_dir(p)) {
                    let f = t!(f).path();
                    recurse(&f, bad, travel_amount);
                }
            }
        }

        fn time_travel<F>(path: &Path, travel_amount: &F)
        where
            F: Fn(i64, u32) -> ((i64, u32)),
        {
            let stat = t!(path.metadata());

            let mtime = FileTime::from_last_modification_time(&stat);

            let (sec, nsec) = travel_amount(mtime.unix_seconds(), mtime.nanoseconds());
            let newtime = FileTime::from_unix_time(sec, nsec);

            // Sadly change_file_times has a failure mode where a readonly file
            // cannot have its times changed on windows.
            do_op(path, "set file times", |path| {
                filetime::set_file_times(path, newtime, newtime)
            });
        }
    }

    fn is_symlink(&self) -> bool {
        fs::symlink_metadata(self)
            .map(|m| m.file_type().is_symlink())
            .unwrap_or(false)
    }
}

fn do_op<F>(path: &Path, desc: &str, mut f: F)
where
    F: FnMut(&Path) -> io::Result<()>,
{
    match f(path) {
        Ok(()) => {}
        Err(ref e) if e.kind() == ErrorKind::PermissionDenied => {
            let mut p = t!(path.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(path, p));

            // Unix also requires the parent to not be readonly for example when
            // removing files
            let parent = path.parent().unwrap();
            let mut p = t!(parent.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(parent, p));

            f(path).unwrap_or_else(|e| {
                panic!("failed to {} {}: {}", desc, path.display(), e);
            })
        }
        Err(e) => {
            panic!("failed to {} {}: {}", desc, path.display(), e);
        }
    }
}
<|endoftext|>


<commit_before>// Support code for rustc's built in test runner generator. Currently,
// none of this is meant for users. It is intended to support the
// simplest interface possible for representing and running tests
// while providing a base that other test frameworks may build off of.

import sort = sort::ivector;
import generic_os::getenv;

export test_name;
export test_fn;
export test_desc;
export test_main;
export test_result;
export test_opts;
export tr_ok;
export tr_failed;
export tr_ignored;
export run_tests_console;
export run_tests_console_;
export run_test;
export filter_tests;
export parse_opts;
export test_to_task;
export default_test_to_task;
export configure_test_task;

native "rust" mod rustrt {
    fn hack_allow_leaks();
    fn sched_threads() -> uint;
}

// The name of a test. By convention this follows the rules for rust
// paths, i.e it should be a series of identifiers seperated by double
// colons. This way if some test runner wants to arrange the tests
// heirarchically it may.
type test_name = str;

// A function that runs a test. If the function returns successfully,
// the test succeeds; if the function fails then the test fails. We
// may need to come up with a more clever definition of test in order
// to support isolation of tests into tasks.
type test_fn = fn() ;

// The definition of a single test. A test runner will run a list of
// these.
type test_desc = {name: test_name, fn: test_fn, ignore: bool};

// The default console test runner. It accepts the command line
// arguments and a vector of test_descs (generated at compile time).
fn test_main(args: &vec[str], tests: &test_desc[]) {
    let ivec_args =
        { let iargs = ~[]; for arg: str  in args { iargs += ~[arg] } iargs };
    check (ivec::is_not_empty(ivec_args));
    let opts =
        alt parse_opts(ivec_args) {
          either::left(o) { o }
          either::right(m) { fail m }
        };
    if !run_tests_console(opts, tests) { fail "Some tests failed"; }
}

type test_opts = {filter: option::t[str], run_ignored: bool};

type opt_res = either::t[test_opts, str];

// Parses command line arguments into test options
fn parse_opts(args: &str[]) : ivec::is_not_empty(args) -> opt_res {

    // FIXME (#649): Shouldn't have to check here
    check (ivec::is_not_empty(args));
    let args_ = ivec::tail(args);
    let opts = ~[getopts::optflag("ignored")];
    let match =
        alt getopts::getopts_ivec(args_, opts) {
          getopts::success(m) { m }
          getopts::failure(f) { ret either::right(getopts::fail_str(f)) }
        };

    let filter =
        if vec::len(match.free) > 0u {
            option::some(match.free.(0))
        } else { option::none };

    let run_ignored = getopts::opt_present(match, "ignored");

    let test_opts = {filter: filter, run_ignored: run_ignored};

    ret either::left(test_opts);
}

tag test_result { tr_ok; tr_failed; tr_ignored; }

// To get isolation and concurrency tests have to be run in their own tasks.
// In cases where test functions and closures it is not ok to just dump them
// into a task and run them, so this transformation gives the caller a chance
// to create the test task.
type test_to_task = fn(&fn()) -> task ;

// A simple console test runner
fn run_tests_console(opts: &test_opts, tests: &test_desc[]) -> bool {
    run_tests_console_(opts, tests, default_test_to_task)
}

fn run_tests_console_(opts: &test_opts, tests: &test_desc[],
                      to_task: &test_to_task) -> bool {

    type test_state = @{
        out: io::writer,
        use_color: bool,
        mutable total: uint,
        mutable passed: uint,
        mutable failed: uint,
        mutable ignored: uint,
        mutable failures: test_desc[]
    };

    fn callback(event: testevent, st: test_state) {
        alt event {
          te_filtered(filtered_tests) {
            st.total = ivec::len(filtered_tests);
            st.out.write_line(#fmt("\nrunning %u tests", st.total));
          }
          te_result(test, result) {
            st.out.write_str(#fmt("test %s ... ", test.name));
            alt result {
              tr_ok. {
                st.passed += 1u;
                write_ok(st.out, st.use_color);
                st.out.write_line("");
              }
              tr_failed. {
                st.failed += 1u;
                write_failed(st.out, st.use_color);
                st.out.write_line("");
                st.failures += ~[test];
              }
              tr_ignored. {
                st.ignored += 1u;
                write_ignored(st.out, st.use_color);
                st.out.write_line("");
              }
            }
          }
        }
    }

    let st = @{
        out: io::stdout(),
        use_color: use_color(),
        mutable total: 0u,
        mutable passed: 0u,
        mutable failed: 0u,
        mutable ignored: 0u,
        mutable failures: ~[]
    };

    run_tests(opts, tests, to_task,
              bind callback(_, st));

    assert st.passed + st.failed + st.ignored == st.total;
    let success = st.failed == 0u;

    if !success {
        st.out.write_line("\nfailures:");
        for test: test_desc in st.failures {
            let testname = test.name; // Satisfy alias analysis
            st.out.write_line(#fmt("    %s", testname));
        }
    }

    st.out.write_str(#fmt("\nresult: "));
    if success {
        write_ok(st.out, st.use_color);
    } else { write_failed(st.out, st.use_color); }
    st.out.write_str(#fmt(". %u passed; %u failed; %u ignored\n\n",
                       st.passed, st.failed, st.ignored));

    ret success;

    fn write_ok(out: &io::writer, use_color: bool) {
        write_pretty(out, "ok", term::color_green, use_color);
    }

    fn write_failed(out: &io::writer, use_color: bool) {
        write_pretty(out, "FAILED", term::color_red, use_color);
    }

    fn write_ignored(out: &io::writer, use_color: bool) {
        write_pretty(out, "ignored", term::color_yellow, use_color);
    }

    fn write_pretty(out: &io::writer, word: &str, color: u8,
                    use_color: bool) {
        if use_color && term::color_supported() {
            term::fg(out.get_buf_writer(), color);
        }
        out.write_str(word);
        if use_color && term::color_supported() {
            term::reset(out.get_buf_writer());
        }
    }
}

fn use_color() -> bool {
    ret get_concurrency() == 1u;
}

tag testevent {
    te_filtered(test_desc[]);
    te_result(test_desc, test_result);
}

fn run_tests(opts: &test_opts, tests: &test_desc[],
             to_task: &test_to_task, callback: fn(testevent)) {

    let filtered_tests = filter_tests(opts, tests);

    callback(te_filtered(filtered_tests));

    // It's tempting to just spawn all the tests at once but that doesn't
    // provide a great user experience because you might sit waiting for the
    // result of a particular test for an unusually long amount of time.
    let concurrency = get_concurrency();
    log #fmt("using %u test tasks", concurrency);
    let total = ivec::len(filtered_tests);
    let run_idx = 0u;
    let wait_idx = 0u;
    let futures = ~[];

    while wait_idx < total {
        while ivec::len(futures) < concurrency && run_idx < total {
            futures += ~[run_test(filtered_tests.(run_idx), to_task)];
            run_idx += 1u;
        }

        let future = futures.(0);
        let result = future.wait();
        callback(te_result(future.test, result));
        futures = ivec::slice(futures, 1u, ivec::len(futures));
        wait_idx += 1u;
    }
}

fn get_concurrency() -> uint { rustrt::sched_threads() }

fn filter_tests(opts: &test_opts, tests: &test_desc[]) -> test_desc[] {
    let filtered = tests;

    // Remove tests that don't match the test filter
    filtered =
        if option::is_none(opts.filter) {
            filtered
        } else {
            let filter_str =
                alt opts.filter {
                  option::some(f) { f }
                  option::none. { "" }
                };

            let filter =
                bind fn (test: &test_desc, filter_str: str) ->
                        option::t[test_desc] {
                         if str::find(test.name, filter_str) >= 0 {
                             ret option::some(test);
                         } else { ret option::none; }
                     }(_, filter_str);

            ivec::filter_map(filter, filtered)
        };

    // Maybe pull out the ignored test and unignore them
    filtered =
        if !opts.run_ignored {
            filtered
        } else {
            let filter =
                fn (test: &test_desc) -> option::t[test_desc] {
                    if test.ignore {
                        ret option::some({name: test.name,
                                          fn: test.fn,
                                          ignore: false});
                    } else { ret option::none; }
                };

            ivec::filter_map(filter, filtered)
        };

    // Sort the tests alphabetically
    filtered =
        {
            fn lteq(t1: &test_desc, t2: &test_desc) -> bool {
                str::lteq(t1.name, t2.name)
            }
            sort::merge_sort(lteq, filtered)
        };

    ret filtered;
}

type test_future =
    {test: test_desc, fnref: @fn() , wait: fn() -> test_result };

fn run_test(test: &test_desc, to_task: &test_to_task) -> test_future {
    // FIXME: Because of the unsafe way we're passing the test function
    // to the test task, we need to make sure we keep a reference to that
    // function around for longer than the lifetime of the task. To that end
    // we keep the function boxed in the test future.
    let fnref = @test.fn;
    if !test.ignore {
        let test_task = to_task(*fnref);
        ret {test: test,
             fnref: fnref,
             wait:
                 bind fn (test_task: &task) -> test_result {
                          alt task::join(test_task) {
                            task::tr_success. { tr_ok }
                            task::tr_failure. { tr_failed }
                          }
                      }(test_task)};
    } else {
        ret {test: test,
             fnref: fnref,
             wait: fn () -> test_result { tr_ignored }};
    }
}

// We need to run our tests in another task in order to trap test failures.
// But, at least currently, functions can't be used as spawn arguments so
// we've got to treat our test functions as unsafe pointers.  This function
// only works with functions that don't contain closures.
fn default_test_to_task(f: &fn()) -> task {
    fn run_task(fptr: *mutable fn() ) {
        configure_test_task();
        // Run the test
        (*fptr)()
    }
    let fptr = ptr::addr_of(f);
    ret spawn run_task(fptr);
}

// Call from within a test task to make sure it's set up correctly
fn configure_test_task() {
    // If this task fails we don't want that failure to propagate to the
    // test runner or else we couldn't keep running tests
    task::unsupervise();

    // FIXME (236): Hack supreme - unwinding doesn't work yet so if this
    // task fails memory will not be freed correctly. This turns off the
    // sanity checks in the runtime's memory region for the task, so that
    // the test runner can continue.
    rustrt::hack_allow_leaks();
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Use color to report the final test result, even when running in parallel<commit_after>// Support code for rustc's built in test runner generator. Currently,
// none of this is meant for users. It is intended to support the
// simplest interface possible for representing and running tests
// while providing a base that other test frameworks may build off of.

import sort = sort::ivector;
import generic_os::getenv;

export test_name;
export test_fn;
export test_desc;
export test_main;
export test_result;
export test_opts;
export tr_ok;
export tr_failed;
export tr_ignored;
export run_tests_console;
export run_tests_console_;
export run_test;
export filter_tests;
export parse_opts;
export test_to_task;
export default_test_to_task;
export configure_test_task;

native "rust" mod rustrt {
    fn hack_allow_leaks();
    fn sched_threads() -> uint;
}

// The name of a test. By convention this follows the rules for rust
// paths, i.e it should be a series of identifiers seperated by double
// colons. This way if some test runner wants to arrange the tests
// heirarchically it may.
type test_name = str;

// A function that runs a test. If the function returns successfully,
// the test succeeds; if the function fails then the test fails. We
// may need to come up with a more clever definition of test in order
// to support isolation of tests into tasks.
type test_fn = fn() ;

// The definition of a single test. A test runner will run a list of
// these.
type test_desc = {name: test_name, fn: test_fn, ignore: bool};

// The default console test runner. It accepts the command line
// arguments and a vector of test_descs (generated at compile time).
fn test_main(args: &vec[str], tests: &test_desc[]) {
    let ivec_args =
        { let iargs = ~[]; for arg: str  in args { iargs += ~[arg] } iargs };
    check (ivec::is_not_empty(ivec_args));
    let opts =
        alt parse_opts(ivec_args) {
          either::left(o) { o }
          either::right(m) { fail m }
        };
    if !run_tests_console(opts, tests) { fail "Some tests failed"; }
}

type test_opts = {filter: option::t[str], run_ignored: bool};

type opt_res = either::t[test_opts, str];

// Parses command line arguments into test options
fn parse_opts(args: &str[]) : ivec::is_not_empty(args) -> opt_res {

    // FIXME (#649): Shouldn't have to check here
    check (ivec::is_not_empty(args));
    let args_ = ivec::tail(args);
    let opts = ~[getopts::optflag("ignored")];
    let match =
        alt getopts::getopts_ivec(args_, opts) {
          getopts::success(m) { m }
          getopts::failure(f) { ret either::right(getopts::fail_str(f)) }
        };

    let filter =
        if vec::len(match.free) > 0u {
            option::some(match.free.(0))
        } else { option::none };

    let run_ignored = getopts::opt_present(match, "ignored");

    let test_opts = {filter: filter, run_ignored: run_ignored};

    ret either::left(test_opts);
}

tag test_result { tr_ok; tr_failed; tr_ignored; }

// To get isolation and concurrency tests have to be run in their own tasks.
// In cases where test functions and closures it is not ok to just dump them
// into a task and run them, so this transformation gives the caller a chance
// to create the test task.
type test_to_task = fn(&fn()) -> task ;

// A simple console test runner
fn run_tests_console(opts: &test_opts, tests: &test_desc[]) -> bool {
    run_tests_console_(opts, tests, default_test_to_task)
}

fn run_tests_console_(opts: &test_opts, tests: &test_desc[],
                      to_task: &test_to_task) -> bool {

    type test_state = @{
        out: io::writer,
        use_color: bool,
        mutable total: uint,
        mutable passed: uint,
        mutable failed: uint,
        mutable ignored: uint,
        mutable failures: test_desc[]
    };

    fn callback(event: testevent, st: test_state) {
        alt event {
          te_filtered(filtered_tests) {
            st.total = ivec::len(filtered_tests);
            st.out.write_line(#fmt("\nrunning %u tests", st.total));
          }
          te_result(test, result) {
            st.out.write_str(#fmt("test %s ... ", test.name));
            alt result {
              tr_ok. {
                st.passed += 1u;
                write_ok(st.out, st.use_color);
                st.out.write_line("");
              }
              tr_failed. {
                st.failed += 1u;
                write_failed(st.out, st.use_color);
                st.out.write_line("");
                st.failures += ~[test];
              }
              tr_ignored. {
                st.ignored += 1u;
                write_ignored(st.out, st.use_color);
                st.out.write_line("");
              }
            }
          }
        }
    }

    let st = @{
        out: io::stdout(),
        use_color: use_color(),
        mutable total: 0u,
        mutable passed: 0u,
        mutable failed: 0u,
        mutable ignored: 0u,
        mutable failures: ~[]
    };

    run_tests(opts, tests, to_task,
              bind callback(_, st));

    assert st.passed + st.failed + st.ignored == st.total;
    let success = st.failed == 0u;

    if !success {
        st.out.write_line("\nfailures:");
        for test: test_desc in st.failures {
            let testname = test.name; // Satisfy alias analysis
            st.out.write_line(#fmt("    %s", testname));
        }
    }

    st.out.write_str(#fmt("\nresult: "));
    if success {
        // There's no parallelism at this point so it's safe to use color
        write_ok(st.out, true);
    } else { write_failed(st.out, true); }
    st.out.write_str(#fmt(". %u passed; %u failed; %u ignored\n\n",
                       st.passed, st.failed, st.ignored));

    ret success;

    fn write_ok(out: &io::writer, use_color: bool) {
        write_pretty(out, "ok", term::color_green, use_color);
    }

    fn write_failed(out: &io::writer, use_color: bool) {
        write_pretty(out, "FAILED", term::color_red, use_color);
    }

    fn write_ignored(out: &io::writer, use_color: bool) {
        write_pretty(out, "ignored", term::color_yellow, use_color);
    }

    fn write_pretty(out: &io::writer, word: &str, color: u8,
                    use_color: bool) {
        if use_color && term::color_supported() {
            term::fg(out.get_buf_writer(), color);
        }
        out.write_str(word);
        if use_color && term::color_supported() {
            term::reset(out.get_buf_writer());
        }
    }
}

fn use_color() -> bool {
    ret get_concurrency() == 1u;
}

tag testevent {
    te_filtered(test_desc[]);
    te_result(test_desc, test_result);
}

fn run_tests(opts: &test_opts, tests: &test_desc[],
             to_task: &test_to_task, callback: fn(testevent)) {

    let filtered_tests = filter_tests(opts, tests);

    callback(te_filtered(filtered_tests));

    // It's tempting to just spawn all the tests at once but that doesn't
    // provide a great user experience because you might sit waiting for the
    // result of a particular test for an unusually long amount of time.
    let concurrency = get_concurrency();
    log #fmt("using %u test tasks", concurrency);
    let total = ivec::len(filtered_tests);
    let run_idx = 0u;
    let wait_idx = 0u;
    let futures = ~[];

    while wait_idx < total {
        while ivec::len(futures) < concurrency && run_idx < total {
            futures += ~[run_test(filtered_tests.(run_idx), to_task)];
            run_idx += 1u;
        }

        let future = futures.(0);
        let result = future.wait();
        callback(te_result(future.test, result));
        futures = ivec::slice(futures, 1u, ivec::len(futures));
        wait_idx += 1u;
    }
}

fn get_concurrency() -> uint { rustrt::sched_threads() }

fn filter_tests(opts: &test_opts, tests: &test_desc[]) -> test_desc[] {
    let filtered = tests;

    // Remove tests that don't match the test filter
    filtered =
        if option::is_none(opts.filter) {
            filtered
        } else {
            let filter_str =
                alt opts.filter {
                  option::some(f) { f }
                  option::none. { "" }
                };

            let filter =
                bind fn (test: &test_desc, filter_str: str) ->
                        option::t[test_desc] {
                         if str::find(test.name, filter_str) >= 0 {
                             ret option::some(test);
                         } else { ret option::none; }
                     }(_, filter_str);

            ivec::filter_map(filter, filtered)
        };

    // Maybe pull out the ignored test and unignore them
    filtered =
        if !opts.run_ignored {
            filtered
        } else {
            let filter =
                fn (test: &test_desc) -> option::t[test_desc] {
                    if test.ignore {
                        ret option::some({name: test.name,
                                          fn: test.fn,
                                          ignore: false});
                    } else { ret option::none; }
                };

            ivec::filter_map(filter, filtered)
        };

    // Sort the tests alphabetically
    filtered =
        {
            fn lteq(t1: &test_desc, t2: &test_desc) -> bool {
                str::lteq(t1.name, t2.name)
            }
            sort::merge_sort(lteq, filtered)
        };

    ret filtered;
}

type test_future =
    {test: test_desc, fnref: @fn() , wait: fn() -> test_result };

fn run_test(test: &test_desc, to_task: &test_to_task) -> test_future {
    // FIXME: Because of the unsafe way we're passing the test function
    // to the test task, we need to make sure we keep a reference to that
    // function around for longer than the lifetime of the task. To that end
    // we keep the function boxed in the test future.
    let fnref = @test.fn;
    if !test.ignore {
        let test_task = to_task(*fnref);
        ret {test: test,
             fnref: fnref,
             wait:
                 bind fn (test_task: &task) -> test_result {
                          alt task::join(test_task) {
                            task::tr_success. { tr_ok }
                            task::tr_failure. { tr_failed }
                          }
                      }(test_task)};
    } else {
        ret {test: test,
             fnref: fnref,
             wait: fn () -> test_result { tr_ignored }};
    }
}

// We need to run our tests in another task in order to trap test failures.
// But, at least currently, functions can't be used as spawn arguments so
// we've got to treat our test functions as unsafe pointers.  This function
// only works with functions that don't contain closures.
fn default_test_to_task(f: &fn()) -> task {
    fn run_task(fptr: *mutable fn() ) {
        configure_test_task();
        // Run the test
        (*fptr)()
    }
    let fptr = ptr::addr_of(f);
    ret spawn run_task(fptr);
}

// Call from within a test task to make sure it's set up correctly
fn configure_test_task() {
    // If this task fails we don't want that failure to propagate to the
    // test runner or else we couldn't keep running tests
    task::unsupervise();

    // FIXME (236): Hack supreme - unwinding doesn't work yet so if this
    // task fails memory will not be freed correctly. This turns off the
    // sanity checks in the runtime's memory region for the task, so that
    // the test runner can continue.
    rustrt::hack_allow_leaks();
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::fmt;
use std::convert::From;
use std::io;

use nix;
use core::chars::CharStreamError;

/// An error arising from terminal operations.
///
/// The lower-level cause of the error, if any, will be returned by calling `cause()`.
///
/// **Note:** Errors arising from system calls will return `None` when calling `cause()` as `nix`
/// errors do not implement `Error`. In this case, `description()` will return the standard `errno`
/// description.
#[derive(Debug)]
pub struct Error {
    description: &'static str,
    cause: Option<Box<::std::error::Error>>,
}

impl Error {
    /// Creates a new `Error` with the given description.
    pub fn new(desc: &'static str) -> Error {
        Error {
            description: desc,
            cause: None,
        }
    }
}

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

    fn cause(&self) -> Option<&::std::error::Error> {
        if let Some(ref err) = self.cause {
            Some(&**err)
        } else {
            None
        }
    }
}

impl From<nix::Error> for Error {
    fn from(err: nix::Error) -> Self {
        Error {
            description: err.errno().desc(),
            cause: None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error {
            description: "internal io error",
            cause: Some(Box::new(err)),
        }
    }
}

impl From<CharStreamError> for Error {
    fn from(err: CharStreamError) -> Self {
        Error {
            description: "utf8 encoding error",
            cause: Some(Box::new(err)),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", ::std::error::Error::description(self))
    }
}

<commit_msg>use std::error::Error as StdError<commit_after>use std::fmt;
use std::convert::From;
use std::io;
use std::error::Error as StdError;

use nix;
use core::chars::CharStreamError;

/// An error arising from terminal operations.
///
/// The lower-level cause of the error, if any, will be returned by calling `cause()`.
///
/// **Note:** Errors arising from system calls will return `None` when calling `cause()` as `nix`
/// errors do not implement `Error`. In this case, `description()` will return the standard `errno`
/// description.
#[derive(Debug)]
pub struct Error {
    description: &'static str,
    cause: Option<Box<StdError>>,
}

impl Error {
    /// Creates a new `Error` with the given description.
    pub fn new(desc: &'static str) -> Error {
        Error {
            description: desc,
            cause: None,
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        self.description
    }

    fn cause(&self) -> Option<&StdError> {
        if let Some(ref err) = self.cause {
            Some(&**err)
        } else {
            None
        }
    }
}

impl From<nix::Error> for Error {
    fn from(err: nix::Error) -> Self {
        Error {
            description: err.errno().desc(),
            cause: None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error {
            description: "internal io error",
            cause: Some(Box::new(err)),
        }
    }
}

impl From<CharStreamError> for Error {
    fn from(err: CharStreamError) -> Self {
        Error {
            description: "utf8 encoding error",
            cause: Some(Box::new(err)),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", StdError::description(self))
    }
}

<|endoftext|>


<commit_before>extern crate num;
extern crate rand;
extern crate time;
extern crate bignum = "bignum#0.1.1-pre";

use bignum::{BigUint, ToBigUint, RandBigInt};
use num::{div_mod_floor, Integer};
use std::num::{Zero, One, pow, Float, FromPrimitive};
use rand::{task_rng, Rng};
use rand::distributions::range::SampleRange;
use std::vec::Vec;
use std::iter;
use std::iter::{FromIterator};
use std::clone::Clone;
use std::ops::{Shr, BitAnd};
use std::bool;

static pow_offsets : &'static[uint] = &[0u, 4u, 6u, 10u, 12u, 16u];

#[inline]
fn big<T: ToBigUint>(i : T) -> BigUint {
    i.to_biguint().unwrap()
}

// Source: https://gist.github.com/jsanders/8739134#file-generate_big_primes-rs-L35
fn mod_exp<T: Integer + Clone + Shr<uint,T> + BitAnd<T,T>>
    (base: &T, exponent: &T, modulus: &T) -> T {

    let (zero, one): (T, T) = (Zero::zero(), One::one());
    let mut result = one.clone();
    let mut baseAcc = base.clone();
    let mut exponentAcc = exponent.clone();

    while exponentAcc > zero {
        // Accumulate current base if current exponent bit is 1
        if (exponentAcc & one) == one {
            result = result.mul(&baseAcc);
            result = result.rem(modulus);
        }
        // Get next base by squaring
        baseAcc = baseAcc * baseAcc;
        baseAcc = baseAcc % *modulus;

        // Get next bit of exponent
        exponentAcc = exponentAcc.shr(&1);
    }
    result

}

// Rabin-Miller primality test, probabilistic
fn try_composite(a : &BigUint, d : &BigUint, n : &BigUint, s : &BigUint) -> bool {

    let one : BigUint = One::one();
    if mod_exp(a, d, n) == one {
        return false
    }
    let mut i = 0u;
    loop {
        if big(i) == *s {
            break
        }
        if mod_exp(a, &(pow(one+one, i) * *d), n) == *n-one {
            return false
        }
        i += 1;
    }
    true

}
fn rm_is_prime(n : &BigUint) -> bool {

    let (zero, one): (BigUint, BigUint) = (Zero::zero(), One::one());
    let two = one + one;

    assert!(n >= &two);

    let mut s = zero.clone();
    let mut d = *n-one;
    let num_trials = 5;
    if n == &two {
        return true
    } else if n == &one || n.is_even() {
        return false
    } else {
        loop {
            let (quotient, remainder) = div_mod_floor(d.clone(), two.clone());
            if remainder == one { break }
            s = s + one;
            d = quotient;
        }
    }

    let mut rng = task_rng();
    for _ in range(0, num_trials) {
        let a = rng.gen_biguint_range(&two, n);
        if try_composite(&a, &d, n, &s) {
            return false
        }
    }
    true

}

fn fermat_is_prime(n : &BigUint) -> bool {
    let (zero, one): (BigUint, BigUint) = (Zero::zero(), One::one());
    let two = one + one;

    if n == &two {
        true
    } else if n.is_even() {
        false
    } else if mod_exp(&two, &(n-one), n) == one {
        true
    } else {
        false
    }
}

fn is_valid_pow(prime : &BigUint) -> Option<BigUint> {
    for offset in [big(0u), big(4u), big(6u), big(10u), big(12u), big(16u)].iter() {
        if !fermat_is_prime(&(*prime + *offset)) {
            return None;
        }
    }
    Some(prime.clone())
}

// Simple sieve
fn simple_sieve(primes : &mut Vec<bool>, max_sieve : uint, verbose : bool) -> Vec<uint> {
    #[inline]
    fn int_sqrt(n: uint) -> uint { (n as f64).sqrt() as uint }

    if primes.len() <= max_sieve {
        *primes = Vec::from_elem(max_sieve+1, true);
        *primes.get_mut(0) = false;
        *primes.get_mut(1) = false;
        for prime in range(2, int_sqrt(max_sieve) + 1) {
            if *primes.get(prime) {
                for multiple in iter::range_step(prime * prime, max_sieve + 1, prime) {
                    *primes.get_mut(multiple) = false
                }
                if verbose { println!("Sieved {}", prime) }
            }
        }
    }
    if verbose { println!("Finished sieving") }
    range(2, max_sieve+1).filter(|&n| *primes.get(n)).collect()
}

fn gen_prime(base_val : &BigUint, max_val : &BigUint, max_sieve : uint, verbose : bool) -> uint {

    fn candidate_killed_by(candidate : &BigUint, prime : &BigUint) -> bool {
        let zero : BigUint = Zero::zero();
        for &offset in pow_offsets.iter() {
            let o : BigUint = FromPrimitive::from_uint(offset).unwrap();
            if (*candidate + o) % *prime == zero {
                return true;
            }
        }
        false
    }

    fn add_next_prime (max_val : &BigUint, offsets : Vec<BigUint>, prime : BigUint, primorial : BigUint) -> Vec<BigUint> {
        let (zero, one): (BigUint, BigUint) = (Zero::zero(), One::one());
        let mut base : BigUint = Zero::zero();
        let mut new_offsets : Vec<BigUint> = Vec::new();
        let mut counter = zero.clone();
        while counter < prime {
            if base > *max_val {
                break
            }
            for o in offsets.iter() {
                    let val = base + *o;
                    if val > *max_val {
                        break
                    }
                    if !candidate_killed_by(&val, &prime) {
                        new_offsets.push(val);
                    }
            }
            base = base + primorial;
            counter = counter + one;
        }
        return new_offsets
    }

    let primorial_start : uint = 7u;
    let mut primorial : uint = 210u;  // 2*3*5*7
    let mut offsets : Vec<BigUint> = Vec::from_slice([big(97u)]);

    let mut primes : Vec<bool> = Vec::new();

    for &i in simple_sieve(&mut primes, max_sieve, verbose).iter() {
        if i <= primorial_start {
            continue
        }
        offsets = add_next_prime(max_val, offsets, big(i), big(primorial));
        primorial = primorial * i;
    }
    offsets.retain(|o| o >= base_val && is_valid_pow(o) != None);
    offsets.len()
}

fn gen_prime_par(base_val : &BigUint, max_val : &BigUint, max_sieve : uint, verbose : bool) -> uint {

    fn candidate_killed_by(candidate : &BigUint, prime : &BigUint) -> bool {
        let zero : BigUint = Zero::zero();
        for &offset in pow_offsets.iter() {
            let o : BigUint = FromPrimitive::from_uint(offset).unwrap();
            if (*candidate + o) % *prime == zero {
                return true;
            }
        }
        false
    }

    fn add_next_prime (max_val : &BigUint, offsets : Vec<BigUint>, prime : BigUint, primorial : BigUint) -> Vec<BigUint> {
        let (zero, one): (BigUint, BigUint) = (Zero::zero(), One::one());
        let mut base : BigUint = Zero::zero();
        let mut new_offsets : Vec<BigUint> = Vec::new();
        let mut counter = zero.clone();
        while counter < prime {
            if base > *max_val {
                break
            }
            for o in offsets.iter() {
                    let val = base + *o;
                    if val > *max_val {
                        break
                    }
                    if !candidate_killed_by(&val, &prime) {
                        new_offsets.push(val);
                    }
            }
            base = base + primorial;
            counter = counter + one;
        }
        return new_offsets
    }

    let primorial_start : uint = 7u;
    let mut primorial : uint = 210u;  // 2*3*5*7
    let mut offsets : Vec<BigUint> = Vec::from_slice([big(97u)]);

    let mut primes : Vec<bool> = Vec::new();

    let mut start_time = time::precise_time_s();
    let sieve = simple_sieve(&mut primes, max_sieve, verbose);
    println!("Time to sieve: {}", time::precise_time_s() - start_time);
    start_time = time::precise_time_s();
    for &i in sieve.iter() {
        if i <= primorial_start {
            continue
        }
        offsets = add_next_prime(max_val, offsets, big(i), big(primorial));
        primorial = primorial * i;
    }
    println!("Time to sieve sieve: {}", time::precise_time_s() - start_time);

    start_time = time::precise_time_s();
    let (tx, rx) = channel();
    let mut child_count = 0;
    for o in offsets.iter().filter(|&o| o >= base_val) {
        let child_tx = tx.clone();
        let b = o.clone();
        spawn(proc() {
            child_tx.send(is_valid_pow(&b));
        });
        child_count += 1;
    }

    println!("Time to spawn: {}", time::precise_time_s() - start_time);

    let mut cluster_count = 0;
    for _ in range(0, child_count) {
        match rx.recv() {
            Some(p) => cluster_count += 1,
            None => ()
        }
    }
    cluster_count
}

#[cfg(test)]
mod test_primes {
    use super::{big, gen_prime, simple_sieve};

    #[test]
    fn gen_prime_is_correct() {
        assert!(gen_prime(&big(0), &big(100000000), 29, false) == 81u);
    }

    #[test]
    fn simple_sieve_is_correct() {
        assert!(simple_sieve(&mut Vec::new(), 5000000, false).len() == 348513);
    }
}

fn main() {
    println!("{}", gen_prime_par(&big(0), &big(1000000000), 210, true));
}<commit_msg>Parallelize sieving<commit_after>extern crate num;
extern crate rand;
extern crate time;
extern crate bignum = "bignum#0.1.1-pre";

use bignum::{BigUint, ToBigUint, RandBigInt};
use num::{div_mod_floor, Integer};
use std::num::{Zero, One, pow, Float, FromPrimitive};
use rand::{task_rng, Rng};
use rand::distributions::range::SampleRange;
use std::vec::Vec;
use std::iter;
use std::iter::{FromIterator};
use std::clone::Clone;
use std::ops::{Shr, BitAnd};
use std::bool;

static pow_offsets : &'static[uint] = &[0u, 4u, 6u, 10u, 12u, 16u];

#[inline]
fn big<T: ToBigUint>(i : T) -> BigUint {
    i.to_biguint().unwrap()
}

// Source: https://gist.github.com/jsanders/8739134#file-generate_big_primes-rs-L35
fn mod_exp<T: Integer + Clone + Shr<uint,T> + BitAnd<T,T>>
    (base: &T, exponent: &T, modulus: &T) -> T {

    let (zero, one): (T, T) = (Zero::zero(), One::one());
    let mut result = one.clone();
    let mut baseAcc = base.clone();
    let mut exponentAcc = exponent.clone();

    while exponentAcc > zero {
        // Accumulate current base if current exponent bit is 1
        if (exponentAcc & one) == one {
            result = result.mul(&baseAcc);
            result = result.rem(modulus);
        }
        // Get next base by squaring
        baseAcc = baseAcc * baseAcc;
        baseAcc = baseAcc % *modulus;

        // Get next bit of exponent
        exponentAcc = exponentAcc.shr(&1);
    }
    result

}

// Rabin-Miller primality test, probabilistic
fn try_composite(a : &BigUint, d : &BigUint, n : &BigUint, s : &BigUint) -> bool {

    let one : BigUint = One::one();
    if mod_exp(a, d, n) == one {
        return false
    }
    let mut i = 0u;
    loop {
        if big(i) == *s {
            break
        }
        if mod_exp(a, &(pow(one+one, i) * *d), n) == *n-one {
            return false
        }
        i += 1;
    }
    true

}
fn rm_is_prime(n : &BigUint) -> bool {

    let (zero, one): (BigUint, BigUint) = (Zero::zero(), One::one());
    let two = one + one;

    assert!(n >= &two);

    let mut s = zero.clone();
    let mut d = *n-one;
    let num_trials = 5;
    if n == &two {
        return true
    } else if n == &one || n.is_even() {
        return false
    } else {
        loop {
            let (quotient, remainder) = div_mod_floor(d.clone(), two.clone());
            if remainder == one { break }
            s = s + one;
            d = quotient;
        }
    }

    let mut rng = task_rng();
    for _ in range(0, num_trials) {
        let a = rng.gen_biguint_range(&two, n);
        if try_composite(&a, &d, n, &s) {
            return false
        }
    }
    true

}

fn fermat_is_prime(n : &BigUint) -> bool {
    let (zero, one): (BigUint, BigUint) = (Zero::zero(), One::one());
    let two = one + one;

    if n == &two {
        true
    } else if n.is_even() {
        false
    } else if mod_exp(&two, &(n-one), n) == one {
        true
    } else {
        false
    }
}

fn is_valid_pow(prime : &BigUint) -> Option<BigUint> {
    for offset in [big(0u), big(4u), big(6u), big(10u), big(12u), big(16u)].iter() {
        if !fermat_is_prime(&(*prime + *offset)) {
            return None;
        }
    }
    Some(prime.clone())
}

// Simple sieve
fn simple_sieve(primes : &mut Vec<bool>, max_sieve : uint, verbose : bool) -> Vec<uint> {
    #[inline]
    fn int_sqrt(n: uint) -> uint { (n as f64).sqrt() as uint }

    if primes.len() <= max_sieve {
        *primes = Vec::from_elem(max_sieve+1, true);
        *primes.get_mut(0) = false;
        *primes.get_mut(1) = false;
        for prime in range(2, int_sqrt(max_sieve) + 1) {
            if *primes.get(prime) {
                for multiple in iter::range_step(prime * prime, max_sieve + 1, prime) {
                    *primes.get_mut(multiple) = false
                }
                if verbose { println!("Sieved {}", prime) }
            }
        }
    }
    if verbose { println!("Finished sieving") }
    range(2, max_sieve+1).filter(|&n| *primes.get(n)).collect()
}

fn gen_prime(base_val : &BigUint, max_val : &BigUint, max_sieve : uint, verbose : bool) -> uint {

    fn candidate_killed_by(candidate : &BigUint, prime : &BigUint) -> bool {
        let zero : BigUint = Zero::zero();
        for &offset in pow_offsets.iter() {
            let o : BigUint = FromPrimitive::from_uint(offset).unwrap();
            if (*candidate + o) % *prime == zero {
                return true;
            }
        }
        false
    }

    fn add_next_prime (max_val : &BigUint, offsets : Vec<BigUint>, prime : BigUint, primorial : BigUint) -> Vec<BigUint> {
        let (zero, one): (BigUint, BigUint) = (Zero::zero(), One::one());
        let mut base : BigUint = Zero::zero();
        let mut new_offsets : Vec<BigUint> = Vec::new();
        let mut counter = zero.clone();
        while counter < prime {
            if base > *max_val {
                break
            }
            for o in offsets.iter() {
                let val = base + *o;
                if val > *max_val {
                    break
                }
                if !candidate_killed_by(&val, &prime) {
                    new_offsets.push(val);
                }
            }
            base = base + primorial;
            counter = counter + one;
        }
        return new_offsets
    }

    let primorial_start : uint = 7u;
    let mut primorial : uint = 210u;  // 2*3*5*7
    let mut offsets : Vec<BigUint> = Vec::from_slice([big(97u)]);

    let mut primes : Vec<bool> = Vec::new();

    for &i in simple_sieve(&mut primes, max_sieve, verbose).iter() {
        if i <= primorial_start {
            continue
        }
        offsets = add_next_prime(max_val, offsets, big(i), big(primorial));
        primorial = primorial * i;
    }
    offsets.retain(|o| o >= base_val && is_valid_pow(o) != None);
    offsets.len()
}

fn gen_prime_par(base_val : &BigUint, max_val : &BigUint, max_sieve : uint, verbose : bool) -> uint {

    fn candidate_killed_by(candidate : &BigUint, prime : &BigUint) -> bool {
        let zero : BigUint = Zero::zero();
        for &offset in pow_offsets.iter() {
            let o : BigUint = big(offset);
            if (*candidate + o) % *prime == zero {
                return true;
            }
        }
        false
    }

    fn add_next_prime (max_val : &BigUint, offsets : Vec<BigUint>, prime : BigUint, primorial : BigUint) -> Vec<BigUint> {
        let (zero, one): (BigUint, BigUint) = (Zero::zero(), One::one());
        let mut base : BigUint = Zero::zero();
        let mut new_offsets : Vec<BigUint> = Vec::new();
        let mut counter = zero.clone();

        let mut start_time = time::precise_time_s();
        let (tx, rx) = channel();
        while counter < prime {
            let b = counter * primorial + base;
            if b > *max_val {
                break
            }
            let child_tx = tx.clone();
            let p = prime.clone();
            let mv = max_val.clone();
            let offs = offsets.clone();
            spawn(proc() {
                let mut vals = Vec::new();
                for o in offs.iter() {
                    let val = b + *o;
                    if val <= mv {
                        if !candidate_killed_by(&val, &p) {
                            vals.push(val);
                        }
                    }
                }
                child_tx.send(vals);
            });
            counter = counter + one;
        }
        println!("Time to sieve send: {}", time::precise_time_s() - start_time);

        start_time = time::precise_time_s();
        while counter > zero {
            new_offsets.push_all_move(rx.recv());
            counter = counter - one;
        }
        println!("Time to sieve receive: {}", time::precise_time_s() - start_time);

        new_offsets
    }

    let primorial_start : uint = 7u;
    let mut primorial : uint = 210u;  // 2*3*5*7
    let mut offsets : Vec<BigUint> = Vec::from_slice([big(97u)]);

    let mut primes : Vec<bool> = Vec::new();

    let mut start_time = time::precise_time_s();
    let sieve = simple_sieve(&mut primes, max_sieve, verbose);
    println!("Time to sieve: {}", time::precise_time_s() - start_time);
    start_time = time::precise_time_s();
    for &i in sieve.iter() {
        if i <= primorial_start {
            continue
        }
        offsets = add_next_prime(max_val, offsets, big(i), big(primorial));
        primorial = primorial * i;
    }
    println!("Time to sieve sieve: {}", time::precise_time_s() - start_time);

    start_time = time::precise_time_s();
    let (tx, rx) = channel();
    let mut child_count = 0;
    for o in offsets.iter().filter(|&o| o >= base_val) {
        let child_tx = tx.clone();
        let b = o.clone();
        spawn(proc() {
            child_tx.send(is_valid_pow(&b));
        });
        child_count += 1;
    }

    println!("Time to spawn: {}", time::precise_time_s() - start_time);

    let mut cluster_count = 0;
    for _ in range(0, child_count) {
        match rx.recv() {
            Some(p) => cluster_count += 1,
            None => ()
        }
    }
    cluster_count
}

#[cfg(test)]
mod test_primes {
    use super::{big, gen_prime, simple_sieve};

    #[test]
    fn gen_prime_is_correct() {
        assert!(gen_prime(&big(0), &big(100000000), 29, false) == 81u);
    }

    #[test]
    fn simple_sieve_is_correct() {
        assert!(simple_sieve(&mut Vec::new(), 5000000, false).len() == 348513);
    }
}

fn main() {
    println!("{}", gen_prime_par(&big(0), &big(1000000000), 210, true));
}<|endoftext|>