<commit_before>use crate::utils::{
    in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAP,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        match fn_kind {
            FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
                if visibility.node.is_pub() {
                    return;
                }
            },
            FnKind::Closure(..) => return,
            _ => (),
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if !in_macro(ret_expr.span);
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg && !suggs.is_empty() {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAP,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MaybeIncorrect,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<commit_msg>Remove wildcard use<commit_after>use crate::utils::{
    in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, ExprKind, FnDecl, HirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAP,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        match fn_kind {
            FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
                if visibility.node.is_pub() {
                    return;
                }
            },
            FnKind::Closure(..) => return,
            _ => (),
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if !in_macro(ret_expr.span);
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg && !suggs.is_empty() {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAP,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MaybeIncorrect,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<|endoftext|>


<commit_before>extern crate actix;
extern crate actix_web;
extern crate env_logger;
#[macro_use]
extern crate tera;
use actix_web::*;

struct State {
    template: tera::Tera,  // <- store tera template in application state
}

fn index(req: HttpRequest<State>) -> Result<HttpResponse> {
    let s = if let Some(name) = req.query().get("name") { // <- submitted form
        let mut ctx = tera::Context::new();
        ctx.add("name", name);
        ctx.add("text", &"Welcome!".to_owned());
        req.state().template.render("user.html", &ctx)
            .map_err(|_| error::ErrorInternalServerError("Template error"))?
    } else {
        req.state().template.render("index.html", &tera::Context::new())
            .map_err(|_| error::ErrorInternalServerError("Template error"))?
    };
    Ok(httpcodes::HTTPOk.build()
       .content_type("text/html")
       .body(s)?)
}

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    let _ = env_logger::init();
    let sys = actix::System::new("tera-example");

    HttpServer::new(|| {
        let tera = compile_templates!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*"));

        Application::with_state(State{template: tera})
            // enable logger
            .middleware(middleware::Logger::default())
            .resource("/", |r| r.method(Method::GET).f(index))})
        .bind("127.0.0.1:8080").unwrap()
        .start();

    println!("Started http server: 127.0.0.1:8080");
    let _ = sys.run();
}
<commit_msg>fix example<commit_after>extern crate actix;
extern crate actix_web;
extern crate env_logger;
#[macro_use]
extern crate tera;
use actix_web::*;

struct State {
    template: tera::Tera,  // <- store tera template in application state
}

fn index(req: HttpRequest<State>) -> Result<HttpResponse> {
    let s = if let Some(name) = req.query().get("name") { // <- submitted form
        let mut ctx = tera::Context::new();
        ctx.add("name", &name.to_owned());
        ctx.add("text", &"Welcome!".to_owned());
        req.state().template.render("user.html", &ctx)
            .map_err(|_| error::ErrorInternalServerError("Template error"))?
    } else {
        req.state().template.render("index.html", &tera::Context::new())
            .map_err(|_| error::ErrorInternalServerError("Template error"))?
    };
    Ok(httpcodes::HTTPOk.build()
       .content_type("text/html")
       .body(s)?)
}

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    let _ = env_logger::init();
    let sys = actix::System::new("tera-example");

    HttpServer::new(|| {
        let tera = compile_templates!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*"));

        Application::with_state(State{template: tera})
            // enable logger
            .middleware(middleware::Logger::default())
            .resource("/", |r| r.method(Method::GET).f(index))})
        .bind("127.0.0.1:8080").unwrap()
        .start();

    println!("Started http server: 127.0.0.1:8080");
    let _ = sys.run();
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::cmp::{Ord, Ordering, PartialOrd};
use std::collections::BTreeMap;
use std::fmt;
use std::hash;
use std::ops::{Add, Sub};
use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
use std::str::FromStr;

use chrono::naive::NaiveDate;
use chrono::{DateTime, Datelike, Duration, TimeZone, Utc};
use serde::{Deserialize, Serialize};

pub mod api;
pub mod git;

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct Commit {
    pub sha: String,
    pub date: Date,
}

impl Commit {
    pub fn is_try(&self) -> bool {
        self.date.0.naive_utc().date() == NaiveDate::from_ymd(2000, 1, 1)
    }
}

impl hash::Hash for Commit {
    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
        self.sha.hash(hasher);
    }
}

impl PartialEq for Commit {
    fn eq(&self, other: &Self) -> bool {
        self.sha == other.sha
    }
}

impl Eq for Commit {}

impl PartialOrd for Commit {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(&other))
    }
}

impl Ord for Commit {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date
            .cmp(&other.date)
            .then_with(|| self.sha.cmp(&other.sha))
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Patch {
    index: usize,
    pub name: String,
    path: PathBuf,
}

impl PartialEq for Patch {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}

impl Eq for Patch {}

impl hash::Hash for Patch {
    fn hash<H: hash::Hasher>(&self, h: &mut H) {
        self.name.hash(h);
    }
}

impl Patch {
    pub fn new(path: PathBuf) -> Self {
        assert!(path.is_file());
        let (index, name) = {
            let file_name = path.file_name().unwrap().to_string_lossy();
            let mut parts = file_name.split("-");
            let index = parts.next().unwrap().parse().unwrap_or_else(|e| {
                panic!(
                    "{:?} should be in the format 000-name.patch, \
                     but did not start with a number: {:?}",
                    &path, e
                );
            });
            let mut name = parts.fold(String::new(), |mut acc, part| {
                acc.push_str(part);
                acc.push(' ');
                acc
            });
            let len = name.len();
            // take final space off
            name.truncate(len - 1);
            let name = name.replace(".patch", "");
            (index, name)
        };

        Patch {
            path: PathBuf::from(path.file_name().unwrap()),
            index,
            name,
        }
    }

    pub fn apply(&self, dir: &Path) -> Result<(), String> {
        log::debug!("applying {} to {:?}", self.name, dir);
        let mut cmd = process::Command::new("patch");
        cmd.current_dir(dir).args(&["-Np1", "-i"]).arg(&self.path);
        cmd.stdout(Stdio::null());
        if cmd.status().map(|s| !s.success()).unwrap_or(false) {
            return Err(format!("could not execute {:?}.", cmd));
        }
        Ok(())
    }
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub enum BenchmarkState {
    Clean,
    Nll,
    IncrementalStart,
    IncrementalClean,
    IncrementalPatched(Patch),
}

impl BenchmarkState {
    pub fn is_base_compile(&self) -> bool {
        if let BenchmarkState::Clean = *self {
            true
        } else {
            false
        }
    }

    pub fn is_patch(&self) -> bool {
        if let BenchmarkState::IncrementalPatched(_) = *self {
            true
        } else {
            false
        }
    }

    pub fn name(&self) -> Cow<'static, str> {
        match *self {
            BenchmarkState::Clean => "clean".into(),
            BenchmarkState::Nll => "nll".into(),
            BenchmarkState::IncrementalStart => "baseline incremental".into(),
            BenchmarkState::IncrementalClean => "clean incremental".into(),
            BenchmarkState::IncrementalPatched(ref patch) => {
                format!("patched incremental: {}", patch.name).into()
            }
        }
    }

    // Otherwise we end up with "equivalent benchmarks" looking different,
    // e.g. 8-println.patch vs. 0-println.patch
    pub fn erase_path(mut self) -> Self {
        match &mut self {
            BenchmarkState::IncrementalPatched(patch) => {
                patch.index = 0;
                patch.path = PathBuf::new();
            }
            _ => {}
        }
        self
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Benchmark {
    pub runs: Vec<Run>,
    pub name: String,
}

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct Stat {
    pub name: String,
    pub cnt: f64,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Run {
    pub stats: Vec<Stat>,
    #[serde(default)]
    pub check: bool,
    pub release: bool,
    pub state: BenchmarkState,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RunId {
    check: bool,
    release: bool,
    state: BenchmarkState,
}

impl RunId {
    pub fn name(&self) -> String {
        self.to_string()
    }
}

impl fmt::Display for RunId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let opt = if self.release {
            "-opt"
        } else if self.check {
            "-check"
        } else {
            ""
        };
        write!(f, "{}{}", self.state.name(), opt)
    }
}

impl PartialEq for Run {
    fn eq(&self, other: &Self) -> bool {
        self.release == other.release && self.check == other.check && self.state == other.state
    }
}

impl PartialEq<RunId> for Run {
    fn eq(&self, other: &RunId) -> bool {
        self.release == other.release && self.check == other.check && self.state == other.state
    }
}

impl Run {
    pub fn is_clean(&self) -> bool {
        self.state == BenchmarkState::Clean
    }

    pub fn is_base_incr(&self) -> bool {
        self.state == BenchmarkState::IncrementalStart
    }

    pub fn is_clean_incr(&self) -> bool {
        self.state == BenchmarkState::IncrementalClean
    }

    pub fn is_println_incr(&self) -> bool {
        if let BenchmarkState::IncrementalPatched(ref patch) = self.state {
            return patch.name == "println";
        }
        false
    }

    pub fn id(&self) -> RunId {
        let state = self.state.clone();
        let state = state.erase_path();
        RunId {
            check: self.check,
            release: self.release,
            state: state,
        }
    }

    pub fn name(&self) -> String {
        self.id().name()
    }

    pub fn get_stat(&self, stat: &str) -> Option<f64> {
        self.stats.iter().find(|s| s.name == stat).map(|s| s.cnt)
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ArtifactData {
    pub id: String,
    // String in Result is the output of the command that failed
    pub benchmarks: BTreeMap<String, Result<Benchmark, String>>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CommitData {
    pub commit: Commit,
    // String in Result is the output of the command that failed
    pub benchmarks: BTreeMap<String, Result<Benchmark, String>>,
    pub triple: String,
}

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct DeltaTime(#[serde(with = "round_float")] pub f64);

#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Date(pub DateTime<Utc>);

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Bound {
    // sha, unverified
    Commit(String),
    Date(NaiveDate),
    None,
}

impl Serialize for Bound {
    fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        let s = match *self {
            Bound::Commit(ref s) => s.clone(),
            Bound::Date(ref date) => date.format("%Y-%m-%d").to_string(),
            Bound::None => String::new(),
        };
        serializer.serialize_str(&s)
    }
}

impl<'de> Deserialize<'de> for Bound {
    fn deserialize<D>(deserializer: D) -> ::std::result::Result<Bound, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        struct BoundVisitor;

        impl<'de> serde::de::Visitor<'de> for BoundVisitor {
            type Value = Bound;

            fn visit_str<E>(self, value: &str) -> ::std::result::Result<Bound, E>
            where
                E: serde::de::Error,
            {
                if value.is_empty() {
                    return Ok(Bound::None);
                }

                let bound = value
                    .parse::<NaiveDate>()
                    .map(|d| Bound::Date(d))
                    .unwrap_or(Bound::Commit(value.to_string()));
                Ok(bound)
            }

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                f.write_str("either a YYYY-mm-dd date or a collection ID (usually commit hash)")
            }
        }

        deserializer.deserialize_str(BoundVisitor)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DateParseError {
    pub input: String,
    pub format: String,
    pub error: chrono::ParseError,
}

impl FromStr for Date {
    type Err = DateParseError;
    fn from_str(s: &str) -> Result<Date, DateParseError> {
        match DateTime::parse_from_rfc3339(s) {
            Ok(value) => Ok(Date(value.with_timezone(&Utc))),
            Err(error) => Err(DateParseError {
                input: s.to_string(),
                format: format!("RFC 3339"),
                error,
            }),
        }
    }
}

impl Date {
    pub fn from_format(date: &str, format: &str) -> Result<Date, DateParseError> {
        match DateTime::parse_from_str(date, format) {
            Ok(value) => Ok(Date(value.with_timezone(&Utc))),
            Err(_) => match Utc.datetime_from_str(date, format) {
                Ok(dt) => Ok(Date(dt)),
                Err(err) => Err(DateParseError {
                    input: date.to_string(),
                    format: format.to_string(),
                    error: err,
                }),
            },
        }
    }

    pub fn ymd_hms(year: i32, month: u32, day: u32, h: u32, m: u32, s: u32) -> Date {
        Date(Utc.ymd(year, month, day).and_hms(h, m, s))
    }

    pub fn start_of_week(&self) -> Date {
        let weekday = self.0.weekday();
        // num_days_from_sunday is 0 for Sunday
        Date(self.0 - Duration::days(weekday.num_days_from_sunday() as i64))
    }
}

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.0.to_rfc3339())
    }
}

impl From<DateTime<Utc>> for Date {
    fn from(datetime: DateTime<Utc>) -> Date {
        Date(datetime)
    }
}

impl PartialEq<DateTime<Utc>> for Date {
    fn eq(&self, other: &DateTime<Utc>) -> bool {
        self.0 == *other
    }
}

impl Sub<Duration> for Date {
    type Output = Date;
    fn sub(self, rhs: Duration) -> Date {
        Date(self.0 - rhs)
    }
}

impl Add<Duration> for Date {
    type Output = Date;
    fn add(self, rhs: Duration) -> Date {
        Date(self.0 + rhs)
    }
}

impl Serialize for Date {
    fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        serializer.serialize_str(&self.0.to_rfc3339())
    }
}

impl<'de> Deserialize<'de> for Date {
    fn deserialize<D>(deserializer: D) -> ::std::result::Result<Date, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        struct DateVisitor;

        impl<'de> serde::de::Visitor<'de> for DateVisitor {
            type Value = Date;

            fn visit_str<E>(self, value: &str) -> ::std::result::Result<Date, E>
            where
                E: serde::de::Error,
            {
                Date::from_str(value).map_err(|_| {
                    serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self)
                })
            }

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                f.write_str("an RFC 3339 date")
            }
        }

        deserializer.deserialize_str(DateVisitor)
    }
}

pub fn null_means_nan<'de, D>(deserializer: D) -> ::std::result::Result<f64, D::Error>
where
    D: serde::de::Deserializer<'de>,
{
    Ok(Option::deserialize(deserializer)?.unwrap_or(0.0))
}

pub fn version_supports_incremental(version_str: &str) -> bool {
    if let Some(version) = version_str.parse::<semver::Version>().ok() {
        version >= semver::Version::new(1, 24, 0)
    } else {
        assert!(version_str == "beta" || version_str.starts_with("master"));
        true
    }
}

/// Rounds serialized and deserialized floats to 2 decimal places.
pub mod round_float {
    use serde::{Deserialize, Deserializer, Serializer};

    pub fn serialize<S>(n: &f64, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_f64((*n * 100.0).round() / 100.0)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<f64, D::Error>
    where
        D: Deserializer<'de>,
    {
        let n = f64::deserialize(deserializer)?;
        Ok((n * 100.0).round() / 100.0)
    }
}

pub fn run_command(cmd: &mut Command) -> Result<(), failure::Error> {
    log::trace!("running: {:?}", cmd);
    let status = cmd.status()?;
    if !status.success() {
        failure::bail!("expected success {:?}", status);
    }
    Ok(())
}

pub fn command_output(cmd: &mut Command) -> Result<process::Output, failure::Error> {
    log::trace!("running: {:?}", cmd);
    let output = cmd.output()?;
    if !output.status.success() {
        failure::bail!(
            "expected success, got {}\n\nstderr={}\n\n stdout={}",
            output.status,
            String::from_utf8_lossy(&output.stderr),
            String::from_utf8_lossy(&output.stdout)
        );
    }
    Ok(output)
}
<commit_msg>Remove -opt, -check trailers from individual builds<commit_after>use std::borrow::Cow;
use std::cmp::{Ord, Ordering, PartialOrd};
use std::collections::BTreeMap;
use std::fmt;
use std::hash;
use std::ops::{Add, Sub};
use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
use std::str::FromStr;

use chrono::naive::NaiveDate;
use chrono::{DateTime, Datelike, Duration, TimeZone, Utc};
use serde::{Deserialize, Serialize};

pub mod api;
pub mod git;

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct Commit {
    pub sha: String,
    pub date: Date,
}

impl Commit {
    pub fn is_try(&self) -> bool {
        self.date.0.naive_utc().date() == NaiveDate::from_ymd(2000, 1, 1)
    }
}

impl hash::Hash for Commit {
    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
        self.sha.hash(hasher);
    }
}

impl PartialEq for Commit {
    fn eq(&self, other: &Self) -> bool {
        self.sha == other.sha
    }
}

impl Eq for Commit {}

impl PartialOrd for Commit {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(&other))
    }
}

impl Ord for Commit {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date
            .cmp(&other.date)
            .then_with(|| self.sha.cmp(&other.sha))
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Patch {
    index: usize,
    pub name: String,
    path: PathBuf,
}

impl PartialEq for Patch {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}

impl Eq for Patch {}

impl hash::Hash for Patch {
    fn hash<H: hash::Hasher>(&self, h: &mut H) {
        self.name.hash(h);
    }
}

impl Patch {
    pub fn new(path: PathBuf) -> Self {
        assert!(path.is_file());
        let (index, name) = {
            let file_name = path.file_name().unwrap().to_string_lossy();
            let mut parts = file_name.split("-");
            let index = parts.next().unwrap().parse().unwrap_or_else(|e| {
                panic!(
                    "{:?} should be in the format 000-name.patch, \
                     but did not start with a number: {:?}",
                    &path, e
                );
            });
            let mut name = parts.fold(String::new(), |mut acc, part| {
                acc.push_str(part);
                acc.push(' ');
                acc
            });
            let len = name.len();
            // take final space off
            name.truncate(len - 1);
            let name = name.replace(".patch", "");
            (index, name)
        };

        Patch {
            path: PathBuf::from(path.file_name().unwrap()),
            index,
            name,
        }
    }

    pub fn apply(&self, dir: &Path) -> Result<(), String> {
        log::debug!("applying {} to {:?}", self.name, dir);
        let mut cmd = process::Command::new("patch");
        cmd.current_dir(dir).args(&["-Np1", "-i"]).arg(&self.path);
        cmd.stdout(Stdio::null());
        if cmd.status().map(|s| !s.success()).unwrap_or(false) {
            return Err(format!("could not execute {:?}.", cmd));
        }
        Ok(())
    }
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub enum BenchmarkState {
    Clean,
    Nll,
    IncrementalStart,
    IncrementalClean,
    IncrementalPatched(Patch),
}

impl BenchmarkState {
    pub fn is_base_compile(&self) -> bool {
        if let BenchmarkState::Clean = *self {
            true
        } else {
            false
        }
    }

    pub fn is_patch(&self) -> bool {
        if let BenchmarkState::IncrementalPatched(_) = *self {
            true
        } else {
            false
        }
    }

    pub fn name(&self) -> Cow<'static, str> {
        match *self {
            BenchmarkState::Clean => "clean".into(),
            BenchmarkState::Nll => "nll".into(),
            BenchmarkState::IncrementalStart => "baseline incremental".into(),
            BenchmarkState::IncrementalClean => "clean incremental".into(),
            BenchmarkState::IncrementalPatched(ref patch) => {
                format!("patched incremental: {}", patch.name).into()
            }
        }
    }

    // Otherwise we end up with "equivalent benchmarks" looking different,
    // e.g. 8-println.patch vs. 0-println.patch
    pub fn erase_path(mut self) -> Self {
        match &mut self {
            BenchmarkState::IncrementalPatched(patch) => {
                patch.index = 0;
                patch.path = PathBuf::new();
            }
            _ => {}
        }
        self
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Benchmark {
    pub runs: Vec<Run>,
    pub name: String,
}

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct Stat {
    pub name: String,
    pub cnt: f64,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Run {
    pub stats: Vec<Stat>,
    #[serde(default)]
    pub check: bool,
    pub release: bool,
    pub state: BenchmarkState,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RunId {
    check: bool,
    release: bool,
    state: BenchmarkState,
}

impl RunId {
    pub fn name(&self) -> String {
        self.to_string()
    }
}

impl fmt::Display for RunId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.state.name())
    }
}

impl PartialEq for Run {
    fn eq(&self, other: &Self) -> bool {
        self.release == other.release && self.check == other.check && self.state == other.state
    }
}

impl PartialEq<RunId> for Run {
    fn eq(&self, other: &RunId) -> bool {
        self.release == other.release && self.check == other.check && self.state == other.state
    }
}

impl Run {
    pub fn is_clean(&self) -> bool {
        self.state == BenchmarkState::Clean
    }

    pub fn is_base_incr(&self) -> bool {
        self.state == BenchmarkState::IncrementalStart
    }

    pub fn is_clean_incr(&self) -> bool {
        self.state == BenchmarkState::IncrementalClean
    }

    pub fn is_println_incr(&self) -> bool {
        if let BenchmarkState::IncrementalPatched(ref patch) = self.state {
            return patch.name == "println";
        }
        false
    }

    pub fn id(&self) -> RunId {
        let state = self.state.clone();
        let state = state.erase_path();
        RunId {
            check: self.check,
            release: self.release,
            state: state,
        }
    }

    pub fn name(&self) -> String {
        self.id().name()
    }

    pub fn get_stat(&self, stat: &str) -> Option<f64> {
        self.stats.iter().find(|s| s.name == stat).map(|s| s.cnt)
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ArtifactData {
    pub id: String,
    // String in Result is the output of the command that failed
    pub benchmarks: BTreeMap<String, Result<Benchmark, String>>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CommitData {
    pub commit: Commit,
    // String in Result is the output of the command that failed
    pub benchmarks: BTreeMap<String, Result<Benchmark, String>>,
    pub triple: String,
}

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct DeltaTime(#[serde(with = "round_float")] pub f64);

#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Date(pub DateTime<Utc>);

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Bound {
    // sha, unverified
    Commit(String),
    Date(NaiveDate),
    None,
}

impl Serialize for Bound {
    fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        let s = match *self {
            Bound::Commit(ref s) => s.clone(),
            Bound::Date(ref date) => date.format("%Y-%m-%d").to_string(),
            Bound::None => String::new(),
        };
        serializer.serialize_str(&s)
    }
}

impl<'de> Deserialize<'de> for Bound {
    fn deserialize<D>(deserializer: D) -> ::std::result::Result<Bound, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        struct BoundVisitor;

        impl<'de> serde::de::Visitor<'de> for BoundVisitor {
            type Value = Bound;

            fn visit_str<E>(self, value: &str) -> ::std::result::Result<Bound, E>
            where
                E: serde::de::Error,
            {
                if value.is_empty() {
                    return Ok(Bound::None);
                }

                let bound = value
                    .parse::<NaiveDate>()
                    .map(|d| Bound::Date(d))
                    .unwrap_or(Bound::Commit(value.to_string()));
                Ok(bound)
            }

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                f.write_str("either a YYYY-mm-dd date or a collection ID (usually commit hash)")
            }
        }

        deserializer.deserialize_str(BoundVisitor)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DateParseError {
    pub input: String,
    pub format: String,
    pub error: chrono::ParseError,
}

impl FromStr for Date {
    type Err = DateParseError;
    fn from_str(s: &str) -> Result<Date, DateParseError> {
        match DateTime::parse_from_rfc3339(s) {
            Ok(value) => Ok(Date(value.with_timezone(&Utc))),
            Err(error) => Err(DateParseError {
                input: s.to_string(),
                format: format!("RFC 3339"),
                error,
            }),
        }
    }
}

impl Date {
    pub fn from_format(date: &str, format: &str) -> Result<Date, DateParseError> {
        match DateTime::parse_from_str(date, format) {
            Ok(value) => Ok(Date(value.with_timezone(&Utc))),
            Err(_) => match Utc.datetime_from_str(date, format) {
                Ok(dt) => Ok(Date(dt)),
                Err(err) => Err(DateParseError {
                    input: date.to_string(),
                    format: format.to_string(),
                    error: err,
                }),
            },
        }
    }

    pub fn ymd_hms(year: i32, month: u32, day: u32, h: u32, m: u32, s: u32) -> Date {
        Date(Utc.ymd(year, month, day).and_hms(h, m, s))
    }

    pub fn start_of_week(&self) -> Date {
        let weekday = self.0.weekday();
        // num_days_from_sunday is 0 for Sunday
        Date(self.0 - Duration::days(weekday.num_days_from_sunday() as i64))
    }
}

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.0.to_rfc3339())
    }
}

impl From<DateTime<Utc>> for Date {
    fn from(datetime: DateTime<Utc>) -> Date {
        Date(datetime)
    }
}

impl PartialEq<DateTime<Utc>> for Date {
    fn eq(&self, other: &DateTime<Utc>) -> bool {
        self.0 == *other
    }
}

impl Sub<Duration> for Date {
    type Output = Date;
    fn sub(self, rhs: Duration) -> Date {
        Date(self.0 - rhs)
    }
}

impl Add<Duration> for Date {
    type Output = Date;
    fn add(self, rhs: Duration) -> Date {
        Date(self.0 + rhs)
    }
}

impl Serialize for Date {
    fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        serializer.serialize_str(&self.0.to_rfc3339())
    }
}

impl<'de> Deserialize<'de> for Date {
    fn deserialize<D>(deserializer: D) -> ::std::result::Result<Date, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        struct DateVisitor;

        impl<'de> serde::de::Visitor<'de> for DateVisitor {
            type Value = Date;

            fn visit_str<E>(self, value: &str) -> ::std::result::Result<Date, E>
            where
                E: serde::de::Error,
            {
                Date::from_str(value).map_err(|_| {
                    serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self)
                })
            }

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                f.write_str("an RFC 3339 date")
            }
        }

        deserializer.deserialize_str(DateVisitor)
    }
}

pub fn null_means_nan<'de, D>(deserializer: D) -> ::std::result::Result<f64, D::Error>
where
    D: serde::de::Deserializer<'de>,
{
    Ok(Option::deserialize(deserializer)?.unwrap_or(0.0))
}

pub fn version_supports_incremental(version_str: &str) -> bool {
    if let Some(version) = version_str.parse::<semver::Version>().ok() {
        version >= semver::Version::new(1, 24, 0)
    } else {
        assert!(version_str == "beta" || version_str.starts_with("master"));
        true
    }
}

/// Rounds serialized and deserialized floats to 2 decimal places.
pub mod round_float {
    use serde::{Deserialize, Deserializer, Serializer};

    pub fn serialize<S>(n: &f64, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_f64((*n * 100.0).round() / 100.0)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<f64, D::Error>
    where
        D: Deserializer<'de>,
    {
        let n = f64::deserialize(deserializer)?;
        Ok((n * 100.0).round() / 100.0)
    }
}

pub fn run_command(cmd: &mut Command) -> Result<(), failure::Error> {
    log::trace!("running: {:?}", cmd);
    let status = cmd.status()?;
    if !status.success() {
        failure::bail!("expected success {:?}", status);
    }
    Ok(())
}

pub fn command_output(cmd: &mut Command) -> Result<process::Output, failure::Error> {
    log::trace!("running: {:?}", cmd);
    let output = cmd.output()?;
    if !output.status.success() {
        failure::bail!(
            "expected success, got {}\n\nstderr={}\n\n stdout={}",
            output.status,
            String::from_utf8_lossy(&output.stderr),
            String::from_utf8_lossy(&output.stdout)
        );
    }
    Ok(output)
}
<|endoftext|>


<commit_before>extern crate adapton;

use std::rc::Rc;
use adapton::bitstring::BS;
use adapton::engine::*;
use adapton::trie::*;

#[test]
fn test_is_empty() {
    let meta = Meta { min_depth: 1 };
    let empty = TrieIntro::<usize>::empty(meta.clone());
    let singleton = Trie::singleton(meta.clone(), name_unit(), 7);
    assert!(Trie::<usize>::is_empty(&Trie::nil(BS {
        length: 0,
        value: 0,
    })));
    assert!(Trie::is_empty(&empty));

    assert!(!Trie::is_empty(&Trie::leaf(BS {
                                            length: 0,
                                            value: 0,
                                        },
                                        0)));
    assert!(!Trie::is_empty(&singleton));
}

#[test]
fn test_equal() {
    let meta = Meta { min_depth: 1 };
    let empty: Trie<usize> = TrieIntro::empty(meta.clone());
    let singleton_7 = Trie::singleton(meta.clone(), name_unit(), 7);
    let singleton_7_ = Trie::singleton(meta.clone(), name_unit(), 7);
    let singleton_8 = Trie::singleton(meta.clone(), name_unit(), 8);
    assert_eq!(empty, empty);
    assert_eq!(singleton_7, singleton_7);
    assert_eq!(singleton_7, singleton_7_);
    assert_eq!(singleton_8, singleton_8);

    assert_ne!(empty, singleton_7);
    assert_ne!(empty, singleton_8);
    assert_ne!(singleton_7, singleton_8);
}

// Set membership is consistent after additions.
#[test]
fn test_set() {
    let e: Set<usize> = SetIntro::empty();
    assert!(!Set::mem(&e, &7));
    assert!(!Set::mem(&e, &1));
    let s = SetIntro::add(e, 7);
    let s = SetIntro::add(s, 1);
    let s = SetIntro::add(s, 8);
    println!("{:?}", s);
    assert!(Set::mem(&s, &1));
    assert!(Set::mem(&s, &7));
    assert!(Set::mem(&s, &8));
    assert!(!Set::mem(&s, &0));
}

// Order in which elements are added to sets doesn't matter.
#[test]
fn test_set_equal() {
    let e: Set<usize> = SetIntro::empty();
    let s = SetIntro::add(e, 7);
    let s = SetIntro::add(s, 1);
    let s = SetIntro::add(s, 8);

    let e: Set<usize> = SetIntro::empty();
    let t = SetIntro::add(e, 8);
    let t = SetIntro::add(t, 7);
    let t = SetIntro::add(t, 1);
    assert_eq!(s, t);
}

#[test]
fn test_set_fold() {
    let e: Set<usize> = SetIntro::empty();
    let t = SetIntro::add(e, 8);
    let t = SetIntro::add(t, 7);
    let t = SetIntro::add(t, 1);
    assert_eq!(SetElim::fold(t, 0, Rc::new(|i, acc| i + acc)), 16);
}

// The code that we want to compare/measure under naive versus DCG engines:
fn doit(v:Vec<usize>, t:Trie<usize>) -> Trie<usize> {
    v.into_iter().fold(t, |acc, i| TrieIntro::extend(name_of_usize(i), acc, i))
}

#[test]
fn test_dcg_add_dups () {
    init_dcg();
    let mut dcg = init_naive();

    let mut naive_input : Trie<usize> = SetIntro::empty();
    let mut dcg_input : Trie<usize> = SetIntro::empty();

    let mut v = Vec::new();

    for i in vec![1,1,1,1,1,2,2,2,2,2,3,3,3,3,3].iter()
    {
        assert!(engine_is_naive());
        v.push(*i);
        naive_input = doit(v.clone(), naive_input);
        let naive_output = naive_input.clone();

        use_engine(dcg);
        assert!(engine_is_dcg());
        dcg_input = doit(v.clone(), dcg_input);
        let dcg_output = dcg_input.clone();
        dcg = init_naive();

        assert_eq!(dcg_output, naive_output);
    }
}
<commit_msg>Fixing some tests<commit_after>extern crate adapton;

use std::rc::Rc;
use adapton::bitstring::BS;
use adapton::engine::*;
use adapton::trie::*;

#[test]
fn test_is_empty() {
    let meta = Meta { min_depth: 1 };
    let empty = TrieIntro::<usize>::empty(meta.clone());
    let singleton = Trie::singleton(meta.clone(), name_unit(), 7);
    assert!(Trie::<usize>::is_empty(&Trie::nil(BS {
        length: 0,
        value: 0,
    })));
    assert!(Trie::is_empty(&empty));

    assert!(!Trie::is_empty(&Trie::leaf(BS {
                                            length: 0,
                                            value: 0,
                                        },
                                        0)));
    assert!(!Trie::is_empty(&singleton));
}

#[test]
fn test_equal() {
    let meta = Meta { min_depth: 1 };
    let empty: Trie<usize> = TrieIntro::empty(meta.clone());
    let singleton_7 = Trie::singleton(meta.clone(), name_unit(), 7);
    let singleton_7_ = Trie::singleton(meta.clone(), name_unit(), 7);
    let singleton_8 = Trie::singleton(meta.clone(), name_unit(), 8);
    assert_eq!(empty, empty);
    assert_eq!(singleton_7, singleton_7);
    assert_eq!(singleton_7, singleton_7_);
    assert_eq!(singleton_8, singleton_8);

    assert_ne!(empty, singleton_7);
    assert_ne!(empty, singleton_8);
    assert_ne!(singleton_7, singleton_8);
}

// Set membership is consistent after additions.
#[test]
fn test_set() {
    let e: Set<usize> = SetIntro::empty();
    assert!(!Set::mem(&e, &7));
    assert!(!Set::mem(&e, &1));
    let s = SetIntro::add(e, 7);
    let s = SetIntro::add(s, 1);
    let s = SetIntro::add(s, 8);
    println!("{:?}", s);
    assert!(Set::mem(&s, &1));
    assert!(Set::mem(&s, &7));
    assert!(Set::mem(&s, &8));
    assert!(!Set::mem(&s, &0));
}

// Order in which elements are added to sets doesn't matter.
#[test]
fn test_set_equal() {
    let e: Set<usize> = SetIntro::empty();
    let s = SetIntro::add(e, 7);
    let s = SetIntro::add(s, 1);
    let s = SetIntro::add(s, 8);

    let e: Set<usize> = SetIntro::empty();
    let t = SetIntro::add(e, 8);
    let t = SetIntro::add(t, 7);
    let t = SetIntro::add(t, 1);
    assert_eq!(s, t);
}

fn push_input(i: usize, t: Trie<usize>) -> Trie<usize> {
    let t = Trie::art(cell(name_of_usize(i), t));
    let t = Trie::name(name_of_usize(i), t);
    Trie::extend(name_unit(), t, i)
}

#[test]
fn test_set_fold() {
    let e: Set<usize> = SetIntro::empty();
    let t = push_input(8, e);
    let t = push_input(8, t);
    assert!(SetElim::mem(&t, &8));
    let t = push_input(7, t);
    let t = push_input(1, t);
    assert_eq!(SetElim::fold(t, 0, Rc::new(|i, acc| i + acc)), 16);
}

// The code that we want to compare/measure under naive versus DCG engines:
fn doit(v:Vec<usize>, t:Trie<usize>) -> Trie<usize> {
    v.into_iter().fold(t, |acc, i| {
        let t = Trie::art(cell(name_of_usize(i), acc));
        let t = Trie::name(name_of_usize(i), t);
        Trie::extend(name_unit(), t, i)
    })
}

#[test]
fn test_dcg_add_dups () {
    init_dcg();
    let mut dcg = init_naive();

    let mut naive_input : Trie<usize> = SetIntro::empty();
    let mut dcg_input : Trie<usize> = SetIntro::empty();

    let mut v = Vec::new();

    for i in vec![1,1,1,1,1,2,2,2,2,2,3,3,3,3,3].iter()
    {
        assert!(engine_is_naive());
        v.push(*i);
        naive_input = doit(v.clone(), naive_input);
        let naive_output = naive_input.clone();

        use_engine(dcg);
        assert!(engine_is_dcg());
        dcg_input = doit(v.clone(), dcg_input);
        let dcg_output = dcg_input.clone();
        dcg = init_naive();

        assert_eq!(dcg_output, naive_output);
    }
}
<|endoftext|>


<commit_before>use crate::{
  fail::{RtErr, RtResult},
  term::{
    boxed::{BoxHeader, BoxType},
    value::{PrimaryTag, Term},
  },
};

impl Term {
  #[inline]
  pub fn make_boxed<T>(p: *const T) -> Self {
    let p_val = p as usize;
    assert_eq!(
      p_val & PrimaryTag::TAG_MASK,
      0,
      "Creating a boxed value from {:p} is only allowed for word aligned addresses, it would be 0x{:x} then",
      p,
      p_val & !PrimaryTag::TAG_MASK
    );
    Self {
      value: p_val | PrimaryTag::BOX_PTR.0,
    }
  }

  /// Check whether tag bits of a value equal to `PrimaryTag::BOX_PTR`
  #[inline]
  pub fn is_boxed(self) -> bool {
    self.get_term_tag() == PrimaryTag::BOX_PTR
  }

  /// Just raw decode value bits into a pointer, no safety checks
  #[inline]
  pub fn get_box_ptr_unchecked<T>(self) -> *const T {
    (self.value & !PrimaryTag::TAG_MASK) as *const T
  }

  /// Just raw decode value bits into a mut pointer, no safety checks
  #[inline]
  pub fn get_box_ptr_unchecked_mut<T>(self) -> *mut T {
    (self.value & !PrimaryTag::TAG_MASK) as *mut T
  }

  #[inline]
  pub fn get_box_ptr<T>(self) -> *const T {
    assert!(self.is_boxed());
    self.debug_assert_box_pointer_valid();
    self.get_box_ptr_unchecked::<T>()
  }

  #[inline]
  pub fn get_box_ptr_mut<T>(self) -> *mut T {
    assert!(self.is_boxed());
    self.debug_assert_box_pointer_valid();
    self.get_box_ptr_unchecked_mut::<T>()
  }

  pub fn get_box_ptr_safe<T>(self) -> RtResult<*const T> {
    if !self.is_boxed() {
      return Err(RtErr::TermIsNotABoxed);
    }
    self.debug_assert_box_pointer_valid();
    Ok(self.value as *const T)
  }

  #[cfg(not(debug_assertions))]
  #[inline]
  fn debug_assert_box_pointer_valid(&self) {}

  #[cfg(debug_assertions)]
  fn debug_assert_box_pointer_valid(&self) {
    // Additional check in debug, boxheader has an extra guard word stored
    let boxheader = self.get_box_ptr_unchecked::<BoxHeader>();
    unsafe { (*boxheader).ensure_valid() };
  }

  pub fn get_box_ptr_safe_mut<T>(self) -> RtResult<*mut T> {
    if !self.is_boxed() {
      return Err(RtErr::TermIsNotABoxed);
    }
    Ok(self.value as *mut T)
  }

  /// Checks boxed tag to be equal to t, also returns false if not a boxed.
  #[inline]
  pub fn is_boxed_of_type(self, t: BoxType) -> bool {
    self.is_boxed_of_(|boxtag| boxtag == t)
  }

  /// Extracts boxed tag and runs an inline predicate on its boxed tag, allows
  /// for checking multiple boxed tag values. Returns false if not a boxed.
  #[inline]
  pub fn is_boxed_of_<F>(self, pred: F) -> bool
  where
    F: Fn(BoxType) -> bool,
  {
    if !self.is_boxed() {
      return false;
    }
    let box_ptr = self.get_box_ptr::<BoxHeader>();
    let trait_ptr = unsafe { (*box_ptr).get_trait_ptr() };
    let tag = unsafe { (*trait_ptr).get_type() };
    pred(tag)
  }
}
<commit_msg>Bug in get_box_ptr_safe<commit_after>use crate::{
  fail::{RtErr, RtResult},
  term::{
    boxed::{BoxHeader, BoxType},
    value::{PrimaryTag, Term},
  },
};

impl Term {
  #[inline]
  pub fn make_boxed<T>(p: *const T) -> Self {
    let p_val = p as usize;
    assert_eq!(
      p_val & PrimaryTag::TAG_MASK,
      0,
      "Creating a boxed value from {:p} is only allowed for word aligned addresses, it would be 0x{:x} then",
      p,
      p_val & !PrimaryTag::TAG_MASK
    );
    Self {
      value: p_val | PrimaryTag::BOX_PTR.0,
    }
  }

  /// Check whether tag bits of a value equal to `PrimaryTag::BOX_PTR`
  #[inline]
  pub fn is_boxed(self) -> bool {
    self.get_term_tag() == PrimaryTag::BOX_PTR
  }

  /// Just raw decode value bits into a pointer, no safety checks
  #[inline]
  pub fn get_box_ptr_unchecked<T>(self) -> *const T {
    (self.value & !PrimaryTag::TAG_MASK) as *const T
  }

  /// Just raw decode value bits into a mut pointer, no safety checks
  #[inline]
  pub fn get_box_ptr_unchecked_mut<T>(self) -> *mut T {
    (self.value & !PrimaryTag::TAG_MASK) as *mut T
  }

  #[inline]
  pub fn get_box_ptr<T>(self) -> *const T {
    assert!(self.is_boxed());
    self.debug_assert_box_pointer_valid();
    self.get_box_ptr_unchecked::<T>()
  }

  #[inline]
  pub fn get_box_ptr_mut<T>(self) -> *mut T {
    assert!(self.is_boxed());
    self.debug_assert_box_pointer_valid();
    self.get_box_ptr_unchecked_mut::<T>()
  }

  pub fn get_box_ptr_safe<T>(self) -> RtResult<*const T> {
    if !self.is_boxed() {
      return Err(RtErr::TermIsNotABoxed);
    }
    self.debug_assert_box_pointer_valid();
    Ok(self.get_box_ptr_unchecked::<T>())
  }

  #[cfg(not(debug_assertions))]
  #[inline]
  fn debug_assert_box_pointer_valid(&self) {}

  #[cfg(debug_assertions)]
  fn debug_assert_box_pointer_valid(&self) {
    // Additional check in debug, boxheader has an extra guard word stored
    let boxheader = self.get_box_ptr_unchecked::<BoxHeader>();
    unsafe { (*boxheader).ensure_valid() };
  }

  pub fn get_box_ptr_safe_mut<T>(self) -> RtResult<*mut T> {
    if !self.is_boxed() {
      return Err(RtErr::TermIsNotABoxed);
    }
    Ok(self.value as *mut T)
  }

  /// Checks boxed tag to be equal to t, also returns false if not a boxed.
  #[inline]
  pub fn is_boxed_of_type(self, t: BoxType) -> bool {
    self.is_boxed_of_(|boxtag| boxtag == t)
  }

  /// Extracts boxed tag and runs an inline predicate on its boxed tag, allows
  /// for checking multiple boxed tag values. Returns false if not a boxed.
  #[inline]
  pub fn is_boxed_of_<F>(self, pred: F) -> bool
  where
    F: Fn(BoxType) -> bool,
  {
    if !self.is_boxed() {
      return false;
    }
    let box_ptr = self.get_box_ptr::<BoxHeader>();
    let trait_ptr = unsafe { (*box_ptr).get_trait_ptr() };
    let tag = unsafe { (*trait_ptr).get_type() };
    pred(tag)
  }
}
<|endoftext|>


<commit_before>//! This file contains tests relevant to Rustup's handling of updating PATHs.
//! It depends on self-update working, so if absolutely everything here breaks,
//! check those tests as well.
#![allow(unused)]
pub mod mock;

use crate::mock::clitools::{
    self, expect_err, expect_err_ex, expect_ok, expect_ok_contains, expect_ok_ex, expect_stderr_ok,
    expect_stdout_ok, this_host_triple, Config, Scenario,
};
use crate::mock::dist::calc_hash;
use crate::mock::{get_path, restore_path};
use lazy_static::lazy_static;
use remove_dir_all::remove_dir_all;
use rustup::utils::{raw, utils};
use rustup::Notification;
use std::env;
use std::env::consts::EXE_SUFFIX;
use std::fs;
use std::path::Path;
use std::process::Command;
use std::sync::Mutex;

macro_rules! for_host {
    ($s: expr) => {
        &format!($s, this_host_triple())
    };
}

const TEST_VERSION: &str = "1.1.1";

pub fn setup(f: &dyn Fn(&Config)) {
    clitools::setup(Scenario::SimpleV2, &|config| {
        // Lock protects environment variables
        lazy_static! {
            static ref LOCK: Mutex<()> = Mutex::new(());
        }
        let _g = LOCK.lock();

        // On windows these tests mess with the user's PATH. Save
        // and restore them here to keep from trashing things.
        let saved_path = get_path();
        let _g = scopeguard::guard(saved_path, restore_path);

        f(config);
    });
}

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

    #[test]
    fn produces_env_file_on_unix() {
        setup(&|config| {
            // Override the test harness so that cargo home looks like
            // $HOME/.cargo by removing CARGO_HOME from the environment,
            // otherwise the literal path will be written to the file.

            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env_remove("CARGO_HOME");
            assert!(cmd.output().unwrap().status.success());
            let envfile = config.homedir.join(".cargo/env.sh");
            let envfile = fs::read_to_string(&envfile).unwrap();
            let path_string = "export PATH=\"$HOME/.cargo/bin:${PATH}\"";
            let (_, envfile_export) = envfile.split_at(match envfile.find("export PATH") {
                Some(idx) => idx,
                None => 0,
            });
            assert_eq!(&envfile_export[..path_string.len()], path_string);
        });
    }

    fn install_adds_path_to_rc(rcfile: &str) {
        setup(&|config| {
            let my_rc = "foo\nbar\nbaz";
            let rc = config.homedir.join(rcfile);
            raw::write_file(&rc, my_rc).unwrap();
            expect_ok(config, &["rustup-init", "-y"]);

            let new_rc = fs::read_to_string(&rc).unwrap();
            let addition = format!("source \"{}/env.sh\"", config.cargodir.display());
            let expected = format!("{}\n{}\n", my_rc, addition);
            assert_eq!(new_rc, expected);
        });
    }

    #[test]
    fn install_adds_path_to_profile() {
        install_adds_path_to_rc(".profile");
    }

    #[test]
    fn install_adds_path_to_bashrc() {
        install_adds_path_to_rc(".bashrc");
    }

    #[test]
    fn install_adds_path_to_bash_profile() {
        install_adds_path_to_rc(".bash_profile");
    }

    #[test]
    fn install_does_not_add_path_to_bash_profile_that_doesnt_exist() {
        setup(&|config| {
            let rc = config.homedir.join(".bash_profile");
            expect_ok(config, &["rustup-init", "-y"]);

            assert!(!rc.exists());
        });
    }

    #[test]
    fn install_errors_when_rc_file_cannot_be_updated() {
        setup(&|config| {
            let rc = config.homedir.join(".bashrc");
            fs::File::create(&rc).unwrap();
            let mut perms = fs::metadata(&rc).unwrap().permissions();
            perms.set_readonly(true);
            fs::set_permissions(&rc, perms).unwrap();

            expect_err(config, &["rustup-init", "-y"], "amend shell");
        });
    }

    #[test]
    fn install_with_zsh_adds_path_to_zshenv() {
        setup(&|config| {
            let my_rc = "foo\nbar\nbaz";
            let rc = config.homedir.join(".zshenv");
            raw::write_file(&rc, my_rc).unwrap();

            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env("SHELL", "zsh");
            assert!(cmd.output().unwrap().status.success());

            let new_rc = fs::read_to_string(&rc).unwrap();
            let addition = format!(r#"source "{}/env.sh""#, config.cargodir.display());
            let expected = format!("{}\n{}\n", my_rc, addition);
            assert_eq!(new_rc, expected);
        });
    }

    #[test]
    fn install_with_zdotdir() {
        // New strategy: move all zdotdir tests into one pile
        // Move all zsh-without-zdotdir tests into the pile with bash and posix profiles
        setup(&|config| {
            let zdotdir = tempfile::Builder::new()
                .prefix("zdotdir")
                .tempdir()
                .unwrap();
            let my_rc = "foo\nbar\nbaz";
            let rc = zdotdir.path().join(".zshenv");
            let profile = zdotdir.path().join(".zprofile");
            raw::write_file(&rc, my_rc).unwrap();

            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env("SHELL", "zsh");
            cmd.env("ZDOTDIR", zdotdir.path());
            assert!(cmd.output().unwrap().status.success());

            let new_rc = fs::read_to_string(&rc).unwrap();
            let addition = format!(r#"source "{}/env.sh""#, config.cargodir.display());
            let expected = format!("{}\n{}\n", my_rc, addition);
            assert_eq!(new_rc, expected);
        });
    }

    #[test]
    fn install_adds_path_to_rcfile_just_once() {
        setup(&|config| {
            let my_profile = "foo\nbar\nbaz";
            let profile = config.homedir.join(".profile");
            raw::write_file(&profile, my_profile).unwrap();
            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup-init", "-y"]);

            let new_profile = fs::read_to_string(&profile).unwrap();
            let addition = format!(r#"source "{}/env.sh""#, config.cargodir.display());
            let expected = format!("{}\n{}\n", my_profile, addition);
            assert_eq!(new_profile, expected);
        });
    }

    fn uninstall_removes_path_from_rc(rcfile: &str) {
        setup(&|config| {
            let my_rc = "foo\nbar\nbaz";
            let rc = config.homedir.join(rcfile);
            raw::write_file(&rc, my_rc).unwrap();
            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            let new_rc = fs::read_to_string(&rc).unwrap();
            assert_eq!(new_rc, my_rc);
        });
    }

    #[test]
    fn uninstall_removes_path_from_profile() {
        uninstall_removes_path_from_rc(".profile");
    }

    #[test]
    fn uninstall_removes_path_from_bashrc() {
        uninstall_removes_path_from_rc(".bashrc");
    }

    #[test]
    fn uninstall_removes_path_from_bash_profile() {
        uninstall_removes_path_from_rc(".bash_profile");
    }

    #[test]
    fn uninstall_removes_path_from_zshenv() {
        uninstall_removes_path_from_rc(".zshenv");
    }

    #[test]
    fn uninstall_doesnt_touch_rc_files_that_dont_contain_cargo_home() {
        setup(&|config| {
            let my_rc = "foo\nbar\nbaz";
            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            let profile = config.homedir.join(".profile");
            raw::write_file(&profile, my_rc).unwrap();

            let profile = fs::read_to_string(&profile).unwrap();

            assert_eq!(profile, my_rc);
        });
    }

    // In the default case we want to write $HOME/.cargo/bin as the path,
    // not the full path.
    #[test]
    fn when_cargo_home_is_the_default_write_path_specially() {
        setup(&|config| {
            // Override the test harness so that cargo home looks like
            // $HOME/.cargo by removing CARGO_HOME from the environment,
            // otherwise the literal path will be written to the file.

            let my_profile = "foo\nbar\nbaz";
            let profile = config.homedir.join(".profile");
            raw::write_file(&profile, my_profile).unwrap();
            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env_remove("CARGO_HOME");
            assert!(cmd.output().unwrap().status.success());

            let new_profile = fs::read_to_string(&profile).unwrap();
            let expected = format!("{}\nsource \"$HOME/.cargo/env.sh\"\n", my_profile);
            assert_eq!(new_profile, expected);

            let mut cmd = clitools::cmd(config, "rustup", &["self", "uninstall", "-y"]);
            cmd.env_remove("CARGO_HOME");
            assert!(cmd.output().unwrap().status.success());

            let new_profile = fs::read_to_string(&profile).unwrap();
            assert_eq!(new_profile, my_profile);
        });
    }

    #[test]
    fn install_doesnt_modify_path_if_passed_no_modify_path() {
        setup(&|config| {
            let profile = config.homedir.join(".profile");
            expect_ok(config, &["rustup-init", "-y", "--no-modify-path"]);
            assert!(!profile.exists());
        });
    }
}

#[cfg(windows)]
mod windows {

    use super::*;

    #[test]
    fn install_doesnt_modify_path_if_passed_no_modify_path() {
        use winreg::enums::{HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
        use winreg::RegKey;

        setup(&|config| {
            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let old_path = environment.get_raw_value("PATH").unwrap();

            expect_ok(config, &["rustup-init", "-y", "--no-modify-path"]);

            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let new_path = environment.get_raw_value("PATH").unwrap();

            assert_eq!(old_path, new_path);
        });
    }

    // HKCU\Environment\PATH may not exist during install, and it may need to be
    // deleted during uninstall if we remove the last path from it
    #[test]
    fn windows_handle_empty_path_registry_key() {
        use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
        use winreg::RegKey;

        setup(&|config| {
            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let _ = environment.delete_value("PATH");

            expect_ok(config, &["rustup-init", "-y"]);

            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let path = environment.get_raw_value("PATH").unwrap();
            assert!(path.vtype == RegType::REG_EXPAND_SZ);

            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let path = environment.get_raw_value("PATH");

            assert!(path.is_err());
        });
    }

    #[test]
    fn uninstall_removes_path() {
        setup(&|config| {
            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            let path = config.cargodir.join("bin").to_string_lossy().to_string();
            assert!(!get_path().unwrap().contains(&path));
        });
    }

    #[test]
    fn install_adds_path() {
        setup(&|config| {
            expect_ok(config, &["rustup-init", "-y"]);

            let path = config.cargodir.join("bin").to_string_lossy().to_string();
            assert!(
                get_path().unwrap().contains(&path),
                format!("`{}` not in `{}`", get_path().unwrap(), &path)
            );
        });
    }
}
<commit_msg>Adds testing for cleaning up legacy paths<commit_after>//! This file contains tests relevant to Rustup's handling of updating PATHs.
//! It depends on self-update working, so if absolutely everything here breaks,
//! check those tests as well.
#![allow(unused)]
pub mod mock;

use crate::mock::clitools::{
    self, expect_err, expect_err_ex, expect_ok, expect_ok_contains, expect_ok_ex, expect_stderr_ok,
    expect_stdout_ok, this_host_triple, Config, Scenario,
};
use crate::mock::dist::calc_hash;
use crate::mock::{get_path, restore_path};
use lazy_static::lazy_static;
use remove_dir_all::remove_dir_all;
use rustup::utils::{raw, utils};
use rustup::Notification;
use std::env;
use std::env::consts::EXE_SUFFIX;
use std::fmt::Display;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Mutex;

macro_rules! for_host {
    ($s: expr) => {
        &format!($s, this_host_triple())
    };
}

const TEST_VERSION: &str = "1.1.1";

pub fn setup(f: &dyn Fn(&Config)) {
    clitools::setup(Scenario::SimpleV2, &|config| {
        // Lock protects environment variables
        lazy_static! {
            static ref LOCK: Mutex<()> = Mutex::new(());
        }
        let _g = LOCK.lock();

        // On windows these tests mess with the user's PATH. Save
        // and restore them here to keep from trashing things.
        let saved_path = get_path();
        let _g = scopeguard::guard(saved_path, restore_path);

        f(config);
    });
}

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

    // Let's write a fake .rc which looks vaguely like a real script.
    const FAKE_RC: &str = r#"
# Sources fruity punch.
source ~/fruit/punch

# Adds apples to PATH.
export PATH="$HOME/apple/bin"
"#;

    const DEFAULT_EXPORT: &str = "export PATH=\"$HOME/.cargo/bin:${PATH}\"";
    const POSIX_SH: &str = "env.sh";

    // let my_rc = "foo\nbar\nbaz";
    // let rc = config.homedir.join(".zshenv");
    // raw::write_file(&rc, my_rc).unwrap();

    fn source(dir: impl Display, sh: impl Display) -> String {
        format!("source \"{dir}/{sh}\"", dir = dir, sh = sh)
    }

    fn cat(rc: impl Display, plus: impl Display) -> String {
        format!("{}\n{}\n", rc, plus)
    }

    #[test]
    fn install_writes_env_and_profile() {
        setup(&|config| {
            // Override the test harness so that cargo home looks like
            // $HOME/.cargo by removing CARGO_HOME from the environment,
            // otherwise the literal path will be written to the file.

            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            let envfile = config.homedir.join(".cargo/env.sh");
            let profile = config.homedir.join(".profile");
            assert!(!envfile.exists());
            assert!(!profile.exists());
            cmd.env_remove("CARGO_HOME");
            assert!(cmd.output().unwrap().status.success());
            let envfile = fs::read_to_string(&envfile).unwrap();
            let (_, envfile_export) = envfile.split_at(match envfile.find("export PATH") {
                Some(idx) => idx,
                None => 0,
            });
            assert_eq!(&envfile_export[..DEFAULT_EXPORT.len()], DEFAULT_EXPORT);

            let mut expected = format!("\n{}\n", source("$HOME/.cargo", POSIX_SH));
            let new_profile = fs::read_to_string(&profile).unwrap();
            assert_eq!(new_profile, expected);
        });
    }

    #[test]
    fn install_updates_bash_rcs() {
        setup(&|config| {
            let rcs: Vec<PathBuf> = [".bashrc", ".bash_profile", ".bash_login", ".profile"]
                .iter()
                .map(|rc| config.homedir.join(rc))
                .collect();
            for rc in &rcs {
                raw::write_file(&rc, FAKE_RC).unwrap();
            }

            expect_ok(config, &["rustup-init", "-y"]);

            let expected = cat(FAKE_RC, source(config.cargodir.display(), POSIX_SH));
            for rc in &rcs {
                let new_rc = fs::read_to_string(&rc).unwrap();
                assert_eq!(new_rc, expected);
            }
        })
    }

    #[test]
    fn install_does_not_create_bash_rcs() {
        setup(&|config| {
            let rcs: Vec<PathBuf> = [".bashrc", ".bash_profile", ".bash_login"]
                .iter()
                .map(|rc| config.homedir.join(rc))
                .collect();
            let rcs_before = rcs.iter().map(|rc| rc.exists());
            expect_ok(config, &["rustup-init", "-y"]);

            for (before, after) in rcs_before.zip(rcs.iter().map(|rc| rc.exists())) {
                assert!(before == false);
                assert_eq!(before, after);
            }
        });
    }

    #[test]
    fn install_errors_when_rc_cannot_be_updated() {
        setup(&|config| {
            let rc = config.homedir.join(".profile");
            fs::File::create(&rc).unwrap();
            let mut perms = fs::metadata(&rc).unwrap().permissions();
            perms.set_readonly(true);
            fs::set_permissions(&rc, perms).unwrap();

            expect_err(config, &["rustup-init", "-y"], "amend shell");
        });
    }

    #[test]
    fn install_with_zsh_creates_zshenv() {
        setup(&|config| {
            let rc = config.homedir.join(".zshenv");
            raw::write_file(&rc, FAKE_RC).unwrap();

            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env("SHELL", "zsh");
            assert!(cmd.output().unwrap().status.success());

            let new_rc = fs::read_to_string(&rc).unwrap();
            let addition = format!(r#"source "{}/env.sh""#, config.cargodir.display());
            let expected = format!("{}\n{}\n", FAKE_RC, addition);
            assert_eq!(new_rc, expected);
        });
    }

    #[test]
    fn install_with_zdotdir() {
        setup(&|config| {
            let zdotdir = tempfile::Builder::new()
                .prefix("zdotdir")
                .tempdir()
                .unwrap();
            let my_rc = "foo\nbar\nbaz";
            let rc = zdotdir.path().join(".zshenv");
            raw::write_file(&rc, my_rc).unwrap();

            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env("SHELL", "zsh");
            cmd.env("ZDOTDIR", zdotdir.path());
            assert!(cmd.output().unwrap().status.success());

            let new_rc = fs::read_to_string(&rc).unwrap();
            let addition = format!(r#"source "{}/env.sh""#, config.cargodir.display());
            let expected = format!("{}\n{}\n", my_rc, addition);
            assert_eq!(new_rc, expected);
        });
    }

    #[test]
    fn install_adds_path_to_rc_just_once() {
        setup(&|config| {
            let my_profile = "foo\nbar\nbaz";
            let profile = config.homedir.join(".profile");
            raw::write_file(&profile, my_profile).unwrap();
            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup-init", "-y"]);

            let new_profile = fs::read_to_string(&profile).unwrap();
            let addition = format!(r#"source "{}/env.sh""#, config.cargodir.display());
            let expected = format!("{}\n{}\n", my_profile, addition);
            assert_eq!(new_profile, expected);
        });
    }

    #[test]
    fn uninstall_removes_source_from_bash_rcs() {
        setup(&|config| {
            let rcs: Vec<PathBuf> = [".bashrc", ".bash_profile", ".bash_login", ".profile"]
                .iter()
                .map(|rc| config.homedir.join(rc))
                .collect();
            for rc in &rcs {
                raw::write_file(&rc, FAKE_RC).unwrap();
            }

            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            for rc in &rcs {
                let new_rc = fs::read_to_string(&rc).unwrap();
                assert_eq!(new_rc, FAKE_RC);
            }
        })
    }

    fn uninstall_removes_path_from_rc(rcfile: &str) {
        setup(&|config| {
            let my_rc = "foo\nbar\nbaz";
            let rc = config.homedir.join(rcfile);
            raw::write_file(&rc, my_rc).unwrap();
            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            let new_rc = fs::read_to_string(&rc).unwrap();
            assert_eq!(new_rc, my_rc);
        });
    }

    #[test]
    fn uninstall_removes_source_from_zshenv() {
        uninstall_removes_path_from_rc(".zshenv");
    }

    #[test]
    fn install_cleans_up_legacy_paths() {
        setup(&|config| {
            let zdotdir = tempfile::Builder::new()
                .prefix("zdotdir")
                .tempdir()
                .unwrap();
            let mut rcs: Vec<PathBuf> = [".bash_profile", ".profile"]
                .iter()
                .map(|rc| config.homedir.join(rc))
                .collect();
            let mut zprofiles = vec![config.homedir.join(".zprofile")];
            zprofiles.push(zdotdir.path().join(".zprofile"));
            let old_rc = cat(FAKE_RC, DEFAULT_EXPORT);
            for rc in rcs.iter().chain(zprofiles.iter()) {
                raw::write_file(&rc, FAKE_RC).unwrap();
            }

            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env("SHELL", "zsh");
            cmd.env("ZDOTDIR", zdotdir.path());
            assert!(cmd.output().unwrap().status.success());
            let fixed_rc = cat(FAKE_RC, source(config.cargodir.display(), POSIX_SH));
            for rc in &rcs {
                let new_rc = fs::read_to_string(&rc).unwrap();
                assert_eq!(new_rc, fixed_rc);
            }
            for rc in &zprofiles {
                let new_rc = fs::read_to_string(&rc).unwrap();
                assert_eq!(new_rc, FAKE_RC);
            }
        })
    }

    #[test]
    fn uninstall_cleans_up_legacy_paths() {
        setup(&|config| {
            // Install first, then overwrite.
            expect_ok(config, &["rustup-init", "-y"]);

            let zdotdir = tempfile::Builder::new()
                .prefix("zdotdir")
                .tempdir()
                .unwrap();
            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env("SHELL", "zsh");
            cmd.env("ZDOTDIR", zdotdir.path());
            assert!(cmd.output().unwrap().status.success());
            let mut rcs: Vec<PathBuf> = [".bash_profile", ".profile", ".zprofile"]
                .iter()
                .map(|rc| config.homedir.join(rc))
                .collect();
            rcs.push(zdotdir.path().join(".zprofile"));
            let old_rc = cat(FAKE_RC, DEFAULT_EXPORT);
            for rc in &rcs {
                raw::write_file(&rc, FAKE_RC).unwrap();
            }

            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);
            for rc in &rcs {
                let new_rc = fs::read_to_string(&rc).unwrap();
                assert_eq!(new_rc, FAKE_RC);
            }
        })
    }

    // This test seems confusing and might not do what it's supposed to?
    #[test]
    fn uninstall_doesnt_touch_rc_files_that_dont_contain_cargo_home() {
        setup(&|config| {
            let my_rc = "foo\nbar\nbaz";
            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            let profile = config.homedir.join(".profile");
            raw::write_file(&profile, my_rc).unwrap();

            let profile = fs::read_to_string(&profile).unwrap();

            assert_eq!(profile, my_rc);
        });
    }

    // In the default case we want to write $HOME/.cargo/bin as the path,
    // not the full path.
    #[test]
    fn when_cargo_home_is_the_default_write_path_specially() {
        setup(&|config| {
            // Override the test harness so that cargo home looks like
            // $HOME/.cargo by removing CARGO_HOME from the environment,
            // otherwise the literal path will be written to the file.

            let my_profile = "foo\nbar\nbaz";
            let profile = config.homedir.join(".profile");
            raw::write_file(&profile, my_profile).unwrap();
            let mut cmd = clitools::cmd(config, "rustup-init", &["-y"]);
            cmd.env_remove("CARGO_HOME");
            assert!(cmd.output().unwrap().status.success());

            let new_profile = fs::read_to_string(&profile).unwrap();
            let expected = format!("{}\nsource \"$HOME/.cargo/env.sh\"\n", my_profile);
            assert_eq!(new_profile, expected);

            let mut cmd = clitools::cmd(config, "rustup", &["self", "uninstall", "-y"]);
            cmd.env_remove("CARGO_HOME");
            assert!(cmd.output().unwrap().status.success());

            let new_profile = fs::read_to_string(&profile).unwrap();
            assert_eq!(new_profile, my_profile);
        });
    }

    #[test]
    fn install_doesnt_modify_path_if_passed_no_modify_path() {
        setup(&|config| {
            let profile = config.homedir.join(".profile");
            expect_ok(config, &["rustup-init", "-y", "--no-modify-path"]);
            assert!(!profile.exists());
        });
    }
}

#[cfg(windows)]
mod windows {

    use super::*;

    #[test]
    fn install_doesnt_modify_path_if_passed_no_modify_path() {
        use winreg::enums::{HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
        use winreg::RegKey;

        setup(&|config| {
            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let old_path = environment.get_raw_value("PATH").unwrap();

            expect_ok(config, &["rustup-init", "-y", "--no-modify-path"]);

            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let new_path = environment.get_raw_value("PATH").unwrap();

            assert_eq!(old_path, new_path);
        });
    }

    // HKCU\Environment\PATH may not exist during install, and it may need to be
    // deleted during uninstall if we remove the last path from it
    #[test]
    fn windows_handle_empty_path_registry_key() {
        use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};
        use winreg::RegKey;

        setup(&|config| {
            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let _ = environment.delete_value("PATH");

            expect_ok(config, &["rustup-init", "-y"]);

            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let path = environment.get_raw_value("PATH").unwrap();
            assert!(path.vtype == RegType::REG_EXPAND_SZ);

            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            let root = RegKey::predef(HKEY_CURRENT_USER);
            let environment = root
                .open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
                .unwrap();
            let path = environment.get_raw_value("PATH");

            assert!(path.is_err());
        });
    }

    #[test]
    fn uninstall_removes_path() {
        setup(&|config| {
            expect_ok(config, &["rustup-init", "-y"]);
            expect_ok(config, &["rustup", "self", "uninstall", "-y"]);

            let path = config.cargodir.join("bin").to_string_lossy().to_string();
            assert!(!get_path().unwrap().contains(&path));
        });
    }

    #[test]
    fn install_adds_path() {
        setup(&|config| {
            expect_ok(config, &["rustup-init", "-y"]);

            let path = config.cargodir.join("bin").to_string_lossy().to_string();
            assert!(
                get_path().unwrap().contains(&path),
                format!("`{}` not in `{}`", get_path().unwrap(), &path)
            );
        });
    }
}
<|endoftext|>


<commit_before>//! CPU usage monitor

#![feature(const_fn)]
#![feature(used)]
#![no_std]

// version = "0.2.9"
#[macro_use]
extern crate cortex_m;

// version = "0.2.4"
extern crate cortex_m_rt;

// version = "0.1.0"
#[macro_use]
extern crate cortex_m_rtfm as rtfm;

extern crate blue_pill;

use core::cell::Cell;

use blue_pill::stm32f103xx;
use blue_pill::timer::Timer;
use rtfm::{C1, P0, P1, Resource, T0, T1, TMax};
use stm32f103xx::interrupt::Tim1UpTim10;

// CONFIGURATION
const FREQUENCY: u32 = 1; // Hz

// RESOURCES
peripherals!(stm32f103xx, {
    DWT: Peripheral {
        register_block: Dwt,
        ceiling: C0,
    },
    ITM: Peripheral {
        register_block: Itm,
        ceiling: C1,
    },
    RCC: Peripheral {
        register_block: Rcc,
        ceiling: C0,
    },
    TIM1: Peripheral {
        register_block: Tim1,
        ceiling: C1,
    },
});

static SLEEP_CYCLES: Resource<Cell<u32>, C1> = Resource::new(Cell::new(0));

// INITIALIZATION PHASE
fn init(ref prio: P0, thr: &TMax) {
    let dwt = &DWT.access(prio, thr);
    let rcc = &RCC.access(prio, thr);
    let tim1 = &TIM1.access(prio, thr);

    let timer = Timer(tim1);

    dwt.enable_cycle_counter();

    timer.init(FREQUENCY, rcc);
    timer.resume();
}

// IDLE LOOP
fn idle(ref prio: P0, _thr: T0) -> ! {
    // Sleep
    loop {
        rtfm::atomic(|thr| {
            let dwt = DWT.access(prio, thr);
            let sleep_cycles = SLEEP_CYCLES.access(prio, thr);

            let before = dwt.cyccnt.read();
            rtfm::wfi();
            let after = dwt.cyccnt.read();

            let elapsed = after.wrapping_sub(before);

            sleep_cycles.set(sleep_cycles.get() + elapsed);
        });

        // Tasks are serviced here
    }
}

// TASKS
tasks!(stm32f103xx, {
    periodic: Task {
        interrupt: Tim1UpTim10,
        priority: P1,
        enabled: true,
    },
});

fn periodic(_task: Tim1UpTim10, ref prio: P1, ref thr: T1) {
    let tim1 = &TIM1.access(prio, thr);
    let itm = ITM.access(prio, thr);
    let sleep_cycles = SLEEP_CYCLES.access(prio, thr);

    let timer = Timer(tim1);

    if timer.clear_update_flag().is_ok() {
        // Report clock cycles spent sleeping
        iprintln!(&itm.stim[0], "{}", sleep_cycles.get());

        // Reset sleep cycle counter to zero
        sleep_cycles.set(0);
    } else {
        // Only reachable via `rtfm::request(periodic)`
        unreachable!()
    }
}
<commit_msg>tweak comments in the cpu usage monitor example<commit_after>//! CPU usage monitor

#![feature(const_fn)]
#![feature(used)]
#![no_std]

// version = "0.2.9"
#[macro_use]
extern crate cortex_m;

// version = "0.2.4"
extern crate cortex_m_rt;

// version = "0.1.0"
#[macro_use]
extern crate cortex_m_rtfm as rtfm;

extern crate blue_pill;

use core::cell::Cell;

use blue_pill::stm32f103xx;
use blue_pill::timer::Timer;
use rtfm::{C1, P0, P1, Resource, T0, T1, TMax};
use stm32f103xx::interrupt::Tim1UpTim10;

// CONFIGURATION
const FREQUENCY: u32 = 1; // Hz

// RESOURCES
peripherals!(stm32f103xx, {
    DWT: Peripheral {
        register_block: Dwt,
        ceiling: C0,
    },
    ITM: Peripheral {
        register_block: Itm,
        ceiling: C1,
    },
    RCC: Peripheral {
        register_block: Rcc,
        ceiling: C0,
    },
    TIM1: Peripheral {
        register_block: Tim1,
        ceiling: C1,
    },
});

// Counter of sleep cycles
static SLEEP_CYCLES: Resource<Cell<u32>, C1> = Resource::new(Cell::new(0));

// INITIALIZATION PHASE
fn init(ref prio: P0, thr: &TMax) {
    let dwt = &DWT.access(prio, thr);
    let rcc = &RCC.access(prio, thr);
    let tim1 = &TIM1.access(prio, thr);

    let timer = Timer(tim1);

    dwt.enable_cycle_counter();

    timer.init(FREQUENCY, rcc);
    timer.resume();
}

// IDLE LOOP
fn idle(ref prio: P0, _thr: T0) -> ! {
    loop {
        rtfm::atomic(|thr| {
            let dwt = DWT.access(prio, thr);
            let sleep_cycles = SLEEP_CYCLES.access(prio, thr);

            // Sleep
            let before = dwt.cyccnt.read();
            rtfm::wfi();
            let after = dwt.cyccnt.read();

            let elapsed = after.wrapping_sub(before);

            // Accumulate sleep cycles
            sleep_cycles.set(sleep_cycles.get() + elapsed);
        });

        // Tasks are serviced here
    }
}

// TASKS
tasks!(stm32f103xx, {
    periodic: Task {
        interrupt: Tim1UpTim10,
        priority: P1,
        enabled: true,
    },
});

fn periodic(_task: Tim1UpTim10, ref prio: P1, ref thr: T1) {
    let tim1 = &TIM1.access(prio, thr);
    let itm = ITM.access(prio, thr);
    let sleep_cycles = SLEEP_CYCLES.access(prio, thr);

    let timer = Timer(tim1);

    if timer.clear_update_flag().is_ok() {
        // Report clock cycles spent sleeping
        iprintln!(&itm.stim[0], "{}", sleep_cycles.get());

        // Reset sleep cycle counter to zero
        sleep_cycles.set(0);
    } else {
        // Only reachable via `rtfm::request(periodic)`
        unreachable!()
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use std::hash::Hash;
use std::mem;
use rand::{Rng, SeedableRng, StdRng};

use timely::dataflow::*;
use timely::dataflow::operators::*;

use differential_dataflow::Collection;
use differential_dataflow::operators::*;
use differential_dataflow::operators::group::{GroupUnsigned};
use differential_dataflow::operators::join::{JoinUnsigned};
use differential_dataflow::collection::LeastUpperBound;

type Node = u32;
type Edge = (Node, Node);

fn main() {

    let nodes: u32 = std::env::args().nth(1).unwrap().parse().unwrap();
    let edges: u32 = std::env::args().nth(2).unwrap().parse().unwrap();

    timely::execute_from_args(std::env::args().skip(3), move |computation| {

        let start = time::precise_time_s();
        let start2 = start.clone();

        let mut input = computation.scoped::<u64,_,_>(|scope| {

            let (input, edges) = scope.new_input();
            let mut edges = Collection::new(edges);

            edges = _trim_and_flip(&edges);
            edges = _trim_and_flip(&edges);
            // edges.inspect(|x| println!("edge: {:?}", x.0));
            edges = _strongly_connected(&edges);

            let mut counter = 0;
            edges.consolidate_by(|x| x.0)
                 .inspect_batch(move |t, x| {
                     counter += x.len();
                     println!("{}s:\tobserved at {:?}: {:?} changes",
                              ((time::precise_time_s() - start2)) - (t.inner as f64),
                              t, counter)
                 });

            input
        });

        if computation.index() == 0 {

            println!("determining SCC of {} nodes, {} edges:", nodes, edges);

            let seed: &[_] = &[1, 2, 3, 4];
            let mut rng1: StdRng = SeedableRng::from_seed(seed);
            let mut rng2: StdRng = SeedableRng::from_seed(seed);

            rng1.gen::<f64>();
            rng2.gen::<f64>();

            for index in 0..edges {
                let edge = (rng1.gen_range(0, nodes), rng1.gen_range(0, nodes));
                // println!("edge: {:?}", edge);
                input.send((edge, 1));
                if (index % (1 << 12)) == 0 {
                    computation.step();
                }
            }

            println!("input ingested after {}", time::precise_time_s() - start);

            // while computation.step() {
            //     if time::precise_time_s() - start >= *input.epoch() as f64 {
            //         let change_count = 1;
            //         for _ in 0..change_count {
            //             input.give(((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), 1));
            //             input.give(((rng2.gen_range(0, nodes), rng2.gen_range(0, nodes)),-1));
            //         }
            //         let next_epoch = *input.epoch() + 1;
            //         input.advance_to(next_epoch);
            //     }
            // }
        }

        input.close();
    });
}

fn _trim_and_flip<G: Scope>(graph: &Collection<G, Edge>) -> Collection<G, Edge>
where G::Timestamp: LeastUpperBound {
    graph.iterate(|edges| {
        let inner = graph.enter(&edges.scope())
                         .map_in_place(|x| mem::swap(&mut x.0, &mut x.1));

        edges.map(|(x,_)| x)
             .threshold(|&x| x, |i| (Vec::new(), i), |_,_| 1)
             .map(|x| (x,()))
             .join_map_u(&inner, |&d,_,&s| (s,d))
    })
    .map_in_place(|x| mem::swap(&mut x.0, &mut x.1))
    // .inspect_batch(|t,_x| println!("observed edges at {:?}", t))
}

fn _strongly_connected<G: Scope>(graph: &Collection<G, Edge>) -> Collection<G, Edge>
where G::Timestamp: LeastUpperBound+Hash {
    graph.iterate(|inner| {
        let edges = graph.enter(&inner.scope());
        let trans = edges.map_in_place(|x| mem::swap(&mut x.0, &mut x.1));
        _trim_edges(&_trim_edges(inner, &edges), &trans)
    })
}

fn _trim_edges<G: Scope>(cycle: &Collection<G, Edge>, edges: &Collection<G, Edge>)
    -> Collection<G, Edge> where G::Timestamp: LeastUpperBound+Hash {

    let nodes = edges.map_in_place(|x| x.0 = x.1)
                     .consolidate_by(|&x| x.0);

    let labels = _reachability(&cycle, &nodes);

    edges.join_map_u(&labels, |&e1,&e2,&l1| (e2,(e1,l1)))
         .join_map_u(&labels, |&e2,&(e1,l1),&l2| ((e1,e2),(l1,l2)))
         .filter(|&(_,(l1,l2))| l1 == l2)
         .map(|((x1,x2),_)| (x2,x1))
}

fn _reachability<G: Scope>(edges: &Collection<G, Edge>, nodes: &Collection<G, (Node, Node)>) -> Collection<G, Edge>
where G::Timestamp: LeastUpperBound+Hash {

    edges.filter(|_| false)
         .iterate(|inner| {
             let edges = edges.enter(&inner.scope());
             let nodes = nodes.enter_at(&inner.scope(), |r| 256 * (64 - ((r.0).0 as u64).leading_zeros() as u64));

             inner.join_map_u(&edges, |_k,l,d| (*d,*l))
                  .concat(&nodes)
                  .group_u(|_, mut s, t| t.push((*s.peek().unwrap().0, 1)))
         })
}<commit_msg>scc tidying<commit_after>extern crate rand;
extern crate time;
extern crate timely;
extern crate differential_dataflow;

use std::hash::Hash;
use std::mem;
use rand::{Rng, SeedableRng, StdRng};

use timely::dataflow::*;
use timely::dataflow::operators::*;

use differential_dataflow::Collection;
use differential_dataflow::operators::*;
use differential_dataflow::operators::group::{GroupUnsigned};
use differential_dataflow::operators::join::{JoinUnsigned};
use differential_dataflow::collection::LeastUpperBound;

type Node = u32;
type Edge = (Node, Node);

fn main() {

    let nodes: u32 = std::env::args().nth(1).unwrap().parse().unwrap();
    let edges: u32 = std::env::args().nth(2).unwrap().parse().unwrap();

    timely::execute_from_args(std::env::args().skip(3), move |computation| {

        let start = time::precise_time_s();
        let start2 = start.clone();

        let mut input = computation.scoped::<u64,_,_>(|scope| {

            let (input, edges) = scope.new_input();
            let mut edges = Collection::new(edges);

            edges = _trim_and_flip(&edges);
            edges = _trim_and_flip(&edges);
            edges = _strongly_connected(&edges);

            let mut counter = 0;
            edges.consolidate_by(|x| x.0)
                 .inspect_batch(move |t, x| {
                     counter += x.len();
                     println!("{}s:\tobserved at {:?}: {:?} changes",
                              ((time::precise_time_s() - start2)) - (t.inner as f64),
                              t, counter)
                 });

            input
        });

        if computation.index() == 0 {

            println!("determining SCC of {} nodes, {} edges:", nodes, edges);

            let seed: &[_] = &[1, 2, 3, 4];
            let mut rng1: StdRng = SeedableRng::from_seed(seed);
            let mut rng2: StdRng = SeedableRng::from_seed(seed);

            rng1.gen::<f64>();
            rng2.gen::<f64>();

            for index in 0..edges {
                let edge = (rng1.gen_range(0, nodes), rng1.gen_range(0, nodes));
                input.send((edge, 1));
                if (index % (1 << 12)) == 0 {
                    computation.step();
                }
            }

            println!("input ingested after {}", time::precise_time_s() - start);

            // while computation.step() {
            //     if time::precise_time_s() - start >= *input.epoch() as f64 {
            //         let change_count = 1;
            //         for _ in 0..change_count {
            //             input.give(((rng1.gen_range(0, nodes), rng1.gen_range(0, nodes)), 1));
            //             input.give(((rng2.gen_range(0, nodes), rng2.gen_range(0, nodes)),-1));
            //         }
            //         let next_epoch = *input.epoch() + 1;
            //         input.advance_to(next_epoch);
            //     }
            // }
        }

        input.close();
    });
}

fn _trim_and_flip<G: Scope>(graph: &Collection<G, Edge>) -> Collection<G, Edge>
where G::Timestamp: LeastUpperBound {
    graph.iterate(|edges| {
        let inner = graph.enter(&edges.scope())
                         .map_in_place(|x| mem::swap(&mut x.0, &mut x.1));

        edges.map(|(x,_)| x)
             .threshold(|&x| x, |i| (Vec::new(), i), |_,_| 1)
             .map(|x| (x,()))
             .join_map_u(&inner, |&d,_,&s| (s,d))
    })
    .map_in_place(|x| mem::swap(&mut x.0, &mut x.1))
}

fn _strongly_connected<G: Scope>(graph: &Collection<G, Edge>) -> Collection<G, Edge>
where G::Timestamp: LeastUpperBound+Hash {
    graph.iterate(|inner| {
        let edges = graph.enter(&inner.scope());
        let trans = edges.map_in_place(|x| mem::swap(&mut x.0, &mut x.1));
        _trim_edges(&_trim_edges(inner, &edges), &trans)
    })
}

fn _trim_edges<G: Scope>(cycle: &Collection<G, Edge>, edges: &Collection<G, Edge>)
    -> Collection<G, Edge> where G::Timestamp: LeastUpperBound+Hash {

    let nodes = edges.map_in_place(|x| x.0 = x.1)
                     .consolidate_by(|&x| x.0);

    let labels = _reachability(&cycle, &nodes);

    edges.join_map_u(&labels, |&e1,&e2,&l1| (e2,(e1,l1)))
         .join_map_u(&labels, |&e2,&(e1,l1),&l2| ((e1,e2),(l1,l2)))
         .filter(|&(_,(l1,l2))| l1 == l2)
         .map(|((x1,x2),_)| (x2,x1))
}

fn _reachability<G: Scope>(edges: &Collection<G, Edge>, nodes: &Collection<G, (Node, Node)>) -> Collection<G, Edge>
where G::Timestamp: LeastUpperBound+Hash {

    edges.filter(|_| false)
         .iterate(|inner| {
             let edges = edges.enter(&inner.scope());
             let nodes = nodes.enter_at(&inner.scope(), |r| 256 * (64 - ((r.0).0 as u64).leading_zeros() as u64));

             inner.join_map_u(&edges, |_k,l,d| (*d,*l))
                  .concat(&nodes)
                  .group_u(|_, mut s, t| t.push((*s.peek().unwrap().0, 1)))
         })
}<|endoftext|>


<commit_before><commit_msg>Add basic tests for the PrintAction struct<commit_after><|endoftext|>