<commit_before>use std::env;
use std::process::Command;
use std::str;

fn main() {
    let (rustc_minor_ver, is_nightly) =
        rustc_minor_nightly().expect("Failed to get rustc version");
    let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
    let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
    let const_extern_fn_cargo_feature =
        env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok();
    let libc_ci = env::var("LIBC_CI").is_ok();
    let target = env::var("TARGET").unwrap();

    if env::var("CARGO_FEATURE_USE_STD").is_ok() {
        println!(
            "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \
             please consider using the `std` cargo feature instead\""
        );
    }

    // The ABI of libc used by libstd is backward compatible with FreeBSD 10.
    // The ABI of libc from crates.io is backward compatible with FreeBSD 11.
    //
    // On CI, we detect the actual FreeBSD version and match its ABI exactly,
    // running tests to ensure that the ABI is correct.
    match which_freebsd() {
        Some(10) if libc_ci || rustc_dep_of_std => {
            println!("cargo:rustc-cfg=freebsd10")
        }
        Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
        Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
        Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
        Some(_) | None => println!("cargo:rustc-cfg=freebsd11"),
    }

    // On CI: deny all warnings
    if libc_ci {
        println!("cargo:rustc-cfg=libc_deny_warnings");
    }

    // Rust >= 1.15 supports private module use:
    if rustc_minor_ver >= 15 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_priv_mod_use");
    }

    // Rust >= 1.19 supports unions:
    if rustc_minor_ver >= 19 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_union");
    }

    // Rust >= 1.24 supports const mem::size_of:
    if rustc_minor_ver >= 24 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_const_size_of");
    }

    // Rust >= 1.25 supports repr(align):
    if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
        println!("cargo:rustc-cfg=libc_align");
    }

    // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
    // Otherwise, it defines an incompatible type to retaining
    // backwards-compatibility.
    if rustc_minor_ver >= 30 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_core_cvoid");
    }

    // Rust >= 1.33 supports repr(packed(N)) and cfg(target_vendor).
    if rustc_minor_ver >= 33 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_packedN");
        println!("cargo:rustc-cfg=libc_cfg_target_vendor");
    }

    // #[thread_local] is currently unstable
    if rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_thread_local");
    }

    if const_extern_fn_cargo_feature {
        if !is_nightly || rustc_minor_ver < 40 {
            panic!("const-extern-fn requires a nightly compiler >= 1.40")
        }
        println!("cargo:rustc-cfg=libc_const_extern_fn");
    }

    // For unknown reason, libiconv can't be linked by adding #[link(name = iconv)] to
    // a macOS-specific struct, so we do the linking here.
    if target.contains("-apple-") {
        println!("cargo:rustc-link-lib=iconv");
    }
}

fn rustc_minor_nightly() -> Option<(u32, bool)> {
    macro_rules! otry {
        ($e:expr) => {
            match $e {
                Some(e) => e,
                None => return None,
            }
        };
    }

    let rustc = otry!(env::var_os("RUSTC"));
    let output = otry!(Command::new(rustc).arg("--version").output().ok());
    let version = otry!(str::from_utf8(&output.stdout).ok());
    let mut pieces = version.split('.');

    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let minor = pieces.next();

    // If `rustc` was built from a tarball, its version string
    // will have neither a git hash nor a commit date
    // (e.g. "rustc 1.39.0"). Treat this case as non-nightly,
    // since a nightly build should either come from CI
    // or a git checkout
    let nightly_raw = otry!(pieces.next()).split('-').nth(1);
    let nightly = nightly_raw
        .map(|raw| raw.starts_with("dev") || raw.starts_with("nightly"))
        .unwrap_or(false);
    let minor = otry!(otry!(minor).parse().ok());

    Some((minor, nightly))
}

fn which_freebsd() -> Option<i32> {
    let output = std::process::Command::new("freebsd-version").output().ok();
    if output.is_none() {
        return None;
    }
    let output = output.unwrap();
    if !output.status.success() {
        return None;
    }

    let stdout = String::from_utf8(output.stdout).ok();
    if stdout.is_none() {
        return None;
    }
    let stdout = stdout.unwrap();

    match &stdout {
        s if s.starts_with("10") => Some(10),
        s if s.starts_with("11") => Some(11),
        s if s.starts_with("12") => Some(12),
        s if s.starts_with("13") => Some(13),
        _ => None,
    }
}
<commit_msg>Auto merge of #2138 - JohnTitor:rerun-if-changed, r=Amanieu<commit_after>use std::env;
use std::process::Command;
use std::str;

fn main() {
    // Avoid unnecessary re-building.
    println!("cargo:rerun-if-changed=build.rs");

    let (rustc_minor_ver, is_nightly) =
        rustc_minor_nightly().expect("Failed to get rustc version");
    let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
    let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
    let const_extern_fn_cargo_feature =
        env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok();
    let libc_ci = env::var("LIBC_CI").is_ok();
    let target = env::var("TARGET").unwrap();

    if env::var("CARGO_FEATURE_USE_STD").is_ok() {
        println!(
            "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \
             please consider using the `std` cargo feature instead\""
        );
    }

    // The ABI of libc used by libstd is backward compatible with FreeBSD 10.
    // The ABI of libc from crates.io is backward compatible with FreeBSD 11.
    //
    // On CI, we detect the actual FreeBSD version and match its ABI exactly,
    // running tests to ensure that the ABI is correct.
    match which_freebsd() {
        Some(10) if libc_ci || rustc_dep_of_std => {
            println!("cargo:rustc-cfg=freebsd10")
        }
        Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
        Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
        Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
        Some(_) | None => println!("cargo:rustc-cfg=freebsd11"),
    }

    // On CI: deny all warnings
    if libc_ci {
        println!("cargo:rustc-cfg=libc_deny_warnings");
    }

    // Rust >= 1.15 supports private module use:
    if rustc_minor_ver >= 15 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_priv_mod_use");
    }

    // Rust >= 1.19 supports unions:
    if rustc_minor_ver >= 19 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_union");
    }

    // Rust >= 1.24 supports const mem::size_of:
    if rustc_minor_ver >= 24 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_const_size_of");
    }

    // Rust >= 1.25 supports repr(align):
    if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
        println!("cargo:rustc-cfg=libc_align");
    }

    // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
    // Otherwise, it defines an incompatible type to retaining
    // backwards-compatibility.
    if rustc_minor_ver >= 30 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_core_cvoid");
    }

    // Rust >= 1.33 supports repr(packed(N)) and cfg(target_vendor).
    if rustc_minor_ver >= 33 || rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_packedN");
        println!("cargo:rustc-cfg=libc_cfg_target_vendor");
    }

    // #[thread_local] is currently unstable
    if rustc_dep_of_std {
        println!("cargo:rustc-cfg=libc_thread_local");
    }

    if const_extern_fn_cargo_feature {
        if !is_nightly || rustc_minor_ver < 40 {
            panic!("const-extern-fn requires a nightly compiler >= 1.40")
        }
        println!("cargo:rustc-cfg=libc_const_extern_fn");
    }

    // For unknown reason, libiconv can't be linked by adding #[link(name = iconv)] to
    // a macOS-specific struct, so we do the linking here.
    if target.contains("-apple-") {
        println!("cargo:rustc-link-lib=iconv");
    }
}

fn rustc_minor_nightly() -> Option<(u32, bool)> {
    macro_rules! otry {
        ($e:expr) => {
            match $e {
                Some(e) => e,
                None => return None,
            }
        };
    }

    let rustc = otry!(env::var_os("RUSTC"));
    let output = otry!(Command::new(rustc).arg("--version").output().ok());
    let version = otry!(str::from_utf8(&output.stdout).ok());
    let mut pieces = version.split('.');

    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let minor = pieces.next();

    // If `rustc` was built from a tarball, its version string
    // will have neither a git hash nor a commit date
    // (e.g. "rustc 1.39.0"). Treat this case as non-nightly,
    // since a nightly build should either come from CI
    // or a git checkout
    let nightly_raw = otry!(pieces.next()).split('-').nth(1);
    let nightly = nightly_raw
        .map(|raw| raw.starts_with("dev") || raw.starts_with("nightly"))
        .unwrap_or(false);
    let minor = otry!(otry!(minor).parse().ok());

    Some((minor, nightly))
}

fn which_freebsd() -> Option<i32> {
    let output = std::process::Command::new("freebsd-version").output().ok();
    if output.is_none() {
        return None;
    }
    let output = output.unwrap();
    if !output.status.success() {
        return None;
    }

    let stdout = String::from_utf8(output.stdout).ok();
    if stdout.is_none() {
        return None;
    }
    let stdout = stdout.unwrap();

    match &stdout {
        s if s.starts_with("10") => Some(10),
        s if s.starts_with("11") => Some(11),
        s if s.starts_with("12") => Some(12),
        s if s.starts_with("13") => Some(13),
        _ => None,
    }
}
<|endoftext|>


<commit_before>fn main() {
    manage_docs();
}

#[cfg(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs"))]
fn manage_docs() {
    extern crate lgpl_docs;
    const PATH: &'static str = "src";
    const IGNORES: &'static [&'static str] = &[];
    lgpl_docs::purge(PATH, IGNORES);
    if cfg!(feature = "embed-lgpl-docs") {
        lgpl_docs::embed(lgpl_docs::Library::Cairo, PATH, IGNORES);
    }
}

#[cfg(not(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs")))]
fn manage_docs() {}
<commit_msg>Add lib.rs to ignore purge files<commit_after>fn main() {
    manage_docs();
}

#[cfg(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs"))]
fn manage_docs() {
    extern crate lgpl_docs;
    const PATH: &'static str = "src";
    const IGNORES: &'static [&'static str] = &["lib.rs"];
    lgpl_docs::purge(PATH, IGNORES);
    if cfg!(feature = "embed-lgpl-docs") {
        lgpl_docs::embed(lgpl_docs::Library::Cairo, PATH, IGNORES);
    }
}

#[cfg(not(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs")))]
fn manage_docs() {}
<|endoftext|>


<commit_before>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;

use conduit::{header, Host, RequestExt, Scheme, StatusCode};
use conduit_cookie::RequestSession;
use sentry::Level;

use std::fmt::{self, Display, Formatter};
use std::time::{SystemTime, UNIX_EPOCH};

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

const FILTERED_HEADERS: &[&str] = &["Authorization", "Cookie", "X-Real-Ip", "X-Forwarded-For"];

#[derive(Default)]
pub(super) struct LogRequests();

struct OriginalPath(String);

impl Middleware for LogRequests {
    fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
        let path = OriginalPath(req.path().to_string());
        req.mut_extensions().insert(path);
        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        let response_time =
            if let Ok(start_ms) = request_header(req, "x-request-start").parse::<u128>() {
                let current_ms = SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .expect("Time went way backwards")
                    .as_millis();

                if current_ms > start_ms {
                    // The result cannot be negative
                    current_ms - start_ms
                } else {
                    // Because our nginx proxy and app run on the same dyno in production, we
                    // shouldn't have to worry about clock drift. But if something goes wrong,
                    // calculate the response time based on when the request reached this app.
                    fallback_response_time(req)
                }
            } else {
                // X-Request-Start header couldn't be parsed.
                // We are probably running locally and not behind nginx.
                fallback_response_time(req)
            };

        // This will only trucate for requests lasting > 500 million years
        let response_time = response_time as u64;

        println!(
            "{}",
            RequestLine {
                req,
                res: &res,
                response_time,
            }
        );

        report_to_sentry(req, &res, response_time);

        res
    }
}

/// Calculate the response time based on when the request reached the in-app web server.
///
/// This serves as a fallback in case the `X-Request-Start` header is missing or invalid.
fn fallback_response_time(req: &mut dyn RequestExt) -> u128 {
    req.elapsed().as_millis()
}

struct CustomMetadata {
    entries: Vec<(&'static str, String)>,
}

pub fn add_custom_metadata<V: Display>(req: &mut dyn RequestExt, key: &'static str, value: V) {
    if let Some(metadata) = req.mut_extensions().find_mut::<CustomMetadata>() {
        metadata.entries.push((key, value.to_string()));
    } else {
        let mut metadata = CustomMetadata {
            entries: Vec::new(),
        };
        metadata.entries.push((key, value.to_string()));
        req.mut_extensions().insert(metadata);
    }
}

fn report_to_sentry(req: &dyn RequestExt, res: &AfterResult, response_time: u64) {
    let (message, level) = match res {
        Err(e) => (e.to_string(), Level::Error),
        Ok(_) => return,
    };

    let config = |scope: &mut sentry::Scope| {
        let method = Some(req.method().as_str().to_owned());

        let scheme = match req.scheme() {
            Scheme::Http => "http",
            Scheme::Https => "https",
        };

        let host = match req.host() {
            Host::Name(name) => name.to_owned(),
            Host::Socket(addr) => addr.to_string(),
        };

        let path = &req.extensions().find::<OriginalPath>().unwrap().0;

        let url = format!("{}://{}{}", scheme, host, path).parse().ok();

        {
            let id = req.session().get("user_id").map(|str| str.to_string());

            let user = sentry::User {
                id,
                ..Default::default()
            };

            scope.set_user(Some(user));
        }

        {
            let headers = req
                .headers()
                .iter()
                .filter(|(k, _v)| !FILTERED_HEADERS.iter().any(|name| k == name))
                .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or_default().to_string()))
                .collect();

            let sentry_req = sentry::protocol::Request {
                url,
                method,
                headers,
                ..Default::default()
            };

            scope.add_event_processor(Box::new(move |mut event| {
                if event.request.is_none() {
                    event.request = Some(sentry_req.clone());
                }
                Some(event)
            }));
        }

        if let Some(request_id) = req
            .headers()
            .get("x-request-id")
            .and_then(|value| value.to_str().ok())
        {
            scope.set_tag("request.id", request_id);
        }

        {
            let status = res
                .as_ref()
                .map(|resp| resp.status())
                .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

            scope.set_tag("response.status", status.as_str());
        }

        scope.set_extra("Response time [ms]", response_time.into());

        if let Some(metadata) = req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                scope.set_extra(key, value.to_string().into());
            }
        }
    };

    sentry::with_scope(config, || sentry::capture_message(&message, level));
}

#[cfg(test)]
pub(crate) fn get_log_message(req: &dyn RequestExt, key: &'static str) -> String {
    // Unwrap shouldn't panic as no other code has access to the private struct to remove it
    for (k, v) in &req.extensions().find::<CustomMetadata>().unwrap().entries {
        if key == *k {
            return v.clone();
        }
    }
    panic!("expected log message for {} not found", key);
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
    response_time: u64,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let (at, status) = match self.res {
            Ok(resp) => ("info", resp.status()),
            Err(_) => ("error", StatusCode::INTERNAL_SERVER_ERROR),
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;
        line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;
        line.add_field("service", TimeMs(self.response_time))?;
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        if let Some(metadata) = self.req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                line.add_quoted_field(key, value)?;
            }
        }

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if self.response_time > SLOW_REQUEST_THRESHOLD_MS {
            line.add_marker("SLOW REQUEST")?;
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        write!(
            f,
            "{}",
            self.0.extensions().find::<OriginalPath>().unwrap().0
        )?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct TimeMs(u64);

impl Display for TimeMs {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)?;
        f.write_str("ms")?;
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<commit_msg>Avoid logging request_id for successful download redirects<commit_after>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;

use conduit::{header, Host, RequestExt, Scheme, StatusCode};
use conduit_cookie::RequestSession;
use sentry::Level;

use std::fmt::{self, Display, Formatter};
use std::time::{SystemTime, UNIX_EPOCH};

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

const FILTERED_HEADERS: &[&str] = &["Authorization", "Cookie", "X-Real-Ip", "X-Forwarded-For"];

#[derive(Default)]
pub(super) struct LogRequests();

struct OriginalPath(String);

impl Middleware for LogRequests {
    fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
        let path = OriginalPath(req.path().to_string());
        req.mut_extensions().insert(path);
        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        let response_time =
            if let Ok(start_ms) = request_header(req, "x-request-start").parse::<u128>() {
                let current_ms = SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .expect("Time went way backwards")
                    .as_millis();

                if current_ms > start_ms {
                    // The result cannot be negative
                    current_ms - start_ms
                } else {
                    // Because our nginx proxy and app run on the same dyno in production, we
                    // shouldn't have to worry about clock drift. But if something goes wrong,
                    // calculate the response time based on when the request reached this app.
                    fallback_response_time(req)
                }
            } else {
                // X-Request-Start header couldn't be parsed.
                // We are probably running locally and not behind nginx.
                fallback_response_time(req)
            };

        // This will only trucate for requests lasting > 500 million years
        let response_time = response_time as u64;

        println!(
            "{}",
            RequestLine {
                req,
                res: &res,
                response_time,
            }
        );

        report_to_sentry(req, &res, response_time);

        res
    }
}

/// Calculate the response time based on when the request reached the in-app web server.
///
/// This serves as a fallback in case the `X-Request-Start` header is missing or invalid.
fn fallback_response_time(req: &mut dyn RequestExt) -> u128 {
    req.elapsed().as_millis()
}

struct CustomMetadata {
    entries: Vec<(&'static str, String)>,
}

pub fn add_custom_metadata<V: Display>(req: &mut dyn RequestExt, key: &'static str, value: V) {
    if let Some(metadata) = req.mut_extensions().find_mut::<CustomMetadata>() {
        metadata.entries.push((key, value.to_string()));
    } else {
        let mut metadata = CustomMetadata {
            entries: Vec::new(),
        };
        metadata.entries.push((key, value.to_string()));
        req.mut_extensions().insert(metadata);
    }
}

fn report_to_sentry(req: &dyn RequestExt, res: &AfterResult, response_time: u64) {
    let (message, level) = match res {
        Err(e) => (e.to_string(), Level::Error),
        Ok(_) => return,
    };

    let config = |scope: &mut sentry::Scope| {
        let method = Some(req.method().as_str().to_owned());

        let scheme = match req.scheme() {
            Scheme::Http => "http",
            Scheme::Https => "https",
        };

        let host = match req.host() {
            Host::Name(name) => name.to_owned(),
            Host::Socket(addr) => addr.to_string(),
        };

        let path = &req.extensions().find::<OriginalPath>().unwrap().0;

        let url = format!("{}://{}{}", scheme, host, path).parse().ok();

        {
            let id = req.session().get("user_id").map(|str| str.to_string());

            let user = sentry::User {
                id,
                ..Default::default()
            };

            scope.set_user(Some(user));
        }

        {
            let headers = req
                .headers()
                .iter()
                .filter(|(k, _v)| !FILTERED_HEADERS.iter().any(|name| k == name))
                .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or_default().to_string()))
                .collect();

            let sentry_req = sentry::protocol::Request {
                url,
                method,
                headers,
                ..Default::default()
            };

            scope.add_event_processor(Box::new(move |mut event| {
                if event.request.is_none() {
                    event.request = Some(sentry_req.clone());
                }
                Some(event)
            }));
        }

        if let Some(request_id) = req
            .headers()
            .get("x-request-id")
            .and_then(|value| value.to_str().ok())
        {
            scope.set_tag("request.id", request_id);
        }

        {
            let status = res
                .as_ref()
                .map(|resp| resp.status())
                .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

            scope.set_tag("response.status", status.as_str());
        }

        scope.set_extra("Response time [ms]", response_time.into());

        if let Some(metadata) = req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                scope.set_extra(key, value.to_string().into());
            }
        }
    };

    sentry::with_scope(config, || sentry::capture_message(&message, level));
}

#[cfg(test)]
pub(crate) fn get_log_message(req: &dyn RequestExt, key: &'static str) -> String {
    // Unwrap shouldn't panic as no other code has access to the private struct to remove it
    for (k, v) in &req.extensions().find::<CustomMetadata>().unwrap().entries {
        if key == *k {
            return v.clone();
        }
    }
    panic!("expected log message for {} not found", key);
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
    response_time: u64,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let (at, status) = match self.res {
            Ok(resp) => ("info", resp.status()),
            Err(_) => ("error", StatusCode::INTERNAL_SERVER_ERROR),
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;

        // The request_id is not logged for successful download requests
        if !(self.req.path().ends_with("/download")
            && self
                .res
                .as_ref()
                .ok()
                .map(|ok| ok.status().is_redirection())
                == Some(true))
        {
            line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        }

        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;
        line.add_field("service", TimeMs(self.response_time))?;
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        if let Some(metadata) = self.req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                line.add_quoted_field(key, value)?;
            }
        }

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if self.response_time > SLOW_REQUEST_THRESHOLD_MS {
            line.add_marker("SLOW REQUEST")?;
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        write!(
            f,
            "{}",
            self.0.extensions().find::<OriginalPath>().unwrap().0
        )?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct TimeMs(u64);

impl Display for TimeMs {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)?;
        f.write_str("ms")?;
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix bug with Range<commit_after><|endoftext|>


<commit_before>#![cfg_attr(test, feature(test))]

extern crate random_choice;
extern crate test;

#[cfg(test)]
mod benches {
    use test::Bencher;
    use random_choice::RandomChoice;

    #[bench]
    fn bench_random_choice_1000_it_f64(b: &mut Bencher) {
        let capacity: usize = 1000;
        let mut samples: Vec<f64> = Vec::with_capacity(capacity);
        let mut weights: Vec<f64> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f64);
            weights.push((i + 1usize) as f64);
        }
        b.iter(|| {
            RandomChoice::random_choice_f64(&samples, &weights, capacity);
        });
    }

    #[bench]
    fn bench_random_choice_in_place_1000_it_f64(b: &mut Bencher) {
        let capacity: usize = 1000;
        let mut samples: Vec<f64> = Vec::with_capacity(capacity);
        let mut weights: Vec<f64> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f64);
            weights.push((i + 1usize) as f64);
        }
        b.iter(|| {
            RandomChoice::random_choice_in_place_f64(&mut samples, &weights);
        });
    }

    #[bench]
    fn bench_random_choice_500_it_f64(b: &mut Bencher) {
        let capacity: usize = 500;
        let mut samples: Vec<f64> = Vec::with_capacity(capacity);
        let mut weights: Vec<f64> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f64);
            weights.push((i + 1usize) as f64);
        }
        b.iter(|| {
            RandomChoice::random_choice_f64(&samples, &weights, capacity);
        });
    }

    #[bench]
    fn bench_random_choice_in_place_500_it_f64(b: &mut Bencher) {
        let capacity: usize = 500;
        let mut samples: Vec<f64> = Vec::with_capacity(capacity);
        let mut weights: Vec<f64> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f64);
            weights.push((i + 1usize) as f64);
        }
        b.iter(|| {
            RandomChoice::random_choice_in_place_f64(&mut samples, &weights);
        });
    }

    #[bench]
    fn bench_random_choice_1000_it_f32(b: &mut Bencher) {
        let capacity: usize = 1000;
        let mut samples: Vec<f32> = Vec::with_capacity(capacity);
        let mut weights: Vec<f32> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f32);
            weights.push((i + 1usize) as f32);
        }
        b.iter(|| {
            RandomChoice::random_choice_f32(&samples, &weights, capacity);
        });
    }

    #[bench]
    fn bench_random_choice_500_it_f32(b: &mut Bencher) {
        let capacity: usize = 500;
        let mut samples: Vec<f32> = Vec::with_capacity(capacity);
        let mut weights: Vec<f32> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f32);
            weights.push((i + 1usize) as f32);
        }
        b.iter(|| {
            RandomChoice::random_choice_f32(&samples, &weights, capacity);
        });
    }

    #[bench]
    fn bench_random_choice_in_place_1000_it_f32(b: &mut Bencher) {
        let capacity: usize = 1000;
        let mut samples: Vec<f32> = Vec::with_capacity(capacity);
        let mut weights: Vec<f32> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f32);
            weights.push((i + 1usize) as f32);
        }
        b.iter(|| {
            RandomChoice::random_choice_in_place_f32(&mut samples, &weights);
        });
    }

    #[bench]
    fn bench_random_choice_in_place_500_it_f32(b: &mut Bencher) {
        let capacity: usize = 500;
        let mut samples: Vec<f32> = Vec::with_capacity(capacity);
        let mut weights: Vec<f32> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f32);
            weights.push((i + 1usize) as f32);
        }
        b.iter(|| {
            RandomChoice::random_choice_in_place_f32(&mut samples, &weights);
        });
    }
}<commit_msg>benches fixed<commit_after>#![cfg_attr(test, feature(test))]

extern crate random_choice;
extern crate test;

#[cfg(test)]
mod benches {
    use test::Bencher;
    use random_choice::random_choice;

    #[bench]
    fn bench_random_choice_1000_it_f64(b: &mut Bencher) {
        let capacity: usize = 1000;
        let mut samples: Vec<f64> = Vec::with_capacity(capacity);
        let mut weights: Vec<f64> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f64);
            weights.push((i + 1usize) as f64);
        }
        b.iter(|| {
            random_choice().random_choice_f64(&samples, &weights, capacity);
        });
    }

    #[bench]
    fn bench_random_choice_in_place_1000_it_f64(b: &mut Bencher) {
        let capacity: usize = 1000;
        let mut samples: Vec<f64> = Vec::with_capacity(capacity);
        let mut weights: Vec<f64> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f64);
            weights.push((i + 1usize) as f64);
        }
        b.iter(|| {
            random_choice().random_choice_in_place_f64(&mut samples, &weights);
        });
    }

    #[bench]
    fn bench_random_choice_500_it_f64(b: &mut Bencher) {
        let capacity: usize = 500;
        let mut samples: Vec<f64> = Vec::with_capacity(capacity);
        let mut weights: Vec<f64> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f64);
            weights.push((i + 1usize) as f64);
        }
        b.iter(|| {
            random_choice().random_choice_f64(&samples, &weights, capacity);
        });
    }

    #[bench]
    fn bench_random_choice_in_place_500_it_f64(b: &mut Bencher) {
        let capacity: usize = 500;
        let mut samples: Vec<f64> = Vec::with_capacity(capacity);
        let mut weights: Vec<f64> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f64);
            weights.push((i + 1usize) as f64);
        }
        b.iter(|| {
            random_choice().random_choice_in_place_f64(&mut samples, &weights);
        });
    }

    #[bench]
    fn bench_random_choice_1000_it_f32(b: &mut Bencher) {
        let capacity: usize = 1000;
        let mut samples: Vec<f32> = Vec::with_capacity(capacity);
        let mut weights: Vec<f32> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f32);
            weights.push((i + 1usize) as f32);
        }
        b.iter(|| {
            random_choice().random_choice_f32(&samples, &weights, capacity);
        });
    }

    #[bench]
    fn bench_random_choice_500_it_f32(b: &mut Bencher) {
        let capacity: usize = 500;
        let mut samples: Vec<f32> = Vec::with_capacity(capacity);
        let mut weights: Vec<f32> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f32);
            weights.push((i + 1usize) as f32);
        }
        b.iter(|| {
            random_choice().random_choice_f32(&samples, &weights, capacity);
        });
    }

    #[bench]
    fn bench_random_choice_in_place_1000_it_f32(b: &mut Bencher) {
        let capacity: usize = 1000;
        let mut samples: Vec<f32> = Vec::with_capacity(capacity);
        let mut weights: Vec<f32> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f32);
            weights.push((i + 1usize) as f32);
        }
        b.iter(|| {
            random_choice().random_choice_in_place_f32(&mut samples, &weights);
        });
    }

    #[bench]
    fn bench_random_choice_in_place_500_it_f32(b: &mut Bencher) {
        let capacity: usize = 500;
        let mut samples: Vec<f32> = Vec::with_capacity(capacity);
        let mut weights: Vec<f32> = Vec::with_capacity(capacity);

        for i in 0..capacity {
            samples.push((i + 1usize) as f32);
            weights.push((i + 1usize) as f32);
        }
        b.iter(|| {
            random_choice().random_choice_in_place_f32(&mut samples, &weights);
        });
    }
}<|endoftext|>


<commit_before>// Copyright 2015 Vadim Nazarov.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various subroutines for computing a distance between sequences.

use std::iter::Zip;

pub fn hamm_dist(alpha: &[u8], beta: &[u8]) -> Result<u32, bool> {
    if alpha.len() != beta.len() {
        Result(0, true)
    } else {
        let mut score : u32 = 0;
        for (a, b) in Zip::new(alpha, beta) {
            score += alpha == beta;
        }
        Result(score, false)
    }
}

pub fn lev_dist(alpha: &[u8], beta: &[u8]) -> u32 {

}

#[cfg(test)]
mod tests {

    #[test]
    fn test_hamming_dist() {
        // let x = b"GACTATATCG";
        // let y = b"TTTAGCTAGC";
        // // GTCTGCATGC
        // //  |  ||  ||
        // // TTTAGCTAGC
        // assert_eq!(hamm_dist(x, y), 5)

        assert!(true)
    }

    #[test]
    fn test_levenshtein_dist() {
        // let x = b"ACCGTGGAT";
        // let y = b"AAAAACCGTTGAT";
        // // ----ACCGTGGAT
        // //     ||||| |||
        // // AAAAACCGTTGAT
        // assert_eq!(lev_dist(x, y), align_global!(x, y, -1, 1, |a: u8, b: u8| if a == b {1i32} else {-1i32}))

        assert!(true)
    }
}
<commit_msg>add hamm_dist(), docs and test for it<commit_after>// Copyright 2015 Vadim Nazarov.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various subroutines for computing a distance between sequences.
//! Complexity: O(n) for strings of length n for the Hamming distance;
//! O(n * m) for strings of length n and m for the Levenshtein (or edit) distance.
//!
//! # Example
//!
//! ```
//! use bio::alignment::distance::*;
//! let x = b"GTCTGCATGCG";
//! let y = b"TTTAGCTAGCG";
//! // GTCTGCATGCG
//! //  |  ||  |||
//! // TTTAGCTAGCG
//! match hamm_dist(x, y) {
//!     Ok(s)  => println!("Score is: {}", s),  // Score is 5
//!     Err(e) => println!("Error: {}", e),     // No error in this example
//! }
//!
//! let x = b"ACCGTGGAT";
//! let y = b"AAAAACCGTTGAT";
//! // ----ACCGTGGAT
//! //     ||||| |||
//! // AAAAACCGTTGAT
//! let l_score = lev_dist(x, y);  // Score is 5
//! ```

use itertools::Zip;
use std::result::Result;

/// Compute the Hamming distance between two strings. If returns the `Result<u32, &str>` type
/// with the first element corresponding to the distance between two strings and the second one to the error message
/// when two strings are not of equal sizes.
///
/// ```
/// use bio::alignment::distance::*;
/// let x = b"GTCTGCATGCG";
/// let y = b"TTTAGCTAGCG";
/// // GTCTGCATGCG
/// //  |  ||  |||
/// // TTTAGCTAGCG
/// match hamm_dist(x, y) {
///     Ok(s)  => println!("Score is: {}", s),  // Score is 5
///     Err(e) => println!("Error: {}", e),     // No error in this example
/// }
/// assert!(hamm_dist(x, y).is_ok());
/// assert_eq!(hamm_dist(x, y).unwrap(), 5);
/// ```
///
/// In case of the error:
///
/// ```
/// let x = b"GACTATATCGA";
/// let y = b"TTTAGCTC";
/// match hamm_dist(x, y) {
///     Ok(s)  => println!("Score is: {}", s),  // No score because strings are of unequal sizes.
///     Err(e) => println!("Error: {}", e),     // Will print "Error: hamming distance: strings are of unequal sizes!"
/// }
/// assert!(hamm_dist(x, y).is_err())
/// ```
pub fn hamm_dist(alpha: &[u8], beta: &[u8]) -> Result<u32, &'static str> {
    if alpha.len() != beta.len() {
        Err("hamming distance: strings are of unequal sizes!")
    } else {
        let mut score : u32 = 0;
        for (a, b) in Zip::new((alpha, beta)) {
            if a != b { score += 1; }
        }
        Ok(score)
    }
}

pub fn lev_dist(alpha: &[u8], beta: &[u8]) -> u32 {
    // let mut prev_col : &[u32];
    // let mut cur_col : &[u32];
    1
}

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

    #[test]
    fn test_hamming_dist_good() {
        let x = b"GTCTGCATGCG";
        let y = b"TTTAGCTAGCG";
        // GTCTGCATGCG
        //  |  ||  |||
        // TTTAGCTAGCG
        assert!(hamm_dist(x, y).is_ok());
        assert_eq!(hamm_dist(x, y).unwrap(), 5);
    }

    #[test]
    fn test_hamming_dist_bad() {
        let x = b"GACTATATCGA";
        let y = b"TTTAGCTC";
        assert!(hamm_dist(x, y).is_err());
    }

    #[test]
    fn test_levenshtein_dist() {
        // let x = b"ACCGTGGAT";
        // let y = b"AAAAACCGTTGAT";
        // // ----ACCGTGGAT
        // //     ||||| |||
        // // AAAAACCGTTGAT
        // assert_eq!(lev_dist(x, y), align_global!(x, y, -1, 1, |a: u8, b: u8| if a == b {1i32} else {-1i32}))

        assert!(true)
    }
}
<|endoftext|>


<commit_before>use super::RawOutcome;
use crate::core::LowercaseText;
use crate::utils::is_stop_char;
use crate::Lang;

const BUL: &str = "абвгдежзийклмнопрстуфхцчшщъьюя";
const RUS: &str = "абвгдежзийклмнопрстуфхцчшщъыьэюяё";
const UKR: &str = "абвгдежзийклмнопрстуфхцчшщьюяєіїґ";
const BEL: &str = "абвгдежзйклмнопрстуфхцчшыьэюяёіў";
const SRP: &str = "абвгдежзиклмнопрстуфхцчшђјљњћџ";
const MKD: &str = "абвгдежзиклмнопрстуфхцчшѓѕјљњќџ";

pub fn alphabet_calculate_scores(text: &LowercaseText) -> RawOutcome {
    let mut raw_scores = vec![
        (Lang::Bul, 0i32),
        (Lang::Rus, 0i32),
        (Lang::Ukr, 0i32),
        (Lang::Bel, 0i32),
        (Lang::Srp, 0i32),
        (Lang::Mkd, 0i32),
    ];

    let max_raw_score = text.chars().filter(|&ch| !is_stop_char(ch)).count();

    for (lang, score) in &mut raw_scores {
        let alphabet = get_lang_chars(*lang);

        for ch in text.chars() {
            if is_stop_char(ch) {
                continue;
            };
            if alphabet.contains(&ch) {
                *score += 1;
            } else {
                *score -= 1;
            }
        }
    }

    raw_scores.sort_by(|a, b| b.1.cmp(&a.1));

    let raw_scores: Vec<(Lang, usize)> = raw_scores
        .into_iter()
        .map(|(l, s)| {
            let score = if s < 0 { 0usize } else { s as usize };
            (l, score)
        })
        .collect();

    let mut normalized_scores = vec![];

    for &(lang, raw_score) in &raw_scores {
        let normalized_score = raw_score as f64 / max_raw_score as f64;
        normalized_scores.push((lang, normalized_score));
    }

    RawOutcome {
        count: max_raw_score,
        raw_scores: raw_scores,
        scores: normalized_scores,
    }
}

fn get_lang_chars(lang: Lang) -> Vec<char> {
    let alphabet = match lang {
        Lang::Bul => BUL,
        Lang::Rus => RUS,
        Lang::Ukr => UKR,
        Lang::Bel => BEL,
        Lang::Srp => SRP,
        Lang::Mkd => MKD,

        _ => panic!(format!("No alphabet for {}", lang)),
    };
    alphabet.chars().collect()
}
<commit_msg>Add some tests to src/alphabets/cyrillic.rs<commit_after>use super::RawOutcome;
use crate::core::LowercaseText;
use crate::utils::is_stop_char;
use crate::Lang;

const BUL: &str = "абвгдежзийклмнопрстуфхцчшщъьюя";
const RUS: &str = "абвгдежзийклмнопрстуфхцчшщъыьэюяё";
const UKR: &str = "абвгдежзийклмнопрстуфхцчшщьюяєіїґ";
const BEL: &str = "абвгдежзйклмнопрстуфхцчшыьэюяёіў";
const SRP: &str = "абвгдежзиклмнопрстуфхцчшђјљњћџ";
const MKD: &str = "абвгдежзиклмнопрстуфхцчшѓѕјљњќџ";

const ALL: &str = "абвгдежзийклмнопрстуфхцчшщъыьэюяёєіїґўђјљњћџѓѕќ";

pub fn alphabet_calculate_scores(text: &LowercaseText) -> RawOutcome {
    let mut raw_scores = vec![
        (Lang::Bul, 0i32),
        (Lang::Rus, 0i32),
        (Lang::Ukr, 0i32),
        (Lang::Bel, 0i32),
        (Lang::Srp, 0i32),
        (Lang::Mkd, 0i32),
    ];

    let max_raw_score = text.chars().filter(|&ch| is_relevant(ch)).count();

    for (lang, score) in &mut raw_scores {
        let alphabet = get_lang_chars(*lang);

        for ch in text.chars() {
            if !is_relevant(ch) {
                continue;
            } else if alphabet.contains(&ch) {
                *score += 1;
            } else {
                *score -= 1;
            }
        }
    }

    raw_scores.sort_by(|a, b| b.1.cmp(&a.1));

    let raw_scores: Vec<(Lang, usize)> = raw_scores
        .into_iter()
        .map(|(l, s)| {
            let score = if s < 0 { 0usize } else { s as usize };
            (l, score)
        })
        .collect();

    let mut normalized_scores = vec![];

    for &(lang, raw_score) in &raw_scores {
        // avoid devision by zero
        let normalized_score = if raw_score == 0 {
            0.0
        } else {
            raw_score as f64 / max_raw_score as f64
        };
        normalized_scores.push((lang, normalized_score));
    }

    RawOutcome {
        count: max_raw_score,
        raw_scores: raw_scores,
        scores: normalized_scores,
    }
}

fn is_relevant(ch: char) -> bool {
    ALL.chars().find(|&c| c == ch).is_some()
}

fn get_lang_chars(lang: Lang) -> Vec<char> {
    let alphabet = match lang {
        Lang::Bul => BUL,
        Lang::Rus => RUS,
        Lang::Ukr => UKR,
        Lang::Bel => BEL,
        Lang::Srp => SRP,
        Lang::Mkd => MKD,

        _ => panic!(format!("No alphabet for {}", lang)),
    };
    alphabet.chars().collect()
}

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

    const CYRILLIC_LANGS: [Lang; 6] = [
        Lang::Rus,
        Lang::Ukr,
        Lang::Srp,
        Lang::Bel,
        Lang::Mkd,
        Lang::Bul,
    ];

    fn fetch<T: Copy>(lang: &Lang, scores: &[(Lang, T)]) -> T {
        scores.iter().find(|(l, _)| l == lang).unwrap().1
    }

    #[test]
    fn test_when_latin_is_given() {
        let text = LowercaseText::new("Foobar, hoh");
        let RawOutcome {
            count,
            raw_scores,
            scores,
        } = alphabet_calculate_scores(&text);

        assert_eq!(count, 0);
        assert_eq!(raw_scores.len(), CYRILLIC_LANGS.len());
        assert_eq!(scores.len(), CYRILLIC_LANGS.len());

        for lang in &CYRILLIC_LANGS {
            let raw_score = fetch(lang, &raw_scores);
            assert_eq!(raw_score, 0);
        }

        for lang in &CYRILLIC_LANGS {
            let score = fetch(lang, &scores);
            assert_eq!(score, 0.0);
        }
    }

    #[test]
    fn test_when_common_cyrllic_is_given() {
        let text = LowercaseText::new("абвг ww");
        let RawOutcome {
            count,
            raw_scores,
            scores,
        } = alphabet_calculate_scores(&text);

        assert_eq!(count, 4);

        for lang in &CYRILLIC_LANGS {
            let raw_score = fetch(lang, &raw_scores);
            assert_eq!(raw_score, 4);
        }

        for lang in &CYRILLIC_LANGS {
            let score = fetch(lang, &scores);
            assert_eq!(score, 1.0);
        }
    }

    #[test]
    fn test_when_ukrainian_specific_chars_given() {
        let text = LowercaseText::new("Дуже цікаво");
        let RawOutcome {
            count,
            raw_scores,
            scores,
        } = alphabet_calculate_scores(&text);

        assert_eq!(count, 10);

        assert_eq!(fetch(&Lang::Ukr, &raw_scores), 10);
        assert_eq!(fetch(&Lang::Rus, &raw_scores), 8);

        assert_eq!(fetch(&Lang::Ukr, &scores), 1.0);
        assert_eq!(fetch(&Lang::Rus, &scores), 0.8);
    }
}
<|endoftext|>


<commit_before><commit_msg>more iterations<commit_after><|endoftext|>


<commit_before>//! Graph generation AST traversal.

use std::{
    ffi::OsStr,
    fs,
    io::Error as IoError,
    path::PathBuf,
    string::ToString,
};

use rustc_ast::{
    ast::{
        Attribute,
        Crate,
        Item,
        ItemKind,
        MacCall,
        Mod,
        NodeId,
        UseTree,
        UseTreeKind,
        VisibilityKind,
    },
    visit::{
        self,
        Visitor,
    },
    //source_map::{edition::Edition, FilePathMapping, SourceMap, Span, Symbol},
};
use rustc_ast_pretty::pprust;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{
    edition::Edition,
    FilePathMapping,
    SourceMap,
    Span,
    Symbol,
};

use crate::{
    error::Error,
    manifest::Target,
    ng::graph::{
        Graph,
        GraphBuilder,
        Visibility,
        GLOB,
        SEP,
    },
};

const SOURCE_DIR: &str = "./src/";
const DIR_SEP: &str = "/";

struct Builder<'a> {
    graph_builder: GraphBuilder,
    ignored_files: &'a [PathBuf],
    path: Vec<String>,
    source_map: &'a SourceMap,
}

impl<'a> Builder<'a> {
    fn new(edition: Edition, ignored_files: &'a [PathBuf], source_map: &'a SourceMap) -> Self {
        Builder {
            graph_builder: GraphBuilder::new(edition),
            ignored_files,
            path: vec![],
            source_map,
        }
    }

    fn path_str(&self) -> String {
        self.path.join(SEP)
    }

    fn add_use_tree(&mut self, prefix: &str, use_tree: &UseTree, visibility: Visibility) {
        let path_string = pprust::path_to_string(&use_tree.prefix);
        let new_prefix = if path_string != "self" {
            [prefix, &path_string].join(SEP)
        } else {
            prefix.to_string()
        };

        match use_tree.kind {
            UseTreeKind::Simple(..) => self.graph_builder.add_use(&self.path_str(), new_prefix),
            UseTreeKind::Nested(ref children) => {
                for (child, _) in children {
                    self.add_use_tree(&new_prefix, child, visibility);
                }
            }
            UseTreeKind::Glob => {
                self.graph_builder
                    .add_use(&self.path_str(), format!("{}{}{}", new_prefix, SEP, GLOB));
            }
        }
    }
}

pub fn build_graph<'a>(
    edition: Edition,
    target: &Target,
    ignored_files: &'a [PathBuf],
) -> Result<Graph, Error> {
    rustc_ast::attr::with_session_globals(edition, || {
        let parse_session = ParseSess::new(FilePathMapping::empty());
        let crate_: Crate =
            match rustc_parse::parse_crate_from_file(&target.src_path(), &parse_session) {
                Ok(_) if parse_session.span_diagnostic.has_errors() => Err(None),
                Ok(krate) => Ok(krate),
                Err(e) => Err(Some(e)),
            }
            .map_err(|e| Error::Syntax(format!("{:?}", e)))?;
        let mut builder = Builder::new(edition, ignored_files, parse_session.source_map());
        builder.graph_builder.add_crate_root(target.name());
        builder.path.push(target.name().to_owned());

        // Starting point is Builder.visit_mod with the crate
        builder.visit_mod(
            &crate_.module,
            crate_.span,
            &crate_.attrs[..],
            NodeId::from(0 as u32),
        );

        Ok(builder.graph_builder.build())
    })
}

// This function walks a single directory non-recursively and it is called
// every time a module is visited.  It would have been great not to
// repetitively call this but figure out orphan candidates at once.
// Unfortunately that solution, although elegant, becomes quite complex. And
// we would still be relying on an assumption that maps modules to directories
// as the original version relies on.  A real elegant solution would be to get
// the filename somehow from syntax module, in the span or something.
fn find_orphan_candidates(
    path: &[String],
    ignored_files: &[PathBuf],
) -> Result<Vec<String>, IoError> {
    let mut dir_path = SOURCE_DIR.to_string();
    for name in path.iter() {
        dir_path.push_str(name);
        dir_path.push_str(DIR_SEP);
    }
    fn is_mod(entry: &fs::DirEntry) -> bool {
        let path = entry.path();
        if path.is_file() {
            if path.extension().map_or(false, |ext| ext == "rs") {
                return file_name(entry)
                    .map_or(false, |s| (s != "mod") && (s != "lib") && (s != "main"));
            }
        } else if path.join("mod.rs").exists() {
            return true;
        }
        false
    }
    fn file_name(entry: &fs::DirEntry) -> Option<String> {
        entry
            .path()
            .file_stem()
            .and_then(OsStr::to_str)
            .map(ToString::to_string)
    }
    Ok(fs::read_dir(&dir_path)?
        .filter_map(Result::ok)
        .filter(is_mod)
        .filter(|e| !ignored_files.contains(&e.path()))
        .filter_map(|e| file_name(&e))
        .collect::<Vec<_>>())
}

impl<'a> Visitor<'a> for Builder<'a> {
    fn visit_item(&mut self, item: &'a Item) {
        match item.kind {
            ItemKind::Mod(_) => {
                let path = self.path_str();
                let name = item.ident.to_string();
                let visibility = match item.vis.node {
                    VisibilityKind::Public => Visibility::Public,
                    _ => Visibility::Private,
                };
                let conditions: Option<String> = item
                    .attrs
                    .iter()
                    .find(|attr| attr.check_name(Symbol::intern("cfg")))
                    .map(|attr| {
                        self.source_map
                            .span_to_snippet(attr.span)
                            .map(|attr| attr)
                            .unwrap_or_else(|_| String::from(""))
                    });
                self.graph_builder
                    .add_mod(&path, &name, visibility, conditions.as_deref());
                self.path.push(name);
                visit::walk_item(self, item);
                self.path.pop();
            }
            ItemKind::Use(ref use_tree) => {
                let visibility = if let VisibilityKind::Public = item.vis.node {
                    Visibility::Public
                } else {
                    Visibility::Private
                };
                self.add_use_tree("", use_tree, visibility);
                visit::walk_item(self, item);
            }
            _ => visit::walk_item(self, item),
        }
    }

    fn visit_mac(&mut self, macro_: &'a MacCall) {
        visit::walk_mac(self, macro_);
    }

    fn visit_mod(&mut self, module: &'a Mod, _: Span, _: &[Attribute], _: NodeId) {
        // This is the default behavior:
        visit::walk_mod(self, module);

        // Add orphaned modules.
        if let Ok(candidates) = find_orphan_candidates(&self.path[1..], &self.ignored_files[..]) {
            for candidate in candidates {
                let path: String = [&self.path_str(), SEP, &candidate].concat();
                match self.graph_builder.find(&path) {
                    Some(_) => (), // Already visited, not an orphan.
                    None => {
                        self.graph_builder.add_orphan(&self.path_str(), &candidate);
                    }
                }
            }
        }
    }
}
<commit_msg>Fix clippy<commit_after>//! Graph generation AST traversal.

use std::{
    ffi::OsStr,
    fs,
    io::Error as IoError,
    path::PathBuf,
    string::ToString,
};

use rustc_ast::{
    ast::{
        Attribute,
        Crate,
        Item,
        ItemKind,
        MacCall,
        Mod,
        NodeId,
        UseTree,
        UseTreeKind,
        VisibilityKind,
    },
    visit::{
        self,
        Visitor,
    },
    //source_map::{edition::Edition, FilePathMapping, SourceMap, Span, Symbol},
};
use rustc_ast_pretty::pprust;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{
    edition::Edition,
    FilePathMapping,
    SourceMap,
    Span,
    Symbol,
};

use crate::{
    error::Error,
    manifest::Target,
    ng::graph::{
        Graph,
        GraphBuilder,
        Visibility,
        GLOB,
        SEP,
    },
};

const SOURCE_DIR: &str = "./src/";
const DIR_SEP: &str = "/";

struct Builder<'a> {
    graph_builder: GraphBuilder,
    ignored_files: &'a [PathBuf],
    path: Vec<String>,
    source_map: &'a SourceMap,
}

impl<'a> Builder<'a> {
    fn new(edition: Edition, ignored_files: &'a [PathBuf], source_map: &'a SourceMap) -> Self {
        Builder {
            graph_builder: GraphBuilder::new(edition),
            ignored_files,
            path: vec![],
            source_map,
        }
    }

    fn path_str(&self) -> String {
        self.path.join(SEP)
    }

    fn add_use_tree(&mut self, prefix: &str, use_tree: &UseTree, visibility: Visibility) {
        let path_string = pprust::path_to_string(&use_tree.prefix);
        let new_prefix = if path_string != "self" {
            [prefix, &path_string].join(SEP)
        } else {
            prefix.to_string()
        };

        match use_tree.kind {
            UseTreeKind::Simple(..) => self.graph_builder.add_use(&self.path_str(), new_prefix),
            UseTreeKind::Nested(ref children) => {
                for (child, _) in children {
                    self.add_use_tree(&new_prefix, child, visibility);
                }
            }
            UseTreeKind::Glob => {
                self.graph_builder
                    .add_use(&self.path_str(), format!("{}{}{}", new_prefix, SEP, GLOB));
            }
        }
    }
}

pub fn build_graph<'a>(
    edition: Edition,
    target: &Target,
    ignored_files: &'a [PathBuf],
) -> Result<Graph, Error> {
    rustc_ast::attr::with_session_globals(edition, || {
        let parse_session = ParseSess::new(FilePathMapping::empty());
        let crate_: Crate =
            match rustc_parse::parse_crate_from_file(&target.src_path(), &parse_session) {
                Ok(_) if parse_session.span_diagnostic.has_errors() => Err(None),
                Ok(krate) => Ok(krate),
                Err(e) => Err(Some(e)),
            }
            .map_err(|e| Error::Syntax(format!("{:?}", e)))?;
        let mut builder = Builder::new(edition, ignored_files, parse_session.source_map());
        builder.graph_builder.add_crate_root(target.name());
        builder.path.push(target.name().to_owned());

        // Starting point is Builder.visit_mod with the crate
        builder.visit_mod(
            &crate_.module,
            crate_.span,
            &crate_.attrs[..],
            NodeId::from(0 as u32),
        );

        Ok(builder.graph_builder.build())
    })
}

// This function walks a single directory non-recursively and it is called
// every time a module is visited.  It would have been great not to
// repetitively call this but figure out orphan candidates at once.
// Unfortunately that solution, although elegant, becomes quite complex. And
// we would still be relying on an assumption that maps modules to directories
// as the original version relies on.  A real elegant solution would be to get
// the filename somehow from syntax module, in the span or something.
fn find_orphan_candidates(
    path: &[String],
    ignored_files: &[PathBuf],
) -> Result<Vec<String>, IoError> {
    let mut dir_path = SOURCE_DIR.to_string();
    for name in path.iter() {
        dir_path.push_str(name);
        dir_path.push_str(DIR_SEP);
    }
    fn is_mod(entry: &fs::DirEntry) -> bool {
        let path = entry.path();
        if path.is_file() {
            if path.extension().map_or(false, |ext| ext == "rs") {
                return file_name(entry)
                    .map_or(false, |s| (s != "mod") && (s != "lib") && (s != "main"));
            }
        } else if path.join("mod.rs").exists() {
            return true;
        }
        false
    }
    fn file_name(entry: &fs::DirEntry) -> Option<String> {
        entry
            .path()
            .file_stem()
            .and_then(OsStr::to_str)
            .map(ToString::to_string)
    }
    Ok(fs::read_dir(&dir_path)?
        .filter_map(Result::ok)
        .filter(is_mod)
        .filter(|e| !ignored_files.contains(&e.path()))
        .filter_map(|e| file_name(&e))
        .collect::<Vec<_>>())
}

impl<'a> Visitor<'a> for Builder<'a> {
    fn visit_item(&mut self, item: &'a Item) {
        match item.kind {
            ItemKind::Mod(_) => {
                let path = self.path_str();
                let name = item.ident.to_string();
                let visibility = match item.vis.node {
                    VisibilityKind::Public => Visibility::Public,
                    _ => Visibility::Private,
                };
                let conditions: Option<String> = item
                    .attrs
                    .iter()
                    .find(|attr| attr.check_name(Symbol::intern("cfg")))
                    .map(|attr| {
                        self.source_map
                            .span_to_snippet(attr.span)
                            .unwrap_or_else(|_| String::from(""))
                    });
                self.graph_builder
                    .add_mod(&path, &name, visibility, conditions.as_deref());
                self.path.push(name);
                visit::walk_item(self, item);
                self.path.pop();
            }
            ItemKind::Use(ref use_tree) => {
                let visibility = if let VisibilityKind::Public = item.vis.node {
                    Visibility::Public
                } else {
                    Visibility::Private
                };
                self.add_use_tree("", use_tree, visibility);
                visit::walk_item(self, item);
            }
            _ => visit::walk_item(self, item),
        }
    }

    fn visit_mac(&mut self, macro_: &'a MacCall) {
        visit::walk_mac(self, macro_);
    }

    fn visit_mod(&mut self, module: &'a Mod, _: Span, _: &[Attribute], _: NodeId) {
        // This is the default behavior:
        visit::walk_mod(self, module);

        // Add orphaned modules.
        if let Ok(candidates) = find_orphan_candidates(&self.path[1..], &self.ignored_files[..]) {
            for candidate in candidates {
                let path: String = [&self.path_str(), SEP, &candidate].concat();
                match self.graph_builder.find(&path) {
                    Some(_) => (), // Already visited, not an orphan.
                    None => {
                        self.graph_builder.add_orphan(&self.path_str(), &candidate);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! rustbuild, the Rust build system
//!
//! This is the entry point for the build system used to compile the `rustc`
//! compiler. Lots of documentation can be found in the `README.md` file in the
//! parent directory, and otherwise documentation can be found throughout the `build`
//! directory in each respective module.

use std::env;

use bootstrap::{Build, Config};

fn main() {
    let args = env::args().skip(1).collect::<Vec<_>>();
    let config = Config::parse(&args);

    let changelog_suggestion = check_version(&config);
    if let Some(suggestion) = &changelog_suggestion {
        println!("{}", suggestion);
    }

    Build::new(config).build();

    if let Some(suggestion) = changelog_suggestion {
        println!("{}", suggestion);
        println!("note: this message was printed twice to make it more likely to be seen");
    }
}

fn check_version(config: &Config) -> Option<String> {
    const VERSION: usize = 1;

    let mut msg = String::new();

    let suggestion = if let Some(seen) = config.changelog_seen {
        if seen != VERSION {
            msg.push_str("warning: there have been changes to x.py since you last updated.\n");
            format!("update `config.toml` to use `changelog-seen = {}` instead", VERSION)
        } else {
            return None;
        }
    } else {
        msg.push_str("warning: x.py has made several changes recently you may want to look at\n");
        format!("add `changelog-seen = {}` to `config.toml`", VERSION)
    };

    msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n");
    msg.push_str("note: to silence this warning, ");
    msg.push_str(&suggestion);

    Some(msg)
}
<commit_msg>Rollup merge of #77106 - matthiaskrgr:changelog_seen, r=Mark-Simulacrum<commit_after>//! rustbuild, the Rust build system
//!
//! This is the entry point for the build system used to compile the `rustc`
//! compiler. Lots of documentation can be found in the `README.md` file in the
//! parent directory, and otherwise documentation can be found throughout the `build`
//! directory in each respective module.

use std::env;

use bootstrap::{Build, Config};

fn main() {
    let args = env::args().skip(1).collect::<Vec<_>>();
    let config = Config::parse(&args);

    let changelog_suggestion = check_version(&config);
    if let Some(suggestion) = &changelog_suggestion {
        println!("{}", suggestion);
    }

    Build::new(config).build();

    if let Some(suggestion) = changelog_suggestion {
        println!("{}", suggestion);
        println!("note: this message was printed twice to make it more likely to be seen");
    }
}

fn check_version(config: &Config) -> Option<String> {
    const VERSION: usize = 1;

    let mut msg = String::new();

    let suggestion = if let Some(seen) = config.changelog_seen {
        if seen != VERSION {
            msg.push_str("warning: there have been changes to x.py since you last updated.\n");
            format!("update `config.toml` to use `changelog-seen = {}` instead", VERSION)
        } else {
            return None;
        }
    } else {
        msg.push_str("warning: x.py has made several changes recently you may want to look at\n");
        format!("add `changelog-seen = {}` at the top of `config.toml`", VERSION)
    };

    msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n");
    msg.push_str("note: to silence this warning, ");
    msg.push_str(&suggestion);

    Some(msg)
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;

fn main() {
    if std::env::var("DOCS_RS").is_ok() {
        // Skip everything when building docs on docs.rs
        return;
    }

    let current_dir = std::env::current_dir()
        .unwrap()
        .into_os_string()
        .into_string()
        .unwrap();
    let out_dir = env::var("OUT_DIR").unwrap();

    // Add C++ std lib
    #[cfg(target_os = "linux")]
    {
        let path = Command::new(env::var("CXX").unwrap_or_else(|_| "c++".to_string()))
            .arg("--print-file-name=libstdc++.a")
            .output()
            .expect("Failed to start")
            .stdout;
        println!(
            "cargo:rustc-link-search=native={}",
            String::from_utf8_lossy(&path)
                .trim()
                .strip_suffix("libstdc++.a")
                .expect("Failed to strip suffix"),
        );
        println!("cargo:rustc-link-lib=static=stdc++");
    }
    #[cfg(any(
        target_os = "freebsd",
        target_os = "dragonfly",
        target_os = "openbsd",
        target_os = "netbsd"
    ))]
    {
        let path = Command::new(env::var("CXX").unwrap_or_else(|_| "c++".to_string()))
            .arg("--print-file-name=libc++.a")
            .output()
            .expect("Failed to start")
            .stdout;
        println!(
            "cargo:rustc-link-search=native={}",
            String::from_utf8_lossy(&path)
                .trim()
                .strip_suffix("libc++.a")
                .expect("Failed to strip suffix"),
        );
        println!("cargo:rustc-link-lib=static=c++");
    }
    #[cfg(target_os = "macos")]
    {
        let path = Command::new("xcrun")
            .args(&["--show-sdk-path"])
            .output()
            .expect("Failed to start")
            .stdout;

        let libpath = format!(
            "{}/usr/lib",
            String::from_utf8(path)
                .expect("Failed to decode path")
                .trim()
        );
        println!("cargo:rustc-link-search={}", libpath);
        println!("cargo:rustc-cdylib-link-arg=-stdlib=libc++");
        println!("cargo:rustc-link-lib=dylib=c++");
        println!("cargo:rustc-link-lib=dylib=c++abi");
    }
    #[cfg(target_os = "windows")]
    {
        panic!("Building on Windows is not currently supported");
        // TODO: Didn't bother, feel free to PR
    }

    // The build here is a bit awkward since we can't just specify custom target directory as
    // openssl will fail to build with `make[1]: /bin/sh: Argument list too long` due to large
    // number of files. So instead we build in place, copy files to out directory and then clean
    // after ourselves
    {
        // Build
        if !Command::new("make")
            .arg("libmediasoup-worker")
            .env("PYTHONDONTWRITEBYTECODE", "1")
            .spawn()
            .expect("Failed to start")
            .wait()
            .expect("Wasn't running")
            .success()
        {
            panic!("Failed to build libmediasoup-worker")
        }

        for file in &[
            "libnetstring.a",
            "libuv.a",
            "libopenssl.a",
            "libsrtp.a",
            "libusrsctp.a",
            "libwebrtc.a",
            "libmediasoup-worker.a",
            "libabseil.a",
            #[cfg(windows)]
            "libgetopt.a",
        ] {
            std::fs::copy(
                format!("{}/out/Release/{}", current_dir, file),
                format!("{}/{}", out_dir, file),
            )
            .unwrap_or_else(|_| {
                panic!(
                    "Failed to copy static library from {}/out/Release/{} to {}/{}",
                    current_dir, file, out_dir, file
                )
            });
        }

        if env::var("KEEP_BUILD_ARTIFACTS") != Ok("1".to_string()) {
            // Clean
            if !Command::new("make")
                .arg("clean-all")
                .spawn()
                .expect("Failed to start")
                .wait()
                .expect("Wasn't running")
                .success()
            {
                panic!("Failed to clean libmediasoup-worker")
            }
        }
    }

    println!("cargo:rustc-link-lib=static=netstring");
    println!("cargo:rustc-link-lib=static=uv");
    println!("cargo:rustc-link-lib=static=openssl");
    println!("cargo:rustc-link-lib=static=srtp");
    println!("cargo:rustc-link-lib=static=usrsctp");
    println!("cargo:rustc-link-lib=static=webrtc");
    println!("cargo:rustc-link-lib=static=mediasoup-worker");
    println!("cargo:rustc-link-lib=static=abseil");
    #[cfg(windows)]
    println!("cargo:rustc-link-lib=static=getopt");
    println!("cargo:rustc-link-search=native={}", out_dir);
}
<commit_msg>remove unnecessary flag<commit_after>use std::env;
use std::process::Command;

fn main() {
    if std::env::var("DOCS_RS").is_ok() {
        // Skip everything when building docs on docs.rs
        return;
    }

    let current_dir = std::env::current_dir()
        .unwrap()
        .into_os_string()
        .into_string()
        .unwrap();
    let out_dir = env::var("OUT_DIR").unwrap();

    // Add C++ std lib
    #[cfg(target_os = "linux")]
    {
        let path = Command::new(env::var("CXX").unwrap_or_else(|_| "c++".to_string()))
            .arg("--print-file-name=libstdc++.a")
            .output()
            .expect("Failed to start")
            .stdout;
        println!(
            "cargo:rustc-link-search=native={}",
            String::from_utf8_lossy(&path)
                .trim()
                .strip_suffix("libstdc++.a")
                .expect("Failed to strip suffix"),
        );
        println!("cargo:rustc-link-lib=static=stdc++");
    }
    #[cfg(any(
        target_os = "freebsd",
        target_os = "dragonfly",
        target_os = "openbsd",
        target_os = "netbsd"
    ))]
    {
        let path = Command::new(env::var("CXX").unwrap_or_else(|_| "c++".to_string()))
            .arg("--print-file-name=libc++.a")
            .output()
            .expect("Failed to start")
            .stdout;
        println!(
            "cargo:rustc-link-search=native={}",
            String::from_utf8_lossy(&path)
                .trim()
                .strip_suffix("libc++.a")
                .expect("Failed to strip suffix"),
        );
        println!("cargo:rustc-link-lib=static=c++");
    }
    #[cfg(target_os = "macos")]
    {
        let path = Command::new("xcrun")
            .args(&["--show-sdk-path"])
            .output()
            .expect("Failed to start")
            .stdout;

        let libpath = format!(
            "{}/usr/lib",
            String::from_utf8(path)
                .expect("Failed to decode path")
                .trim()
        );
        println!("cargo:rustc-link-search={}", libpath);
        println!("cargo:rustc-link-lib=dylib=c++");
        println!("cargo:rustc-link-lib=dylib=c++abi");
    }
    #[cfg(target_os = "windows")]
    {
        panic!("Building on Windows is not currently supported");
        // TODO: Didn't bother, feel free to PR
    }

    // The build here is a bit awkward since we can't just specify custom target directory as
    // openssl will fail to build with `make[1]: /bin/sh: Argument list too long` due to large
    // number of files. So instead we build in place, copy files to out directory and then clean
    // after ourselves
    {
        // Build
        if !Command::new("make")
            .arg("libmediasoup-worker")
            .env("PYTHONDONTWRITEBYTECODE", "1")
            .spawn()
            .expect("Failed to start")
            .wait()
            .expect("Wasn't running")
            .success()
        {
            panic!("Failed to build libmediasoup-worker")
        }

        for file in &[
            "libnetstring.a",
            "libuv.a",
            "libopenssl.a",
            "libsrtp.a",
            "libusrsctp.a",
            "libwebrtc.a",
            "libmediasoup-worker.a",
            "libabseil.a",
            #[cfg(windows)]
            "libgetopt.a",
        ] {
            std::fs::copy(
                format!("{}/out/Release/{}", current_dir, file),
                format!("{}/{}", out_dir, file),
            )
            .unwrap_or_else(|_| {
                panic!(
                    "Failed to copy static library from {}/out/Release/{} to {}/{}",
                    current_dir, file, out_dir, file
                )
            });
        }

        if env::var("KEEP_BUILD_ARTIFACTS") != Ok("1".to_string()) {
            // Clean
            if !Command::new("make")
                .arg("clean-all")
                .spawn()
                .expect("Failed to start")
                .wait()
                .expect("Wasn't running")
                .success()
            {
                panic!("Failed to clean libmediasoup-worker")
            }
        }
    }

    println!("cargo:rustc-link-lib=static=netstring");
    println!("cargo:rustc-link-lib=static=uv");
    println!("cargo:rustc-link-lib=static=openssl");
    println!("cargo:rustc-link-lib=static=srtp");
    println!("cargo:rustc-link-lib=static=usrsctp");
    println!("cargo:rustc-link-lib=static=webrtc");
    println!("cargo:rustc-link-lib=static=mediasoup-worker");
    println!("cargo:rustc-link-lib=static=abseil");
    #[cfg(windows)]
    println!("cargo:rustc-link-lib=static=getopt");
    println!("cargo:rustc-link-search=native={}", out_dir);
}
<|endoftext|>


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

#[macro_use]
extern crate nom;

use nom::{IResult, space, alphanumeric, multispace};

use std::str;
use std::collections::HashMap;

named!(category<&str>, map_res!(
    terminated!(
        delimited!(
          char!('['),
          take_while!(call!(|c| c != ']' as u8)),
          char!(']')),
        opt!(multispace)
    ),
    str::from_utf8
));

named!(key_value    <&[u8],(&str,&str)>,
  do_parse!(
     key: map_res!(alphanumeric, str::from_utf8)
  >>      opt!(space)
  >>      char!('=')
  >>      opt!(space)
  >> val: map_res!(
           take_while!(call!(|c| c != '\n' as u8 && c != ';' as u8)),
           str::from_utf8
         )
  >>      opt!(pair!(char!(';'), take_while!(call!(|c| c != '\n' as u8))))
  >>      opt!(multispace)
  >>      (key, val)
  )
);

named!(keys_and_values<&[u8], HashMap<&str, &str> >,
  map!(
    many0!(key_value),
    |vec: Vec<_>| vec.into_iter().collect()
  )
);

named!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,
  do_parse!(
    category: category    >>
    keys: keys_and_values >>
    (category, keys)
  )
);

named!(categories<&[u8], HashMap<&str, HashMap<&str,&str> > >,
  map!(
    many0!(
      pair!(
        category,
        //keys_and_values
        map!(
          many0!(key_value),
          |vec: Vec<_>| vec.into_iter().collect()
        )
      )
    ),
    |vec: Vec<_>| vec.into_iter().collect()
  )
);

#[test]
fn parse_category_test() {
  let ini_file = &b"[category]

parameter=value
key = value2"[..];

  let ini_without_category = &b"parameter=value
key = value2"[..];

  let res = category(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_category, "category"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = &b"parameter=value
key = value2"[..];

  let ini_without_key_value = &b"key = value2"[..];

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = &b"parameter = value
key = value2"[..];

  let ini_without_key_value = &b"key = value2"[..];

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = &b"parameter=value;abc
key = value2"[..];

  let ini_without_key_value = &b"key = value2"[..];

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = &b"parameter=value;abc

key = value2

[category]"[..];

  let ini_without_key_value = &b"[category]"[..];

  let res = keys_and_values(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, IResult::Done(ini_without_key_value, expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = &b"[abcd]
parameter=value;abc

key = value2

[category]"[..];

  let ini_after_parser = &b"[category]"[..];

  let res = category_and_keys(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, IResult::Done(ini_after_parser, ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = &b"[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
"[..];

  let ini_after_parser = &b""[..];

  let res = categories(ini_file);
  //println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, IResult::Done(ini_after_parser, expected_h));
}

#[bench]
fn bench_ini(b: &mut test::Bencher) {
  let str = "[owner]
name=John Doe
organization=Acme Widgets Inc.

[database]
server=192.0.2.62
port=143
file=payroll.dat
";

  b.iter(|| categories(str.as_bytes()).unwrap());
  b.bytes = str.len() as u64;
}

#[bench]
fn bench_ini_keys_and_values(b: &mut test::Bencher) {
  let str = "server=192.0.2.62
port=143
file=payroll.dat
";

  named!(acc< Vec<(&str,&str)> >, many0!(key_value));

  b.iter(|| acc(str.as_bytes()).unwrap());
  b.bytes = str.len() as u64;
}

#[bench]
fn bench_ini_key_value(b: &mut test::Bencher) {
  let str = "server=192.0.2.62\n";

  b.iter(|| key_value(str.as_bytes()).unwrap());
  b.bytes = str.len() as u64;
}
<commit_msg>move multispace parsers out of basic ones<commit_after>#![feature(test)]
extern crate test;

#[macro_use]
extern crate nom;

use nom::{IResult, space, alphanumeric, multispace};

use std::str;
use std::collections::HashMap;

named!(category<&str>, map_res!(
    delimited!(
      char!('['),
      take_while!(call!(|c| c != ']' as u8)),
      char!(']')
    ),
    str::from_utf8
));

named!(key_value    <&[u8],(&str,&str)>,
  do_parse!(
     key: map_res!(alphanumeric, str::from_utf8)
  >>      opt!(space)
  >>      char!('=')
  >>      opt!(space)
  >> val: map_res!(
           take_while!(call!(|c| c != '\n' as u8 && c != ';' as u8)),
           str::from_utf8
         )
  >>      opt!(pair!(char!(';'), take_while!(call!(|c| c != '\n' as u8))))
  >>      (key, val)
  )
);

named!(keys_and_values<&[u8], HashMap<&str, &str> >,
  map!(
    many0!(terminated!(key_value, opt!(multispace))),
    |vec: Vec<_>| vec.into_iter().collect()
  )
);

named!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,
  do_parse!(
    category: category         >>
              opt!(multispace) >>
    keys: keys_and_values      >>
    (category, keys)
  )
);

named!(categories<&[u8], HashMap<&str, HashMap<&str,&str> > >,
  map!(
    many0!(
      separated_pair!(
        category,
        opt!(multispace),
        map!(
          many0!(terminated!(key_value, opt!(multispace))),
          |vec: Vec<_>| vec.into_iter().collect()
        )
      )
    ),
    |vec: Vec<_>| vec.into_iter().collect()
  )
);

#[test]
fn parse_category_test() {
  let ini_file = &b"[category]

parameter=value
key = value2"[..];

  let ini_without_category = &b"parameter=value
key = value2"[..];

  let res = category(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_category, "category"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = &b"parameter=value
key = value2"[..];

  let ini_without_key_value = &b"key = value2"[..];

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = &b"parameter = value
key = value2"[..];

  let ini_without_key_value = &b"key = value2"[..];

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = &b"parameter=value;abc
key = value2"[..];

  let ini_without_key_value = &b"key = value2"[..];

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = &b"parameter=value;abc

key = value2

[category]"[..];

  let ini_without_key_value = &b"[category]"[..];

  let res = keys_and_values(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, IResult::Done(ini_without_key_value, expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = &b"[abcd]
parameter=value;abc

key = value2

[category]"[..];

  let ini_after_parser = &b"[category]"[..];

  let res = category_and_keys(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, IResult::Done(ini_after_parser, ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = &b"[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
"[..];

  let ini_after_parser = &b""[..];

  let res = categories(ini_file);
  //println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, IResult::Done(ini_after_parser, expected_h));
}

#[bench]
fn bench_ini(b: &mut test::Bencher) {
  let str = "[owner]
name=John Doe
organization=Acme Widgets Inc.

[database]
server=192.0.2.62
port=143
file=payroll.dat
";

  b.iter(|| categories(str.as_bytes()).unwrap());
  b.bytes = str.len() as u64;
}

#[bench]
fn bench_ini_keys_and_values(b: &mut test::Bencher) {
  let str = "server=192.0.2.62
port=143
file=payroll.dat
";

  named!(acc< Vec<(&str,&str)> >, many0!(key_value));

  b.iter(|| acc(str.as_bytes()).unwrap());
  b.bytes = str.len() as u64;
}

#[bench]
fn bench_ini_key_value(b: &mut test::Bencher) {
  let str = "server=192.0.2.62\n";

  b.iter(|| key_value(str.as_bytes()).unwrap());
  b.bytes = str.len() as u64;
}
<|endoftext|>


<commit_before>use std::error::Error;

//Following semver here
#[derive(Clone, PartialOrd, RustcDecodable, RustcEncodable)]
pub struct Version {
    pub major: u16,
    pub minor: u16,
    pub patch: u32
}

#[derive(Clone, RustcDecodable, RustcEncodable)]
pub struct Package {
    pub name: String,
    pub version: Version,
    pub crc32: u32,
    pub child_url: String, // Examples: /some_dir/something.exe
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    pub packages: Vec<Package>,
    pub parent_url: String, // Examples: https://www.foo.bar
    pub version: u32
}

impl Version {
    pub fn new() -> Version {
        Version {
            major: 0u16,
            minor: 0u16,
            patch: 0u32
        }
    }

    pub fn from(major: u16, minor: u16, patch: u32) -> Version {
        Version {
            major: major,
            minor: minor,
            patch: patch
        }
    }

    pub fn from_str(input: &str) -> Result<Version, String> {
        let versions: Vec<&str> = input.split('.').collect();
        if versions.len() == 3 {
            return Ok(
                Version {
                    major: get!(versions[0].parse::<u16>(),"Version: Unable to parse &str into u16 (major)"),
                    minor: get!(versions[1].parse::<u16>(),"Version: Unable to parse &str into u16 (minor)"),
                    patch: get!(versions[2].parse::<u32>(),"Version: Unable to parse &str into u32 (patch)")
                }
            )
        } else {
            return Err("Version::from_str() cannot parse provided input into Version".to_string())
        }
    }
}

impl PartialEq for Version {
    fn eq(&self, other: &Version) -> bool {
        self.major == other.major &&
        self.minor == other.minor &&
        self.patch == other.patch
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self.name == other.name &&
        self.version == other.version &&
        self.crc32 == other.crc32 &&
        self.dependencies == other.dependencies
    }
}<commit_msg>implement ToString for Version<commit_after>use std::error::Error;

//Following semver here
#[derive(Clone, Debug, PartialOrd, RustcDecodable, RustcEncodable)]
pub struct Version {
    pub major: u16,
    pub minor: u16,
    pub patch: u32
}

#[derive(Clone, RustcDecodable, RustcEncodable)]
pub struct Package {
    pub name: String,
    pub version: Version,
    pub crc32: u32,
    pub child_url: String, // Examples: /some_dir/something.exe
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    pub packages: Vec<Package>,
    pub parent_url: String, // Examples: https://www.foo.bar
    pub version: u32
}

impl Version {
    pub fn new() -> Version {
        Version {
            major: 0u16,
            minor: 0u16,
            patch: 0u32
        }
    }

    pub fn from(major: u16, minor: u16, patch: u32) -> Version {
        Version {
            major: major,
            minor: minor,
            patch: patch
        }
    }

    pub fn from_str(input: &str) -> Result<Version, String> {
        let versions: Vec<&str> = input.split('.').collect();
        if versions.len() == 3 {
            return Ok(
                Version {
                    major: get!(versions[0].parse::<u16>(),"Version: Unable to parse &str into u16 (major)"),
                    minor: get!(versions[1].parse::<u16>(),"Version: Unable to parse &str into u16 (minor)"),
                    patch: get!(versions[2].parse::<u32>(),"Version: Unable to parse &str into u32 (patch)")
                }
            )
        } else {
            return Err("Version::from_str() cannot parse provided input into Version".to_string())
        }
    }
}

impl PartialEq for Version {
    fn eq(&self, other: &Version) -> bool {
        self.major == other.major &&
        self.minor == other.minor &&
        self.patch == other.patch
    }
}

impl ToString for Version {
    fn to_string(&self) -> String {
        String::from(self.major.to_string() + "." + &self.minor.to_string() + "." + &self.minor.to_string())
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self.name == other.name &&
        self.version == other.version &&
        self.crc32 == other.crc32 &&
        self.dependencies == other.dependencies
    }
}<|endoftext|>