<commit_before>//! # Sampler
use crate::api;

/// Sampling options
#[derive(Clone, Debug)]
pub enum Sampler {
    /// Always sample the trace
    AlwaysOn,
    /// Never sample the trace
    AlwaysOff,
    /// Respects the parent span's sampling decision or delegates a delegate sampler for root spans.
    ParentOrElse(Box<Sampler>),
    /// Sample a given fraction of traces. Fractions >= 1 will always sample. If the parent span is
    /// sampled, then it's child spans will automatically be sampled. Fractions < 0 are treated as
    /// zero, but spans may still be sampled if their parent is.
    Probability(f64),
}

impl api::Sampler for Sampler {
    fn should_sample(
        &self,
        parent_context: Option<&api::SpanContext>,
        trace_id: api::TraceId,
        name: &str,
        span_kind: &api::SpanKind,
        attributes: &[api::KeyValue],
        links: &[api::Link],
    ) -> api::SamplingResult {
        let decision = match self {
            // Always sample the trace
            Sampler::AlwaysOn => api::SamplingDecision::RecordAndSampled,
            // Never sample the trace
            Sampler::AlwaysOff => api::SamplingDecision::NotRecord,
            // The parent decision if sampled; otherwise the decision of delegate_sampler
            Sampler::ParentOrElse(delegate_sampler) => parent_context.map_or(
                delegate_sampler
                    .should_sample(parent_context, trace_id, name, span_kind, attributes, links)
                    .decision,
                |ctx| {
                    if ctx.is_sampled() {
                        api::SamplingDecision::RecordAndSampled
                    } else {
                        api::SamplingDecision::NotRecord
                    }
                },
            ),
            // Match parent or probabilistically sample the trace.
            Sampler::Probability(prob) => {
                if *prob >= 1.0 || parent_context.map(|ctx| ctx.is_sampled()).unwrap_or(false) {
                    api::SamplingDecision::RecordAndSampled
                } else {
                    let prob_upper_bound = (prob.max(0.0) * (1u64 << 63) as f64) as u64;
                    // The trace_id is already randomly generated, so we don't need a new one here
                    let rnd_from_trace_id = (trace_id.to_u128() as u64) >> 1;

                    if rnd_from_trace_id < prob_upper_bound {
                        api::SamplingDecision::RecordAndSampled
                    } else {
                        api::SamplingDecision::NotRecord
                    }
                }
            }
        };

        api::SamplingResult {
            decision,
            // No extra attributes ever set by the SDK samplers.
            attributes: Vec::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::api::{self, Sampler as _};
    use crate::sdk::Sampler;
    use rand::Rng;

    #[rustfmt::skip]
    fn sampler_data() -> Vec<(&'static str, Sampler, f64, bool, bool)> {
        vec![
            // Span w/o a parent
            ("never_sample", Sampler::AlwaysOff, 0.0, false, false),
            ("always_sample", Sampler::AlwaysOn, 1.0, false, false),
            ("probability_-1",  Sampler::Probability(-1.0), 0.0,  false, false),
            ("probability_.25", Sampler::Probability(0.25), 0.25, false, false),
            ("probability_.50", Sampler::Probability(0.50), 0.5,  false, false),
            ("probability_.75", Sampler::Probability(0.75), 0.75, false, false),
            ("probability_2.0", Sampler::Probability(2.0),  1.0,  false, false),

            // Spans w/o a parent delegate
            ("delegate_to_always_on", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOn)), 1.0, false, false),
            ("delegate_to_always_off", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOff)), 0.0, false, false),
            ("delegate_to_probability_-1", Sampler::ParentOrElse(Box::new(Sampler::Probability(-1.0))), 0.0, false, false),
            ("delegate_to_probability_.25", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.25))), 0.25, false, false),
            ("delegate_to_probability_.50", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.50))), 0.50, false, false),
            ("delegate_to_probability_.75", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.75))), 0.75, false, false),
            ("delegate_to_probability_2.0", Sampler::ParentOrElse(Box::new(Sampler::Probability(2.0))), 1.0, false, false),

            // Spans with a parent that is *not* sampled act like spans w/o a parent
            ("unsampled_parent_with_probability_-1",  Sampler::Probability(-1.0), 0.0, true, false),
            ("unsampled_parent_with_probability_.25", Sampler::Probability(0.25), 0.25, true, false),
            ("unsampled_parent_with_probability_.50", Sampler::Probability(0.50), 0.5, true, false),
            ("unsampled_parent_with_probability_.75", Sampler::Probability(0.75), 0.75, true, false),
            ("unsampled_parent_with_probability_2.0", Sampler::Probability(2.0),  1.0, true, false),
            ("unsampled_parent_or_else_with_always_on", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOn)), 0.0, true, false),
            ("unsampled_parent_or_else_with_always_off", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOff)), 0.0, true, false),
            ("unsampled_parent_or_else_with_probability", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.25))), 0.0, true, false),

            // Spans with a parent that is sampled, will always sample, regardless of the probability
            ("sampled_parent_with_probability_-1",  Sampler::Probability(-1.0), 1.0, true, true),
            ("sampled_parent_with_probability_.25", Sampler::Probability(0.25), 1.0, true, true),
            ("sampled_parent_with_probability_2.0", Sampler::Probability(2.0),  1.0, true, true),

            // Spans with a parent that is sampled, will always sample, regardless of the delegate sampler
            ("sampled_parent_or_else_with_always_on", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOn)), 1.0, true, true),
            ("sampled_parent_or_else_with_always_off", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOff)), 1.0, true, true),
            ("sampled_parent_or_else_with_probability_.25", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.25))), 1.0, true, true),

            // Spans with a sampled parent, but when using the NeverSample Sampler, aren't sampled
            ("sampled_parent_span_with_never_sample", Sampler::AlwaysOff, 0.0, true, true),
        ]
    }

    #[test]
    fn sampling() {
        let total = 10_000;
        let mut rng = rand::thread_rng();
        for (name, sampler, expectation, parent, sample_parent) in sampler_data() {
            let mut sampled = 0;
            for _ in 0..total {
                let parent_context = if parent {
                    let trace_flags = if sample_parent {
                        api::TRACE_FLAG_SAMPLED
                    } else {
                        0
                    };
                    Some(api::SpanContext::new(
                        api::TraceId::from_u128(1),
                        api::SpanId::from_u64(1),
                        trace_flags,
                        false,
                    ))
                } else {
                    None
                };
                let trace_id = api::TraceId::from_u128(rng.gen());
                if sampler
                    .should_sample(
                        parent_context.as_ref(),
                        trace_id,
                        name,
                        &api::SpanKind::Internal,
                        &[],
                        &[],
                    )
                    .decision
                    == api::SamplingDecision::RecordAndSampled
                {
                    sampled += 1;
                }
            }
            let mut tolerance = 0.0;
            let got = sampled as f64 / total as f64;

            if expectation > 0.0 && expectation < 1.0 {
                // See https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval
                let z = 4.75342; // This should succeed 99.9999% of the time
                tolerance = z * (got * (1.0 - got) / total as f64).sqrt();
            }

            let diff = (got - expectation).abs();
            assert!(
                diff <= tolerance,
                "{} got {:?} (diff: {}), expected {} (w/tolerance: {})",
                name,
                got,
                diff,
                expectation,
                tolerance
            );
        }
    }
}
<commit_msg>The probability sampler should ignore the parent sampled flag (#154)<commit_after>//! # Sampler
use crate::api;

/// Sampling options
#[derive(Clone, Debug)]
pub enum Sampler {
    /// Always sample the trace
    AlwaysOn,
    /// Never sample the trace
    AlwaysOff,
    /// Respects the parent span's sampling decision or delegates a delegate sampler for root spans.
    ParentOrElse(Box<Sampler>),
    /// Sample a given fraction of traces. Fractions >= 1 will always sample. If the parent span is
    /// sampled, then it's child spans will automatically be sampled. Fractions < 0 are treated as
    /// zero, but spans may still be sampled if their parent is.
    Probability(f64),
}

impl api::Sampler for Sampler {
    fn should_sample(
        &self,
        parent_context: Option<&api::SpanContext>,
        trace_id: api::TraceId,
        name: &str,
        span_kind: &api::SpanKind,
        attributes: &[api::KeyValue],
        links: &[api::Link],
    ) -> api::SamplingResult {
        let decision = match self {
            // Always sample the trace
            Sampler::AlwaysOn => api::SamplingDecision::RecordAndSampled,
            // Never sample the trace
            Sampler::AlwaysOff => api::SamplingDecision::NotRecord,
            // The parent decision if sampled; otherwise the decision of delegate_sampler
            Sampler::ParentOrElse(delegate_sampler) => parent_context.map_or(
                delegate_sampler
                    .should_sample(parent_context, trace_id, name, span_kind, attributes, links)
                    .decision,
                |ctx| {
                    if ctx.is_sampled() {
                        api::SamplingDecision::RecordAndSampled
                    } else {
                        api::SamplingDecision::NotRecord
                    }
                },
            ),
            // Probabilistically sample the trace.
            Sampler::Probability(prob) => {
                if *prob >= 1.0 {
                    api::SamplingDecision::RecordAndSampled
                } else {
                    let prob_upper_bound = (prob.max(0.0) * (1u64 << 63) as f64) as u64;
                    // The trace_id is already randomly generated, so we don't need a new one here
                    let rnd_from_trace_id = (trace_id.to_u128() as u64) >> 1;

                    if rnd_from_trace_id < prob_upper_bound {
                        api::SamplingDecision::RecordAndSampled
                    } else {
                        api::SamplingDecision::NotRecord
                    }
                }
            }
        };

        api::SamplingResult {
            decision,
            // No extra attributes ever set by the SDK samplers.
            attributes: Vec::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::api::{self, Sampler as _};
    use crate::sdk::Sampler;
    use rand::Rng;

    #[rustfmt::skip]
    fn sampler_data() -> Vec<(&'static str, Sampler, f64, bool, bool)> {
        vec![
            // Span w/o a parent
            ("never_sample", Sampler::AlwaysOff, 0.0, false, false),
            ("always_sample", Sampler::AlwaysOn, 1.0, false, false),
            ("probability_-1",  Sampler::Probability(-1.0), 0.0,  false, false),
            ("probability_.25", Sampler::Probability(0.25), 0.25, false, false),
            ("probability_.50", Sampler::Probability(0.50), 0.5,  false, false),
            ("probability_.75", Sampler::Probability(0.75), 0.75, false, false),
            ("probability_2.0", Sampler::Probability(2.0),  1.0,  false, false),

            // Spans w/o a parent delegate
            ("delegate_to_always_on", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOn)), 1.0, false, false),
            ("delegate_to_always_off", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOff)), 0.0, false, false),
            ("delegate_to_probability_-1", Sampler::ParentOrElse(Box::new(Sampler::Probability(-1.0))), 0.0, false, false),
            ("delegate_to_probability_.25", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.25))), 0.25, false, false),
            ("delegate_to_probability_.50", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.50))), 0.50, false, false),
            ("delegate_to_probability_.75", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.75))), 0.75, false, false),
            ("delegate_to_probability_2.0", Sampler::ParentOrElse(Box::new(Sampler::Probability(2.0))), 1.0, false, false),

            // Spans with a parent that is *not* sampled act like spans w/o a parent
            ("unsampled_parent_with_probability_-1",  Sampler::Probability(-1.0), 0.0, true, false),
            ("unsampled_parent_with_probability_.25", Sampler::Probability(0.25), 0.25, true, false),
            ("unsampled_parent_with_probability_.50", Sampler::Probability(0.50), 0.5, true, false),
            ("unsampled_parent_with_probability_.75", Sampler::Probability(0.75), 0.75, true, false),
            ("unsampled_parent_with_probability_2.0", Sampler::Probability(2.0),  1.0, true, false),
            ("unsampled_parent_or_else_with_always_on", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOn)), 0.0, true, false),
            ("unsampled_parent_or_else_with_always_off", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOff)), 0.0, true, false),
            ("unsampled_parent_or_else_with_probability", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.25))), 0.0, true, false),

            // A probability sampler with a parent that is sampled will ignore the parent
            ("sampled_parent_with_probability_-1",  Sampler::Probability(-1.0), 0.0, true, true),
            ("sampled_parent_with_probability_.25", Sampler::Probability(0.25), 0.25, true, true),
            ("sampled_parent_with_probability_2.0", Sampler::Probability(2.0),  1.0, true, true),

            // Spans with a parent that is sampled, will always sample, regardless of the delegate sampler
            ("sampled_parent_or_else_with_always_on", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOn)), 1.0, true, true),
            ("sampled_parent_or_else_with_always_off", Sampler::ParentOrElse(Box::new(Sampler::AlwaysOff)), 1.0, true, true),
            ("sampled_parent_or_else_with_probability_.25", Sampler::ParentOrElse(Box::new(Sampler::Probability(0.25))), 1.0, true, true),

            // Spans with a sampled parent, but when using the NeverSample Sampler, aren't sampled
            ("sampled_parent_span_with_never_sample", Sampler::AlwaysOff, 0.0, true, true),
        ]
    }

    #[test]
    fn sampling() {
        let total = 10_000;
        let mut rng = rand::thread_rng();
        for (name, sampler, expectation, parent, sample_parent) in sampler_data() {
            let mut sampled = 0;
            for _ in 0..total {
                let parent_context = if parent {
                    let trace_flags = if sample_parent {
                        api::TRACE_FLAG_SAMPLED
                    } else {
                        0
                    };
                    Some(api::SpanContext::new(
                        api::TraceId::from_u128(1),
                        api::SpanId::from_u64(1),
                        trace_flags,
                        false,
                    ))
                } else {
                    None
                };
                let trace_id = api::TraceId::from_u128(rng.gen());
                if sampler
                    .should_sample(
                        parent_context.as_ref(),
                        trace_id,
                        name,
                        &api::SpanKind::Internal,
                        &[],
                        &[],
                    )
                    .decision
                    == api::SamplingDecision::RecordAndSampled
                {
                    sampled += 1;
                }
            }
            let mut tolerance = 0.0;
            let got = sampled as f64 / total as f64;

            if expectation > 0.0 && expectation < 1.0 {
                // See https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval
                let z = 4.75342; // This should succeed 99.9999% of the time
                tolerance = z * (got * (1.0 - got) / total as f64).sqrt();
            }

            let diff = (got - expectation).abs();
            assert!(
                diff <= tolerance,
                "{} got {:?} (diff: {}), expected {} (w/tolerance: {})",
                name,
                got,
                diff,
                expectation,
                tolerance
            );
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate bart_derive;

#[test]
fn it_works() {
    #[derive(BartDisplay)]
    #[template_string="Hello, {{name}}"]
    struct Test { name: String }

    assert_eq!(
        "Hello, World",
        format!("{}", Test { name: "World".to_owned() })
    );
}

#[test]
fn it_can_borrow() {
    #[derive(BartDisplay)]
    #[template_string="Hello, {{name}}"]
    struct Test<'a> { name: &'a str }

    assert_eq!(
        "Hello, World",
        format!("{}", Test { name: "World" })
    );
}

#[test]
fn it_performs_escaping() {
    #[derive(BartDisplay)]
    #[template_string="{{txt}}"]
    struct Test<'a> { txt: &'a str }

    assert_eq!(
        "<&"'",
        format!("{}", Test { txt: "<&\"'" })
    );
}

#[test]
fn it_passes_through() {
    #[derive(BartDisplay)]
    #[template_string="{{{txt}}}"]
    struct Test<'a> { txt: &'a str }

    assert_eq!(
        "<&\"'",
        format!("{}", Test { txt: "<&\"'" })
    );
}

#[test]
fn it_can_iterate() {
    #[derive(BartDisplay)]
    #[template_string="{{#vec}}{{.}}{{/vec}}"]
    struct Test { vec: Vec<i32> }

    assert_eq!(
        "123",
        format!("{}", Test { vec: vec![1, 2, 3] })
    );
}

#[test]
fn it_can_iterate_option() {
    #[derive(BartDisplay)]
    #[template_string="{{#a}}({{.}}){{/a}}"]
    struct Test { a: Option<i32> }

    assert_eq!(
        "(1)",
        format!("{}", Test { a: Some(1) })
    );

    assert_eq!(
        "",
        format!("{}", Test { a: None })
    );
}

#[test]
fn it_can_iterate_borrowed_slice() {
    #[derive(BartDisplay)]
    #[template_string="{{#slice}}{{.}}{{/slice}}"]
    struct Test<'a> { slice: &'a [i32] }

    assert_eq!(
        "123",
        format!("{}", Test { slice: &[1, 2, 3] })
    );
}

#[test]
fn it_can_access_nested_fields() {
    struct Nested { a: i32 }

    #[derive(BartDisplay)]
    #[template_string="{{nested.a}}"]
    struct Test { nested: Nested }

    assert_eq!(
        "42",
        format!("{}", Test { nested: Nested { a: 42 } })
    );
}

#[test]
fn it_can_scope_into_nested_values() {
    struct Nested { a: i32 }

    #[derive(BartDisplay)]
    #[template_string="{{#nested.}}{{.a}}{{/nested}}"]
    struct Test { nested: Nested }

    assert_eq!(
        "42",
        format!("{}", Test { nested: Nested { a: 42 } })
    );
}

#[test]
fn it_supports_conditional_scope_with_boolean() {
    #[derive(BartDisplay)]
    #[template_string="{{#a?}}yes{{/a}}"]
    struct Test { a: bool }

    assert_eq!(
        "yes",
        format!("{}", Test { a: true })
    );

    assert_eq!(
        "",
        format!("{}", Test { a: false })
    );
}

#[test]
fn it_supports_conditional_scope_with_non_bool() {
    extern crate bart;

    struct TestBool<'a> {
        name: &'a str,
    }

    impl<'a> bart::Conditional for TestBool<'a> {
        fn val(&self) -> bool {
            self.name.len() > 2
        }
    }

    #[derive(BartDisplay)]
    #[template_string="{{cond.name}}: {{#cond?}}Hello {{.name}}{{/cond}}"]
    struct Test<'a> { cond: TestBool<'a> }

    assert_eq!(
        "Joe: Hello Joe",
        format!("{}", Test { cond: TestBool { name: "Joe" } })
    );

    assert_eq!(
        "No: ",
        format!("{}", Test { cond: TestBool { name: "No" } })
    );
}
<commit_msg>Add test for name with underscore. This fixes #3 and #6<commit_after>#[macro_use] extern crate bart_derive;

#[test]
fn it_works() {
    #[derive(BartDisplay)]
    #[template_string="Hello, {{name}}"]
    struct Test { name: String }

    assert_eq!(
        "Hello, World",
        format!("{}", Test { name: "World".to_owned() })
    );
}

#[test]
fn it_handles_names_with_underscore() {
    #[derive(BartDisplay)]
    #[template_string="Hello, {{your_name}}"]
    struct Test { your_name: String }

    assert_eq!(
        "Hello, World",
        format!("{}", Test { your_name: "World".to_owned() })
    );
}

#[test]
fn it_can_borrow() {
    #[derive(BartDisplay)]
    #[template_string="Hello, {{name}}"]
    struct Test<'a> { name: &'a str }

    assert_eq!(
        "Hello, World",
        format!("{}", Test { name: "World" })
    );
}

#[test]
fn it_performs_escaping() {
    #[derive(BartDisplay)]
    #[template_string="{{txt}}"]
    struct Test<'a> { txt: &'a str }

    assert_eq!(
        "<&"'",
        format!("{}", Test { txt: "<&\"'" })
    );
}

#[test]
fn it_passes_through() {
    #[derive(BartDisplay)]
    #[template_string="{{{txt}}}"]
    struct Test<'a> { txt: &'a str }

    assert_eq!(
        "<&\"'",
        format!("{}", Test { txt: "<&\"'" })
    );
}

#[test]
fn it_can_iterate() {
    #[derive(BartDisplay)]
    #[template_string="{{#vec}}{{.}}{{/vec}}"]
    struct Test { vec: Vec<i32> }

    assert_eq!(
        "123",
        format!("{}", Test { vec: vec![1, 2, 3] })
    );
}

#[test]
fn it_can_iterate_option() {
    #[derive(BartDisplay)]
    #[template_string="{{#a}}({{.}}){{/a}}"]
    struct Test { a: Option<i32> }

    assert_eq!(
        "(1)",
        format!("{}", Test { a: Some(1) })
    );

    assert_eq!(
        "",
        format!("{}", Test { a: None })
    );
}

#[test]
fn it_can_iterate_borrowed_slice() {
    #[derive(BartDisplay)]
    #[template_string="{{#slice}}{{.}}{{/slice}}"]
    struct Test<'a> { slice: &'a [i32] }

    assert_eq!(
        "123",
        format!("{}", Test { slice: &[1, 2, 3] })
    );
}

#[test]
fn it_can_access_nested_fields() {
    struct Nested { a: i32 }

    #[derive(BartDisplay)]
    #[template_string="{{nested.a}}"]
    struct Test { nested: Nested }

    assert_eq!(
        "42",
        format!("{}", Test { nested: Nested { a: 42 } })
    );
}

#[test]
fn it_can_scope_into_nested_values() {
    struct Nested { a: i32 }

    #[derive(BartDisplay)]
    #[template_string="{{#nested.}}{{.a}}{{/nested}}"]
    struct Test { nested: Nested }

    assert_eq!(
        "42",
        format!("{}", Test { nested: Nested { a: 42 } })
    );
}

#[test]
fn it_supports_conditional_scope_with_boolean() {
    #[derive(BartDisplay)]
    #[template_string="{{#a?}}yes{{/a}}"]
    struct Test { a: bool }

    assert_eq!(
        "yes",
        format!("{}", Test { a: true })
    );

    assert_eq!(
        "",
        format!("{}", Test { a: false })
    );
}

#[test]
fn it_supports_conditional_scope_with_non_bool() {
    extern crate bart;

    struct TestBool<'a> {
        name: &'a str,
    }

    impl<'a> bart::Conditional for TestBool<'a> {
        fn val(&self) -> bool {
            self.name.len() > 2
        }
    }

    #[derive(BartDisplay)]
    #[template_string="{{cond.name}}: {{#cond?}}Hello {{.name}}{{/cond}}"]
    struct Test<'a> { cond: TestBool<'a> }

    assert_eq!(
        "Joe: Hello Joe",
        format!("{}", Test { cond: TestBool { name: "Joe" } })
    );

    assert_eq!(
        "No: ",
        format!("{}", Test { cond: TestBool { name: "No" } })
    );
}
<|endoftext|>


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

//! ncurses-compatible database discovery
//!
//! Does not support hashed database, only filesystem!

use std::env;
use std::fs;
use std::path::PathBuf;

/// Return path to database entry for `term`
pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
    let mut dirs_to_search = Vec::new();
    let first_char = match term.chars().next() {
        Some(c) => c,
        None => return None,
    };

    // Find search directory
    // The terminfo manual says:
    //
    // > If  the  environment  variable  TERMINFO is set, it is interpreted
    // > as the pathname of a directory containing the compiled description
    // > you are working on.  Only that directory is searched.
    //
    // However, the ncurses manual says:
    //
    // > If the environment variable TERMINFO is defined, any program using
    // > curses checks for a local terminal definition  before  checking in
    // > the standard place.
    //
    // Given that ncurses is the defacto standard, we follow the ncurses manual.
    if let Some(dir) = env::var_os("TERMINFO") {
        dirs_to_search.push(PathBuf::from(dir));
    }

    if let Ok(dirs) = match env::var("TERMINFO_DIRS") {
        for i in dirs.split(':') {
            if i == "" {
                dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
            } else {
                dirs_to_search.push(PathBuf::from(i));
            }
        }
    } else {
        // Found nothing in TERMINFO_DIRS, use the default paths:
        // According to  /etc/terminfo/README, after looking at
        // ~/.terminfo, ncurses will search /etc/terminfo, then
        // /lib/terminfo, and eventually /usr/share/terminfo.
        // On Haiku the database can be found at /boot/system/data/terminfo
        if let Some(mut homedir) = env::home_dir() {
            homedir.push(".terminfo");
            dirs_to_search.push(homedir)
        }

        dirs_to_search.push(PathBuf::from("/etc/terminfo"));
        dirs_to_search.push(PathBuf::from("/lib/terminfo"));
        dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
        dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo"));
    }

    // Look for the terminal in all of the search directories
    for mut p in dirs_to_search {
        if fs::metadata(&p).is_ok() {
            p.push(&first_char.to_string());
            p.push(&term);
            if fs::metadata(&p).is_ok() {
                return Some(p);
            }
            p.pop();
            p.pop();

            // on some installations the dir is named after the hex of the char
            // (e.g. OS X)
            p.push(&format!("{:x}", first_char as usize));
            p.push(term);
            if fs::metadata(&p).is_ok() {
                return Some(p);
            }
        }
    }
    None
}
<commit_msg>Remove extraneous match keyword.<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ncurses-compatible database discovery
//!
//! Does not support hashed database, only filesystem!

use std::env;
use std::fs;
use std::path::PathBuf;

/// Return path to database entry for `term`
pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
    let mut dirs_to_search = Vec::new();
    let first_char = match term.chars().next() {
        Some(c) => c,
        None => return None,
    };

    // Find search directory
    // The terminfo manual says:
    //
    // > If  the  environment  variable  TERMINFO is set, it is interpreted
    // > as the pathname of a directory containing the compiled description
    // > you are working on.  Only that directory is searched.
    //
    // However, the ncurses manual says:
    //
    // > If the environment variable TERMINFO is defined, any program using
    // > curses checks for a local terminal definition  before  checking in
    // > the standard place.
    //
    // Given that ncurses is the defacto standard, we follow the ncurses manual.
    if let Some(dir) = env::var_os("TERMINFO") {
        dirs_to_search.push(PathBuf::from(dir));
    }

    if let Ok(dirs) = env::var("TERMINFO_DIRS") {
        for i in dirs.split(':') {
            if i == "" {
                dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
            } else {
                dirs_to_search.push(PathBuf::from(i));
            }
        }
    } else {
        // Found nothing in TERMINFO_DIRS, use the default paths:
        // According to  /etc/terminfo/README, after looking at
        // ~/.terminfo, ncurses will search /etc/terminfo, then
        // /lib/terminfo, and eventually /usr/share/terminfo.
        // On Haiku the database can be found at /boot/system/data/terminfo
        if let Some(mut homedir) = env::home_dir() {
            homedir.push(".terminfo");
            dirs_to_search.push(homedir)
        }

        dirs_to_search.push(PathBuf::from("/etc/terminfo"));
        dirs_to_search.push(PathBuf::from("/lib/terminfo"));
        dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
        dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo"));
    }

    // Look for the terminal in all of the search directories
    for mut p in dirs_to_search {
        if fs::metadata(&p).is_ok() {
            p.push(&first_char.to_string());
            p.push(&term);
            if fs::metadata(&p).is_ok() {
                return Some(p);
            }
            p.pop();
            p.pop();

            // on some installations the dir is named after the hex of the char
            // (e.g. OS X)
            p.push(&format!("{:x}", first_char as usize));
            p.push(term);
            if fs::metadata(&p).is_ok() {
                return Some(p);
            }
        }
    }
    None
}
<|endoftext|>


<commit_before>use syntax::{ast, AstToken, SyntaxKind::STRING};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: replace_string_with_char
//
// Replace string with char.
//
// ```
// fn main() {
//     find("{$0");
// }
// ```
// ->
// ```
// fn main() {
//     find('{');
// }
// ```
pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
    let value = token.value()?;
    let target = token.syntax().text_range();

    if value.chars().take(2).count() != 1 {
        return None;
    }

    acc.add(
        AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
        "Replace string with char",
        target,
        |edit| {
            let token_text = token.syntax().text();
            let inner_text = &token_text[1..token_text.len() - 1];
            edit.replace(token.syntax().text_range(), format!("'{}'", inner_text));
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn replace_string_with_char_target() {
        check_assist_target(
            replace_string_with_char,
            r#"
            fn f() {
                let s = "$0c";
            }
            "#,
            r#""c""#,
        );
    }

    #[test]
    fn replace_string_with_char_assist() {
        check_assist(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "$0c";
    }
    "#,
            r##"
    fn f() {
        let s = 'c';
    }
    "##,
        )
    }

    #[test]
    fn replace_string_with_char_assist_with_emoji() {
        check_assist(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "$0😀";
    }
    "#,
            r##"
    fn f() {
        let s = '😀';
    }
    "##,
        )
    }

    #[test]
    fn replace_string_with_char_assist_not_applicable() {
        check_assist_not_applicable(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "$0test";
    }
    "#,
        )
    }

    #[test]
    fn replace_string_with_char_works_inside_macros() {
        check_assist(
            replace_string_with_char,
            r#"
                fn f() {
                    format!($0"x", 92)
                }
                "#,
            r##"
                fn f() {
                    format!('x', 92)
                }
                "##,
        )
    }

    #[test]
    fn replace_string_with_char_works_func_args() {
        check_assist(
            replace_string_with_char,
            r#"
                fn f() {
                    find($0"x");
                }
                "#,
            r##"
                fn f() {
                    find('x');
                }
                "##,
        )
    }

    #[test]
    fn replace_string_with_char_newline() {
        check_assist(
            replace_string_with_char,
            r#"
                fn f() {
                    find($0"\n");
                }
                "#,
            r##"
                fn f() {
                    find('\n');
                }
                "##,
        )
    }

    #[test]
    fn replace_string_with_char_unicode_escape() {
        check_assist(
            replace_string_with_char,
            r#"
                fn f() {
                    find($0"\u{7FFF}");
                }
                "#,
            r##"
                fn f() {
                    find('\u{7FFF}');
                }
                "##,
        )
    }
}
<commit_msg>Only replace quotes in replace_string_with_char assist<commit_after>use syntax::{ast, AstToken, SyntaxKind::STRING};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: replace_string_with_char
//
// Replace string with char.
//
// ```
// fn main() {
//     find("{$0");
// }
// ```
// ->
// ```
// fn main() {
//     find('{');
// }
// ```
pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
    let value = token.value()?;
    let target = token.syntax().text_range();

    if value.chars().take(2).count() != 1 {
        return None;
    }
    let quote_offets = token.quote_offsets()?;

    acc.add(
        AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
        "Replace string with char",
        target,
        |edit| {
            let (left, right) = quote_offets.quotes;
            edit.replace(left, String::from('\''));
            edit.replace(right, String::from('\''));
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn replace_string_with_char_target() {
        check_assist_target(
            replace_string_with_char,
            r#"
fn f() {
    let s = "$0c";
}
"#,
            r#""c""#,
        );
    }

    #[test]
    fn replace_string_with_char_assist() {
        check_assist(
            replace_string_with_char,
            r#"
fn f() {
    let s = "$0c";
}
"#,
            r##"
fn f() {
    let s = 'c';
}
"##,
        )
    }

    #[test]
    fn replace_string_with_char_assist_with_emoji() {
        check_assist(
            replace_string_with_char,
            r#"
fn f() {
    let s = "$0😀";
}
"#,
            r##"
fn f() {
    let s = '😀';
}
"##,
        )
    }

    #[test]
    fn replace_string_with_char_assist_not_applicable() {
        check_assist_not_applicable(
            replace_string_with_char,
            r#"
fn f() {
    let s = "$0test";
}
"#,
        )
    }

    #[test]
    fn replace_string_with_char_works_inside_macros() {
        check_assist(
            replace_string_with_char,
            r#"
fn f() {
    format!($0"x", 92)
}
"#,
            r##"
fn f() {
    format!('x', 92)
}
"##,
        )
    }

    #[test]
    fn replace_string_with_char_works_func_args() {
        check_assist(
            replace_string_with_char,
            r#"
fn f() {
    find($0"x");
}
"#,
            r##"
fn f() {
    find('x');
}
"##,
        )
    }

    #[test]
    fn replace_string_with_char_newline() {
        check_assist(
            replace_string_with_char,
            r#"
fn f() {
    find($0"\n");
}
"#,
            r##"
fn f() {
    find('\n');
}
"##,
        )
    }

    #[test]
    fn replace_string_with_char_unicode_escape() {
        check_assist(
            replace_string_with_char,
            r#"
fn f() {
    find($0"\u{7FFF}");
}
"#,
            r##"
fn f() {
    find('\u{7FFF}');
}
"##,
        )
    }

    #[test]
    fn replace_raw_string_with_char() {
        check_assist(
            replace_string_with_char,
            r##"
fn f() {
    $0r#"X"#
}
"##,
            r##"
fn f() {
    'X'
}
"##,
        )
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
#![allow(unused_imports)]

extern crate test;
#[macro_use(s)]
extern crate ndarray;
#[cfg(feature = "rblas")]
extern crate rblas;
#[cfg(feature = "rblas")]
use rblas::matrix::Matrix;

use ndarray::{
    OwnedArray,
    zeros,
};
use ndarray::{arr0, arr1, arr2};

use test::black_box;

#[bench]
fn bench_std_add_shared(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    let b = a.clone();
    bench.iter(|| a.iadd(&b));
}

#[bench]
fn bench_std_add_owned(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    let mut a = a.to_owned();
    let b = a.clone();
    bench.iter(|| a.iadd(&b));
}

#[bench]
fn small_iter_1d(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn small_iter_1d_raw(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt); })
}

#[bench]
fn small_iter_2d(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn sum_1d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros(64 * 64);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_1d_raw(bench: &mut test::Bencher)
{
    // this is autovectorized to death (= great performance)
    let a = OwnedArray::<i32, _>::zeros(64 * 64);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.raw_data() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_by_row(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for row in a.outer_iter() {
            for &elt in row {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_raw(bench: &mut test::Bencher)
{
    // this is autovectorized to death (= great performance)
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.raw_data() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout_fold(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        a.fold(0, |acc, elt| acc + *elt)
    });
}

#[bench]
fn sum_2d_cutout_by_row(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for row in 0..a.shape()[0] {
            for &elt in a.row_iter(row) {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout_outer_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for row in a.outer_iter() {
            for &elt in row {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_transpose_regular(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    a.swap_axes(0, 1);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_transpose_by_row(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    a.swap_axes(0, 1);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for row in 0..a.shape()[0] {
            for &elt in a.row_iter(row) {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn assign_scalar_2d_transposed(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    a.swap_axes(0, 1);
    bench.iter(|| a.assign_scalar(&3.))
}

#[bench]
fn assign_scalar_2d(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    bench.iter(|| a.assign_scalar(&3.))
}

#[bench]
fn assign_scalar_2d_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::zeros((64, 64));
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_cutout(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::zeros((66, 66));
    let mut a = a.slice_mut(s![1..-1, 1..-1]);
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_transposed_large(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::zeros((64, 64));
    a.swap_axes(0, 1);
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_raw_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::zeros((64, 64));
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| for elt in a.raw_data_mut() { *elt = s; });
}

#[bench]
fn bench_iter_diag(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    bench.iter(|| for elt in a.diag_iter() { black_box(elt); })
}

#[bench]
fn bench_row_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    let it = a.row_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_col_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    let it = a.col_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_mat_mul(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    let mut at = a.clone();
    at.swap_axes(0, 1);
    bench.iter(|| at.mat_mul(&a));
}

#[bench]
fn bench_mat_mul_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((64, 64));
    let b = OwnedArray::<f32, _>::zeros((64, 64));
    let a = black_box(a.view());
    let b = black_box(b.view());
    bench.iter(|| a.mat_mul(&b));
}

#[cfg(feature = "rblas")]
#[bench]
fn bench_mat_mul_rblas_large(bench: &mut test::Bencher)
{
    use rblas::Gemm;
    use rblas::attribute::Transpose;
    use ndarray::blas::AsBlas;

    let mut a = OwnedArray::<f32, _>::zeros((64, 64));
    let mut b = OwnedArray::<f32, _>::zeros((64, 64));
    let mut c = OwnedArray::<f32, _>::zeros((64, 64));
    bench.iter(|| {
        // C ← α AB + β C
        f32::gemm(&1.,
                  Transpose::NoTrans, &a.blas(),
                  Transpose::NoTrans, &b.blas(),
                  &1., &mut c.blas());
    });
}

#[bench]
fn bench_create_iter(bench: &mut test::Bencher)
{
    let a = arr2(&[[1., 2., 2.],
                   [3., 4., 4.],
                   [3., 4., 4.],
                   [3., 4., 4.],
                   [5., 6., 6.]]);
    let mut at = a.clone();
    at.swap_axes(0, 1);
    let v = black_box(at.view());

    bench.iter(|| {
        let v = black_box(v);
        v.into_iter()
    });
}

#[bench]
fn lst_squares(bench: &mut test::Bencher)
{
    let xs = arr2::<f32, _>(&[[ 2.,  3.],
                           [-2., -1.],
                           [ 1.,  5.],
                           [-1.,  2.]]);
    let b = arr1(&[1., -1., 2., 1.]);
    bench.iter(|| ndarray::linalg::least_squares(&xs, &b));
}

#[bench]
fn bench_to_owned_n(bench: &mut test::Bencher)
{
    let a = zeros::<f32, _>((32, 32));
    bench.iter(|| a.to_owned());
}

#[bench]
fn bench_to_owned_t(bench: &mut test::Bencher)
{
    let mut a = zeros::<f32, _>((32, 32));
    a.swap_axes(0, 1);
    bench.iter(|| a.to_owned());
}
<commit_msg>Add benchmarks for matrix addition<commit_after>#![feature(test)]
#![allow(unused_imports)]

extern crate test;
#[macro_use(s)]
extern crate ndarray;
#[cfg(feature = "rblas")]
extern crate rblas;
#[cfg(feature = "rblas")]
use rblas::matrix::Matrix;

use ndarray::{
    OwnedArray,
    zeros,
};
use ndarray::{arr0, arr1, arr2};

use test::black_box;

#[bench]
fn bench_std_add_shared(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    let b = a.clone();
    bench.iter(|| a.iadd(&b));
}

#[bench]
fn bench_std_add_owned(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    let mut a = a.to_owned();
    let b = a.clone();
    bench.iter(|| a.iadd(&b));
}

#[bench]
fn small_iter_1d(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn small_iter_1d_raw(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt); })
}

#[bench]
fn small_iter_2d(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn sum_1d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros(64 * 64);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_1d_raw(bench: &mut test::Bencher)
{
    // this is autovectorized to death (= great performance)
    let a = OwnedArray::<i32, _>::zeros(64 * 64);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.raw_data() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_by_row(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for row in a.outer_iter() {
            for &elt in row {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_raw(bench: &mut test::Bencher)
{
    // this is autovectorized to death (= great performance)
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.raw_data() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout_fold(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        a.fold(0, |acc, elt| acc + *elt)
    });
}

#[bench]
fn sum_2d_cutout_by_row(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for row in 0..a.shape()[0] {
            for &elt in a.row_iter(row) {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout_outer_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for row in a.outer_iter() {
            for &elt in row {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_transpose_regular(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    a.swap_axes(0, 1);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_transpose_by_row(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    a.swap_axes(0, 1);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for row in 0..a.shape()[0] {
            for &elt in a.row_iter(row) {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn add_2d_regular(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(a.view_mut() + bv);
    });
}

#[bench]
fn add_2d_cutout(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((66, 66));
    let mut acut = a.slice_mut(s![1..-1, 1..-1]);
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(acut.view_mut() + bv);
    });
}

#[bench]
fn assign_scalar_2d_transposed(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    a.swap_axes(0, 1);
    bench.iter(|| a.assign_scalar(&3.))
}

#[bench]
fn assign_scalar_2d(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    bench.iter(|| a.assign_scalar(&3.))
}

#[bench]
fn assign_scalar_2d_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::zeros((64, 64));
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_cutout(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::zeros((66, 66));
    let mut a = a.slice_mut(s![1..-1, 1..-1]);
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_transposed_large(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::zeros((64, 64));
    a.swap_axes(0, 1);
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_raw_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::zeros((64, 64));
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| for elt in a.raw_data_mut() { *elt = s; });
}

#[bench]
fn bench_iter_diag(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    bench.iter(|| for elt in a.diag_iter() { black_box(elt); })
}

#[bench]
fn bench_row_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    let it = a.row_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_col_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    let it = a.col_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_mat_mul(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    let mut at = a.clone();
    at.swap_axes(0, 1);
    bench.iter(|| at.mat_mul(&a));
}

#[bench]
fn bench_mat_mul_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((64, 64));
    let b = OwnedArray::<f32, _>::zeros((64, 64));
    let a = black_box(a.view());
    let b = black_box(b.view());
    bench.iter(|| a.mat_mul(&b));
}

#[cfg(feature = "rblas")]
#[bench]
fn bench_mat_mul_rblas_large(bench: &mut test::Bencher)
{
    use rblas::Gemm;
    use rblas::attribute::Transpose;
    use ndarray::blas::AsBlas;

    let mut a = OwnedArray::<f32, _>::zeros((64, 64));
    let mut b = OwnedArray::<f32, _>::zeros((64, 64));
    let mut c = OwnedArray::<f32, _>::zeros((64, 64));
    bench.iter(|| {
        // C ← α AB + β C
        f32::gemm(&1.,
                  Transpose::NoTrans, &a.blas(),
                  Transpose::NoTrans, &b.blas(),
                  &1., &mut c.blas());
    });
}

#[bench]
fn bench_create_iter(bench: &mut test::Bencher)
{
    let a = arr2(&[[1., 2., 2.],
                   [3., 4., 4.],
                   [3., 4., 4.],
                   [3., 4., 4.],
                   [5., 6., 6.]]);
    let mut at = a.clone();
    at.swap_axes(0, 1);
    let v = black_box(at.view());

    bench.iter(|| {
        let v = black_box(v);
        v.into_iter()
    });
}

#[bench]
fn lst_squares(bench: &mut test::Bencher)
{
    let xs = arr2::<f32, _>(&[[ 2.,  3.],
                           [-2., -1.],
                           [ 1.,  5.],
                           [-1.,  2.]]);
    let b = arr1(&[1., -1., 2., 1.]);
    bench.iter(|| ndarray::linalg::least_squares(&xs, &b));
}

#[bench]
fn bench_to_owned_n(bench: &mut test::Bencher)
{
    let a = zeros::<f32, _>((32, 32));
    bench.iter(|| a.to_owned());
}

#[bench]
fn bench_to_owned_t(bench: &mut test::Bencher)
{
    let mut a = zeros::<f32, _>((32, 32));
    a.swap_axes(0, 1);
    bench.iter(|| a.to_owned());
}
<|endoftext|>


<commit_before>use mio_uds::UnixStream;
use mio::Ready;
use libc::pid_t;
use std::io::{Seek,SeekFrom};
use std::fs::File;
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd};
use tempfile::tempfile;
use serde_json;
use nix;
use nix::unistd::*;

#[cfg(target_os = "macos")]
use std::ffi::CString;
#[cfg(target_os = "macos")]
use libc::{self,c_char,uint32_t,int32_t};
#[cfg(target_os = "macos")]
use std::iter::repeat;
#[cfg(target_os = "macos")]
use std::ptr::null_mut;

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::state::ConfigState;
use sozu_command::scm_socket::{Listeners,ScmSocket};
use sozu_command::messages::{OrderMessage,OrderMessageAnswer};
use sozu::network::proxy::Server;
use sozu::network::metrics;

use util;
use logging;
use command::Worker;

pub fn start_workers(executable_path: String, config: &Config) -> nix::Result<Vec<Worker>> {
  let state = ConfigState::new();
  let mut workers = Vec::new();
  for index in 0..config.worker_count {
    let listeners = Some(Listeners {
      http: Vec::new(),
      tls:  Vec::new(),
      tcp:  Vec::new(),
    });
    match start_worker_process(&index.to_string(), config, executable_path.clone(), &state, listeners) {
      Ok((pid, command, scm)) => {
        let w =  Worker::new(index as u32, pid, command, scm, config);
        workers.push(w);
      },
      Err(e) => return Err(e)
    };
  }
  Ok(workers)
}

pub fn start_worker(id: u32, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<Worker> {
  match start_worker_process(&id.to_string(), config, executable_path, state, listeners) {
    Ok((pid, command, scm)) => {
      let w = Worker::new(id, pid, command, scm, config);
      Ok(w)
    },
    Err(e) => Err(e)
  }
}

pub fn begin_worker_process(fd: i32, scm: i32, configuration_state_fd: i32, id: i32,
  command_buffer_size: usize, max_command_buffer_size: usize) {
  let mut command: Channel<OrderMessageAnswer,Config> = Channel::new(
    unsafe { UnixStream::from_raw_fd(fd) },
    command_buffer_size,
    max_command_buffer_size
  );

  command.set_nonblocking(false);

  let configuration_state_file = unsafe { File::from_raw_fd(configuration_state_fd) };
  let config_state: ConfigState = serde_json::from_reader(configuration_state_file)
    .expect("could not parse configuration state data");

  let proxy_config = command.read_message().expect("worker could not read configuration from socket");
  //println!("got message: {:?}", proxy_config);

  let worker_id = format!("{}-{:02}", "WRK", id);
  logging::setup(worker_id.clone(), &proxy_config.log_level,
    &proxy_config.log_target, proxy_config.log_access_target.as_ref().map(|s| s.as_str()));
  info!("worker {} starting...", id);

  command.set_nonblocking(true);
  let mut command: Channel<OrderMessageAnswer,OrderMessage> = command.into();
  command.readiness.insert(Ready::readable());

  if let Some(ref metrics) = proxy_config.metrics.as_ref() {
    metrics::setup(&metrics.address, worker_id, metrics.tagged_metrics, metrics.prefix.clone());
  }

  let mut server = Server::new_from_config(command, ScmSocket::new(scm), proxy_config, config_state);

  info!("starting event loop");
  server.run();
  info!("ending event loop");
}

pub fn start_worker_process(id: &str, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<(pid_t, Channel<OrderMessage,OrderMessageAnswer>, ScmSocket)> {
  trace!("parent({})", unsafe { libc::getpid() });

  let mut state_file = tempfile().expect("could not create temporary file for configuration state");
  util::disable_close_on_exec(state_file.as_raw_fd());

  serde_json::to_writer(&mut state_file, state).expect("could not write upgrade data to temporary file");
  state_file.seek(SeekFrom::Start(0)).expect("could not seek to beginning of file");

  let (server, client) = UnixStream::pair().unwrap();
  let (scm_server_fd, scm_client) = UnixStream::pair().unwrap();

  let scm_server = ScmSocket::new(scm_server_fd.into_raw_fd());

  util::disable_close_on_exec(client.as_raw_fd());
  util::disable_close_on_exec(scm_client.as_raw_fd());

  let mut command: Channel<Config,OrderMessageAnswer> = Channel::new(
    server,
    config.command_buffer_size,
    config.max_command_buffer_size
  );
  command.set_nonblocking(false);

  info!("{} launching worker", id);
  debug!("executable path is {}", executable_path);
  match fork() {
    Ok(ForkResult::Parent{ child }) => {
      info!("{} worker launched: {}", id, child);
      command.write_message(config);
      command.set_nonblocking(true);

      if let Some(l) = listeners {
        info!("sending listeners to new worker: {:?}", l);
        let res = scm_server.send_listeners(l);
        info!("sent listeners from master: {:?}", res);
      };
      util::disable_close_on_exec(scm_server.fd);

      let command: Channel<OrderMessage,OrderMessageAnswer> = command.into();
      Ok((child.into(), command, scm_server))
    },
    Ok(ForkResult::Child) => {
      trace!("child({}):\twill spawn a child", unsafe { libc::getpid() });
      Command::new(executable_path)
        .arg("worker")
        .arg("--id")
        .arg(id)
        .arg("--fd")
        .arg(client.as_raw_fd().to_string())
        .arg("--scm")
        .arg(scm_client.as_raw_fd().to_string())
        .arg("--configuration-state-fd")
        .arg(state_file.as_raw_fd().to_string())
        .arg("--command-buffer-size")
        .arg(config.command_buffer_size.to_string())
        .arg("--max-command-buffer-size")
        .arg(config.max_command_buffer_size.to_string())
        .exec();

      unreachable!();
    },
    Err(e) => {
      error!("Error during fork(): {}", e);
      Err(e)
    }
  }
}

#[cfg(target_os = "linux")]
pub unsafe fn get_executable_path() -> String {
  use std::fs;

  let path         = fs::read_link("/proc/self/exe").expect("/proc/self/exe doesn't exist");
  let mut path_str = path.into_os_string().into_string().expect("Failed to convert PathBuf to String");

  if path_str.ends_with(" (deleted)") {
    // The kernel appends " (deleted)" to the symlink when the original executable has been replaced
    let len = path_str.len();
    path_str.truncate(len - 10)
  }

  path_str
}

#[cfg(target_os = "macos")]
extern {
  pub fn _NSGetExecutablePath(buf: *mut c_char, size: *mut uint32_t) -> int32_t;
}

#[cfg(target_os = "macos")]
pub unsafe fn get_executable_path() -> String {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let mut size:uint32_t = capacity as u32;
  if _NSGetExecutablePath(ptr, &mut size) == 0 {

    let mut temp2:Vec<u8> = Vec::with_capacity(capacity);
    temp2.extend(repeat(0).take(capacity));
    let pathbuf2 = CString::from_vec_unchecked(temp2);
    let ptr2 = pathbuf2.into_raw();

    if libc::realpath(ptr, ptr2) != null_mut() {
      let path = CString::from_raw(ptr2);
      path.to_str().expect("failed to convert CString to String").to_string()
    } else {
      panic!();
    }
  } else {
    panic!("buffer too small");
  }
}
<commit_msg>fix build<commit_after>use mio_uds::UnixStream;
use mio::Ready;
use libc::{self,pid_t};
use std::io::{Seek,SeekFrom};
use std::fs::File;
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd};
use tempfile::tempfile;
use serde_json;
use nix;
use nix::unistd::*;

#[cfg(target_os = "macos")]
use std::ffi::CString;
#[cfg(target_os = "macos")]
use libc::{self,c_char,uint32_t,int32_t};
#[cfg(target_os = "macos")]
use std::iter::repeat;
#[cfg(target_os = "macos")]
use std::ptr::null_mut;

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::state::ConfigState;
use sozu_command::scm_socket::{Listeners,ScmSocket};
use sozu_command::messages::{OrderMessage,OrderMessageAnswer};
use sozu::network::proxy::Server;
use sozu::network::metrics;

use util;
use logging;
use command::Worker;

pub fn start_workers(executable_path: String, config: &Config) -> nix::Result<Vec<Worker>> {
  let state = ConfigState::new();
  let mut workers = Vec::new();
  for index in 0..config.worker_count {
    let listeners = Some(Listeners {
      http: Vec::new(),
      tls:  Vec::new(),
      tcp:  Vec::new(),
    });
    match start_worker_process(&index.to_string(), config, executable_path.clone(), &state, listeners) {
      Ok((pid, command, scm)) => {
        let w =  Worker::new(index as u32, pid, command, scm, config);
        workers.push(w);
      },
      Err(e) => return Err(e)
    };
  }
  Ok(workers)
}

pub fn start_worker(id: u32, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<Worker> {
  match start_worker_process(&id.to_string(), config, executable_path, state, listeners) {
    Ok((pid, command, scm)) => {
      let w = Worker::new(id, pid, command, scm, config);
      Ok(w)
    },
    Err(e) => Err(e)
  }
}

pub fn begin_worker_process(fd: i32, scm: i32, configuration_state_fd: i32, id: i32,
  command_buffer_size: usize, max_command_buffer_size: usize) {
  let mut command: Channel<OrderMessageAnswer,Config> = Channel::new(
    unsafe { UnixStream::from_raw_fd(fd) },
    command_buffer_size,
    max_command_buffer_size
  );

  command.set_nonblocking(false);

  let configuration_state_file = unsafe { File::from_raw_fd(configuration_state_fd) };
  let config_state: ConfigState = serde_json::from_reader(configuration_state_file)
    .expect("could not parse configuration state data");

  let proxy_config = command.read_message().expect("worker could not read configuration from socket");
  //println!("got message: {:?}", proxy_config);

  let worker_id = format!("{}-{:02}", "WRK", id);
  logging::setup(worker_id.clone(), &proxy_config.log_level,
    &proxy_config.log_target, proxy_config.log_access_target.as_ref().map(|s| s.as_str()));
  info!("worker {} starting...", id);

  command.set_nonblocking(true);
  let mut command: Channel<OrderMessageAnswer,OrderMessage> = command.into();
  command.readiness.insert(Ready::readable());

  if let Some(ref metrics) = proxy_config.metrics.as_ref() {
    metrics::setup(&metrics.address, worker_id, metrics.tagged_metrics, metrics.prefix.clone());
  }

  let mut server = Server::new_from_config(command, ScmSocket::new(scm), proxy_config, config_state);

  info!("starting event loop");
  server.run();
  info!("ending event loop");
}

pub fn start_worker_process(id: &str, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<(pid_t, Channel<OrderMessage,OrderMessageAnswer>, ScmSocket)> {
  trace!("parent({})", unsafe { libc::getpid() });

  let mut state_file = tempfile().expect("could not create temporary file for configuration state");
  util::disable_close_on_exec(state_file.as_raw_fd());

  serde_json::to_writer(&mut state_file, state).expect("could not write upgrade data to temporary file");
  state_file.seek(SeekFrom::Start(0)).expect("could not seek to beginning of file");

  let (server, client) = UnixStream::pair().unwrap();
  let (scm_server_fd, scm_client) = UnixStream::pair().unwrap();

  let scm_server = ScmSocket::new(scm_server_fd.into_raw_fd());

  util::disable_close_on_exec(client.as_raw_fd());
  util::disable_close_on_exec(scm_client.as_raw_fd());

  let mut command: Channel<Config,OrderMessageAnswer> = Channel::new(
    server,
    config.command_buffer_size,
    config.max_command_buffer_size
  );
  command.set_nonblocking(false);

  info!("{} launching worker", id);
  debug!("executable path is {}", executable_path);
  match fork() {
    Ok(ForkResult::Parent{ child }) => {
      info!("{} worker launched: {}", id, child);
      command.write_message(config);
      command.set_nonblocking(true);

      if let Some(l) = listeners {
        info!("sending listeners to new worker: {:?}", l);
        let res = scm_server.send_listeners(l);
        info!("sent listeners from master: {:?}", res);
      };
      util::disable_close_on_exec(scm_server.fd);

      let command: Channel<OrderMessage,OrderMessageAnswer> = command.into();
      Ok((child.into(), command, scm_server))
    },
    Ok(ForkResult::Child) => {
      trace!("child({}):\twill spawn a child", unsafe { libc::getpid() });
      Command::new(executable_path)
        .arg("worker")
        .arg("--id")
        .arg(id)
        .arg("--fd")
        .arg(client.as_raw_fd().to_string())
        .arg("--scm")
        .arg(scm_client.as_raw_fd().to_string())
        .arg("--configuration-state-fd")
        .arg(state_file.as_raw_fd().to_string())
        .arg("--command-buffer-size")
        .arg(config.command_buffer_size.to_string())
        .arg("--max-command-buffer-size")
        .arg(config.max_command_buffer_size.to_string())
        .exec();

      unreachable!();
    },
    Err(e) => {
      error!("Error during fork(): {}", e);
      Err(e)
    }
  }
}

#[cfg(target_os = "linux")]
pub unsafe fn get_executable_path() -> String {
  use std::fs;

  let path         = fs::read_link("/proc/self/exe").expect("/proc/self/exe doesn't exist");
  let mut path_str = path.into_os_string().into_string().expect("Failed to convert PathBuf to String");

  if path_str.ends_with(" (deleted)") {
    // The kernel appends " (deleted)" to the symlink when the original executable has been replaced
    let len = path_str.len();
    path_str.truncate(len - 10)
  }

  path_str
}

#[cfg(target_os = "macos")]
extern {
  pub fn _NSGetExecutablePath(buf: *mut c_char, size: *mut uint32_t) -> int32_t;
}

#[cfg(target_os = "macos")]
pub unsafe fn get_executable_path() -> String {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let mut size:uint32_t = capacity as u32;
  if _NSGetExecutablePath(ptr, &mut size) == 0 {

    let mut temp2:Vec<u8> = Vec::with_capacity(capacity);
    temp2.extend(repeat(0).take(capacity));
    let pathbuf2 = CString::from_vec_unchecked(temp2);
    let ptr2 = pathbuf2.into_raw();

    if libc::realpath(ptr, ptr2) != null_mut() {
      let path = CString::from_raw(ptr2);
      path.to_str().expect("failed to convert CString to String").to_string()
    } else {
      panic!();
    }
  } else {
    panic!("buffer too small");
  }
}
<|endoftext|>


<commit_before>//! Tests for additional link arguments.

// NOTE: Many of these tests use `without_status()` when passing bogus flags
// because MSVC link.exe just gives a warning on unknown flags (how helpful!),
// and other linkers will return an error.

use cargo_test_support::registry::Package;
use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, basic_manifest, project};

#[cargo_test]
fn build_script_extra_link_arg_bin() {
    let p = project()
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-bins=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("build -v")
        .masquerade_as_nightly_cargo()
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg_bin_single() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]

                name = "foobar"
                version = "0.5.0"
                authors = ["wycats@example.com"]

                [[bin]]
                name = "foo"
                [[bin]]
                name = "bar"
            "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-bins=--bogus-flag-all");
                    println!("cargo:rustc-link-arg-bin=foo=--bogus-flag-foo");
                    println!("cargo:rustc-link-arg-bin=bar=--bogus-flag-bar");
                }
            "#,
        )
        .build();

    p.cargo("build -v")
        .masquerade_as_nightly_cargo()
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name foo [..]-C link-arg=--bogus-flag-all -C link-arg=--bogus-flag-foo[..]",
        )
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name bar [..]-C link-arg=--bogus-flag-all -C link-arg=--bogus-flag-bar[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg() {
    let p = project()
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("build -v")
        .masquerade_as_nightly_cargo()
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn link_arg_missing_target() {
    // Errors when a given target doesn't exist.
    let p = project()
        .file("src/lib.rs", "")
        .file(
            "build.rs",
            r#"fn main() { println!("cargo:rustc-link-arg-cdylib=--bogus"); }"#,
        )
        .build();

    // TODO: Uncomment this if cdylib restriction is re-added (see
    // cdylib_link_arg_transitive below).
    //     p.cargo("check")
    //         .with_status(101)
    //         .with_stderr("\
    // [COMPILING] foo [..]
    // error: invalid instruction `cargo:rustc-link-arg-cdylib` from build script of `foo v0.0.1 ([ROOT]/foo)`
    // The package foo v0.0.1 ([ROOT]/foo) does not have a cdylib target.
    // ")
    //         .run();

    p.change_file(
        "build.rs",
        r#"fn main() { println!("cargo:rustc-link-arg-bins=--bogus"); }"#,
    );

    p.cargo("check")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr("\
[COMPILING] foo [..]
error: invalid instruction `cargo:rustc-link-arg-bins` from build script of `foo v0.0.1 ([ROOT]/foo)`
The package foo v0.0.1 ([ROOT]/foo) does not have a bin target.
")
        .run();

    p.change_file(
        "build.rs",
        r#"fn main() { println!("cargo:rustc-link-arg-bin=abc=--bogus"); }"#,
    );

    p.cargo("check")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[COMPILING] foo [..]
error: invalid instruction `cargo:rustc-link-arg-bin` from build script of `foo v0.0.1 ([ROOT]/foo)`
The package foo v0.0.1 ([ROOT]/foo) does not have a bin target with the name `abc`.
",
        )
        .run();

    p.change_file(
        "build.rs",
        r#"fn main() { println!("cargo:rustc-link-arg-bin=abc"); }"#,
    );

    p.cargo("check")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
[COMPILING] foo [..]
error: invalid instruction `cargo:rustc-link-arg-bin=abc` from build script of `foo v0.0.1 ([ROOT]/foo)`
The instruction should have the form cargo:rustc-link-arg-bin=BIN=ARG
",
        )
        .run();
}

#[cargo_test]
fn cdylib_link_arg_transitive() {
    // There was an unintended regression in 1.50 where rustc-link-arg-cdylib
    // arguments from dependencies were being applied in the parent package.
    // Previously it was silently ignored.
    // See https://github.com/rust-lang/cargo/issues/9562
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"

                [lib]
                crate-type = ["cdylib"]

                [dependencies]
                bar = {path="bar"}
            "#,
        )
        .file("src/lib.rs", "")
        .file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0"))
        .file("bar/src/lib.rs", "")
        .file(
            "bar/build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-cdylib=--bogus");
                }
            "#,
        )
        .build();
    p.cargo("build -v")
        .without_status()
        .with_stderr_contains(
            "\
[COMPILING] bar v1.0.0 [..]
[RUNNING] `rustc --crate-name build_script_build bar/build.rs [..]
[RUNNING] `[..]build-script-build[..]
warning: cargo:rustc-link-arg-cdylib was specified in the build script of bar v1.0.0 \
([ROOT]/foo/bar), but that package does not contain a cdylib target

Allowing this was an unintended change in the 1.50 release, and may become an error in \
the future. For more information, see <https://github.com/rust-lang/cargo/issues/9562>.
[RUNNING] `rustc --crate-name bar bar/src/lib.rs [..]
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C link-arg=--bogus[..]`
",
        )
        .run();
}

#[cargo_test]
fn link_arg_transitive_not_allowed() {
    // Verify that transitive dependencies don't pass link args.
    //
    // Note that rustc-link-arg doesn't have any errors or warnings when it is
    // unused. Perhaps that could be more aggressive, but it is difficult
    // since it could be used for test binaries.
    Package::new("bar", "1.0.0")
        .file("src/lib.rs", "")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg=--bogus");
                }
            "#,
        )
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"

                [lib]
                crate-type = ["cdylib"]

                [dependencies]
                bar = "1.0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build -v")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[UPDATING] [..]
[DOWNLOADING] [..]
[DOWNLOADED] [..]
[COMPILING] bar v1.0.0
[RUNNING] `rustc --crate-name build_script_build [..]
[RUNNING] `[..]/build-script-build[..]
[RUNNING] `rustc --crate-name bar [..]
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]
[FINISHED] dev [..]
",
        )
        .with_stderr_does_not_contain("--bogus")
        .run();
}

#[cargo_test]
fn link_arg_with_doctest() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
                //! ```
                //! let x = 5;
                //! assert_eq!(x, 5);
                //! ```
            "#,
        )
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("test --doc -v")
        .masquerade_as_nightly_cargo()
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustdoc [..]--crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg_tests() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file("tests/test_foo.rs", "")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-tests=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("test -v")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name test_foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg_benches() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file("benches/bench_foo.rs", "")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-benches=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("bench -v")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name bench_foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg_examples() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file("examples/example_foo.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-examples=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("build -v --examples")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name example_foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}
<commit_msg>remove `.masquerade_as_nightly_cargo()` from build_script_extra_link_arg.rs<commit_after>//! Tests for additional link arguments.

// NOTE: Many of these tests use `without_status()` when passing bogus flags
// because MSVC link.exe just gives a warning on unknown flags (how helpful!),
// and other linkers will return an error.

use cargo_test_support::registry::Package;
use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, basic_manifest, project};

#[cargo_test]
fn build_script_extra_link_arg_bin() {
    let p = project()
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-bins=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("build -v")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg_bin_single() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]

                name = "foobar"
                version = "0.5.0"
                authors = ["wycats@example.com"]

                [[bin]]
                name = "foo"
                [[bin]]
                name = "bar"
            "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-bins=--bogus-flag-all");
                    println!("cargo:rustc-link-arg-bin=foo=--bogus-flag-foo");
                    println!("cargo:rustc-link-arg-bin=bar=--bogus-flag-bar");
                }
            "#,
        )
        .build();

    p.cargo("build -v")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name foo [..]-C link-arg=--bogus-flag-all -C link-arg=--bogus-flag-foo[..]",
        )
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name bar [..]-C link-arg=--bogus-flag-all -C link-arg=--bogus-flag-bar[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg() {
    let p = project()
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("build -v")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn link_arg_missing_target() {
    // Errors when a given target doesn't exist.
    let p = project()
        .file("src/lib.rs", "")
        .file(
            "build.rs",
            r#"fn main() { println!("cargo:rustc-link-arg-cdylib=--bogus"); }"#,
        )
        .build();

    // TODO: Uncomment this if cdylib restriction is re-added (see
    // cdylib_link_arg_transitive below).
    //     p.cargo("check")
    //         .with_status(101)
    //         .with_stderr("\
    // [COMPILING] foo [..]
    // error: invalid instruction `cargo:rustc-link-arg-cdylib` from build script of `foo v0.0.1 ([ROOT]/foo)`
    // The package foo v0.0.1 ([ROOT]/foo) does not have a cdylib target.
    // ")
    //         .run();

    p.change_file(
        "build.rs",
        r#"fn main() { println!("cargo:rustc-link-arg-bins=--bogus"); }"#,
    );

    p.cargo("check")
        .with_status(101)
        .with_stderr("\
[COMPILING] foo [..]
error: invalid instruction `cargo:rustc-link-arg-bins` from build script of `foo v0.0.1 ([ROOT]/foo)`
The package foo v0.0.1 ([ROOT]/foo) does not have a bin target.
")
        .run();

    p.change_file(
        "build.rs",
        r#"fn main() { println!("cargo:rustc-link-arg-bin=abc=--bogus"); }"#,
    );

    p.cargo("check")
        .with_status(101)
        .with_stderr(
            "\
[COMPILING] foo [..]
error: invalid instruction `cargo:rustc-link-arg-bin` from build script of `foo v0.0.1 ([ROOT]/foo)`
The package foo v0.0.1 ([ROOT]/foo) does not have a bin target with the name `abc`.
",
        )
        .run();

    p.change_file(
        "build.rs",
        r#"fn main() { println!("cargo:rustc-link-arg-bin=abc"); }"#,
    );

    p.cargo("check")
        .with_status(101)
        .with_stderr(
            "\
[COMPILING] foo [..]
error: invalid instruction `cargo:rustc-link-arg-bin=abc` from build script of `foo v0.0.1 ([ROOT]/foo)`
The instruction should have the form cargo:rustc-link-arg-bin=BIN=ARG
",
        )
        .run();
}

#[cargo_test]
fn cdylib_link_arg_transitive() {
    // There was an unintended regression in 1.50 where rustc-link-arg-cdylib
    // arguments from dependencies were being applied in the parent package.
    // Previously it was silently ignored.
    // See https://github.com/rust-lang/cargo/issues/9562
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"

                [lib]
                crate-type = ["cdylib"]

                [dependencies]
                bar = {path="bar"}
            "#,
        )
        .file("src/lib.rs", "")
        .file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0"))
        .file("bar/src/lib.rs", "")
        .file(
            "bar/build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-cdylib=--bogus");
                }
            "#,
        )
        .build();
    p.cargo("build -v")
        .without_status()
        .with_stderr_contains(
            "\
[COMPILING] bar v1.0.0 [..]
[RUNNING] `rustc --crate-name build_script_build bar/build.rs [..]
[RUNNING] `[..]build-script-build[..]
warning: cargo:rustc-link-arg-cdylib was specified in the build script of bar v1.0.0 \
([ROOT]/foo/bar), but that package does not contain a cdylib target

Allowing this was an unintended change in the 1.50 release, and may become an error in \
the future. For more information, see <https://github.com/rust-lang/cargo/issues/9562>.
[RUNNING] `rustc --crate-name bar bar/src/lib.rs [..]
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C link-arg=--bogus[..]`
",
        )
        .run();
}

#[cargo_test]
fn link_arg_transitive_not_allowed() {
    // Verify that transitive dependencies don't pass link args.
    //
    // Note that rustc-link-arg doesn't have any errors or warnings when it is
    // unused. Perhaps that could be more aggressive, but it is difficult
    // since it could be used for test binaries.
    Package::new("bar", "1.0.0")
        .file("src/lib.rs", "")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg=--bogus");
                }
            "#,
        )
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"

                [lib]
                crate-type = ["cdylib"]

                [dependencies]
                bar = "1.0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build -v")
        .with_stderr(
            "\
[UPDATING] [..]
[DOWNLOADING] [..]
[DOWNLOADED] [..]
[COMPILING] bar v1.0.0
[RUNNING] `rustc --crate-name build_script_build [..]
[RUNNING] `[..]/build-script-build[..]
[RUNNING] `rustc --crate-name bar [..]
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]
[FINISHED] dev [..]
",
        )
        .with_stderr_does_not_contain("--bogus")
        .run();
}

#[cargo_test]
fn link_arg_with_doctest() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
                //! ```
                //! let x = 5;
                //! assert_eq!(x, 5);
                //! ```
            "#,
        )
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("test --doc -v")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustdoc [..]--crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg_tests() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file("tests/test_foo.rs", "")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-tests=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("test -v")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name test_foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg_benches() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file("benches/bench_foo.rs", "")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-benches=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("bench -v")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name bench_foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}

#[cargo_test]
fn build_script_extra_link_arg_examples() {
    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file("examples/example_foo.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
                fn main() {
                    println!("cargo:rustc-link-arg-examples=--this-is-a-bogus-flag");
                }
            "#,
        )
        .build();

    p.cargo("build -v --examples")
        .without_status()
        .with_stderr_contains(
            "[RUNNING] `rustc --crate-name example_foo [..]-C link-arg=--this-is-a-bogus-flag[..]",
        )
        .run();
}
<|endoftext|>