<commit_before>use std::io::Read;
use std::path::Path;

use anyhow::{bail, format_err, Result};
use clap::{Arg, ArgMatches, Command};
use console::style;
use sentry::protocol::{Frame, Stacktrace};
use url::Url;

use crate::api::{Api, Artifact, ProcessedEvent};
use crate::config::Config;
use crate::utils::fs::TempFile;
use crate::utils::system::QuietExit;

use super::resolve::print_source;

pub fn make_command(command: Command) -> Command {
    command
        .about("Explain why sourcemaps are not working for a given event.")
        .alias("why")
        .arg(
            Arg::new("event")
                .value_name("EVENT_ID")
                .required(true)
                .help("ID of an event to be explained."),
        )
        .arg(
            Arg::new("force")
                .long("force")
                .short('f')
                .help("Force full validation flow, even when event is already source mapped."),
        )
}

fn tip<S>(msg: S)
where
    S: std::fmt::Display,
{
    println!("{}", style(format!("ℹ {}", msg)).blue());
}

fn success<S>(msg: S)
where
    S: std::fmt::Display,
{
    println!("{}", style(format!("✔ {}", msg)).green());
}

fn warning<S>(msg: S)
where
    S: std::fmt::Display,
{
    println!("{}", style(format!("⚠ {}", msg)).yellow());
}

fn error<S>(msg: S)
where
    S: std::fmt::Display,
{
    println!("{}", style(format!("✖ {}", msg)).red());
}

fn fetch_event(org: &str, project: &str, event_id: &str) -> Result<ProcessedEvent> {
    match Api::current().get_event(org, Some(project), event_id)? {
        Some(event) => {
            success(format!("Fetched data for event: {}", event_id));
            Ok(event)
        }
        None => {
            error(format!("Could not retrieve event {}", event_id));
            tip("Make sure that event ID you used is valid.");
            Err(QuietExit(1).into())
        }
    }
}

fn extract_top_frame(stacktrace: &Stacktrace) -> Result<&Frame> {
    let in_app_frames: Vec<&Frame> = stacktrace
        .frames
        .iter()
        .filter(|frame| frame.in_app.unwrap_or(false))
        .collect();

    if in_app_frames.is_empty() {
        bail!("Event exception stacktrace has no in_app frames");
    }

    let top_frame = in_app_frames.last().unwrap();
    let abs_path = top_frame
        .abs_path
        .as_ref()
        .ok_or_else(|| format_err!("Top frame is missing an abs_path"))?;

    if let Ok(abs_path) = Url::parse(abs_path) {
        if Path::new(abs_path.path()).extension().is_none() {
            bail!("Top frame of event exception originates from the <script> tag, its not possible to resolve source maps");
        }
    } else {
        bail!("Event exception stacktrace top frame has incorrect abs_path (valid url is required). Found {}", abs_path);
    }

    Ok(top_frame)
}

fn fetch_release_artifacts(org: &str, project: &str, release: &str) -> Result<Vec<Artifact>> {
    Api::current().list_release_files(org, Some(project), release).map(|artifacts| {
        if artifacts.is_empty() {
            error("Release has no artifacts uploaded");
            tip("https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js/#verify-artifacts-are-uploaded");
            return Err(QuietExit(1).into());
        }
        Ok(artifacts)
    })?
}

/*
 * Try to find an artifact which matches the path part of the url extracted from the stacktrace frame,
 * prefixed with the default `~/`, which is a "glob-like" pattern for matchin any hostname.
 *
 * We only need the `pathname` portion of the url, so if it's absolute, just extract it.
 * If it's relative however, parse any random url (example.com) and join it with our relative url,
 * as Rust cannot handle parsing of relative urls.
 *
 * http://localhost:5000/dist/bundle.min.js => ~/dist/bundle.min.js
 * /dist/bundle.js.map => ~/dist/bundle.js.map
 * okboomer => error (invalid relative path, no extension)
 *
 * It should be more generic than using the defaults, but should be sufficient for our current usecase.
 */
fn find_matching_artifact(artifacts: &[Artifact], abs_path: &str) -> Result<Artifact> {
    let abs_path = match Url::parse(abs_path) {
        Ok(path) => Ok(path),
        Err(_) => {
            let base = Url::parse("http://example.com").unwrap();
            base.join(abs_path)
                .map_err(|_| format_err!("Cannot parse source map url {}", abs_path))
        }
    }?;
    let mut filename = String::from("~");
    filename.push_str(abs_path.path());

    let full_match = artifacts.iter().find(|a| a.name == filename);
    let partial_match = artifacts
        .iter()
        .find(|a| a.name.ends_with(filename.split('/').last().unwrap()));

    if full_match.is_none() {
        error(format!(
            "Uploaded artifacts do not include entry: {}",
            filename
        ));

        if let Some(pm) = partial_match {
            tip(format!(
                "Found entry with partially matching filename: {}. \
                Make sure that that --url-prefix is set correctly.",
                pm.name,
            ));
        }

        return Err(QuietExit(1).into());
    }

    success(format!("Artifact {} found.", filename));
    Ok(full_match.cloned().unwrap())
}

fn verify_dists_matches(artifact: &Artifact, dist: Option<&str>) -> Result<()> {
    if artifact.dist.as_deref() != dist {
        error(format!(
            "Release artifact distrubition mismatch. Event: {}, Artifact: {}",
            dist.unwrap_or("[none]"),
            artifact.dist.as_ref().unwrap_or(&String::from("[none]"))
        ));
        tip("Configure 'dist' option in the SDK to match the one used during artifacts upload.\n  \
            https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js/#verify-artifact-distribution-value-matches-value-configured-in-your-sdk");

        return Err(QuietExit(1).into());
    }

    success(format!(
        "Release artifact distrubition matched. Event: {}, Artifact: {}",
        dist.unwrap_or("[none]"),
        artifact.dist.as_ref().unwrap_or(&String::from("[none]"))
    ));
    Ok(())
}

fn fetch_release_artifact_file(
    org: &str,
    project: &str,
    release: &str,
    artifact: &Artifact,
) -> Result<TempFile> {
    let api = Api::current();
    let file = TempFile::create()?;

    api.get_release_file(
        org,
        Some(project),
        release,
        &artifact.id,
        &mut file.open().unwrap(),
    )
    .map(|_| {
        success(format!(
            "Successfully fetched {} file from the server.",
            artifact.name
        ));
        Ok(file)
    })
    .map_err(|err| {
        format_err!(
            "Could not retrieve file {} from release {}: {:?}",
            artifact.name,
            release,
            err
        )
    })?
}

fn fetch_release_artifact_file_metadata(
    org: &str,
    project: &str,
    release: &str,
    artifact: &Artifact,
) -> Result<Artifact> {
    let api = Api::current();
    let file_metadata = api.get_release_file_metadata(org, Some(project), release, &artifact.id)?;
    file_metadata
        .ok_or_else(|| format_err!("Could not retrieve file metadata: {}", &artifact.id))
        .map(|f| {
            success(format!(
                "Successfully fetched {} file metadata from the server.",
                artifact.name
            ));
            f
        })
}

// https://github.com/getsentry/sentry/blob/623c2f5f3313e6dc55e08e2ae2b11d8f90cdbece/src/sentry/lang/javascript/processor.py#L145-L207
fn discover_sourcemaps_location(
    org: &str,
    project: &str,
    release: &str,
    artifact: &Artifact,
) -> Result<String> {
    let file_metadata = fetch_release_artifact_file_metadata(org, project, release, artifact)?;

    if let Some(header) = file_metadata.headers.get("Sourcemap") {
        return Ok(header.to_owned());
    }

    if let Some(header) = file_metadata.headers.get("X-SourceMap") {
        return Ok(header.to_owned());
    }

    let file = fetch_release_artifact_file(org, project, release, artifact)?;

    let mut f = file.open()?;
    let mut buffer = String::new();
    f.read_to_string(&mut buffer)?;

    for line in buffer.lines().rev() {
        if line.starts_with("//# sourceMappingURL=") || line.starts_with("//@ sourceMappingURL=") {
            let possible_sourcemap = line[21..].trim();
            if possible_sourcemap.starts_with("data:application/json") {
                bail!("Found inlined source maps, this tool doesnt support further verification for this scenario yet");
            }
            return Ok(possible_sourcemap.to_owned());
        }
    }

    Err(format_err!("Failed to discover source map url"))
}

fn print_sourcemap(file: &TempFile, line: u32, column: u32) -> Result<()> {
    let mut f = file.open()?;
    let mut buf = vec![];
    f.read_to_end(&mut buf)?;
    let sm = sourcemap::decode_slice(&buf)?;

    if let Some(token) = sm.lookup_token(line, column) {
        if let Some(view) = token.get_source_view() {
            success("Sourcemap position resolves to:");
            print_source(&token, view);
        } else if token.get_source_view().is_none() {
            bail!("cannot find source");
        } else {
            bail!("cannot find source for line {} column {}", line, column);
        }
    } else {
        bail!("invalid sourcemap location");
    }

    Ok(())
}

fn print_mapped_frame(frame: &Frame) {
    println!(
        "{}",
        style(
            frame
                .pre_context
                .iter()
                .map(|l| format!("  {}", l))
                .collect::<Vec<String>>()
                .join("\n")
        )
        .yellow()
    );
    println!(
        "{}",
        style(format!("> {}", frame.context_line.as_ref().unwrap())).yellow()
    );
    println!(
        "{}",
        style(
            frame
                .post_context
                .iter()
                .map(|l| format!("  {}", l))
                .collect::<Vec<String>>()
                .join("\n")
        )
        .yellow()
    );
}

fn extract_release(event: &ProcessedEvent) -> Result<String> {
    if let Some(release) = event.release.as_ref() {
        success(format!("Event has release name: {}", release));
        Ok(release.to_string())
    } else {
        error("Event is missing a release name");
        tip("Configure 'release' option in the SDK.\n  \
            https://docs.sentry.io/platforms/javascript/configuration/options/#release\n  \
            https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js/#verify-a-release-is-configured-in-your-sdk");
        Err(QuietExit(1).into())
    }
}

pub fn execute(matches: &ArgMatches) -> Result<()> {
    let config = Config::current();
    let (org, project) = config.get_org_and_project(matches)?;
    let event_id = matches.value_of("event").unwrap();

    let event = fetch_event(&org, &project, event_id)?;
    let release = extract_release(&event)?;

    if event.exception.values.is_empty() {
        warning("Event has no exception captured, there is no use for source maps");
        return Err(QuietExit(0).into());
    }
    success("Event has a valid exception present");

    let exception = &event.exception.values[0];
    let stacktrace = exception.stacktrace.as_ref().ok_or_else(|| {
        error("Event exception has no stacktrace available");
        QuietExit(1)
    })?;
    success("Event has a valid stacktrace present");

    let mut frame = extract_top_frame(stacktrace).map_err(|err| {
        error(err);
        QuietExit(1)
    })?;

    if exception.raw_stacktrace.is_some() {
        if matches.is_present("force") {
            warning(
                "Exception is already source mapped, however 'force' flag was used. Moving along.",
            );
            let raw_stacktrace = exception.raw_stacktrace.as_ref().unwrap();
            frame = extract_top_frame(raw_stacktrace).map_err(|err| {
                error(err);
                QuietExit(1)
            })?;
        } else {
            warning("Exception is already source mapped and resolves to:\n");
            print_mapped_frame(frame);
            return Err(QuietExit(0).into());
        }
    }

    let artifacts = fetch_release_artifacts(&org, &project, &release)?;
    let matched_artifact = find_matching_artifact(&artifacts, frame.abs_path.as_ref().unwrap())?;

    verify_dists_matches(&matched_artifact, event.dist.as_deref())?;

    let sourcemap_location =
        discover_sourcemaps_location(&org, &project, &release, &matched_artifact).map_err(
            |err| {
                error(err);
                QuietExit(1)
            },
        )?;
    success(format!("Found source map location: {}", sourcemap_location));

    let sourcemap_artifact = find_matching_artifact(&artifacts, &sourcemap_location)?;
    verify_dists_matches(&sourcemap_artifact, event.dist.as_deref())?;

    let sourcemap_file =
        fetch_release_artifact_file(&org, &project, &release, &sourcemap_artifact)?;

    print_sourcemap(
        &sourcemap_file,
        frame.lineno.unwrap() as u32 - 1,
        frame.colno.unwrap() as u32 - 1,
    )
    .map_err(|err| {
        error(err);
        QuietExit(1)
    })?;

    success("Source Maps should be working fine. Have you tried turning it off and on again?");
    Ok(())
}
<commit_msg>ref: Change comment format for find_matching_artifact<commit_after>use std::io::Read;
use std::path::Path;

use anyhow::{bail, format_err, Result};
use clap::{Arg, ArgMatches, Command};
use console::style;
use sentry::protocol::{Frame, Stacktrace};
use url::Url;

use crate::api::{Api, Artifact, ProcessedEvent};
use crate::config::Config;
use crate::utils::fs::TempFile;
use crate::utils::system::QuietExit;

use super::resolve::print_source;

pub fn make_command(command: Command) -> Command {
    command
        .about("Explain why sourcemaps are not working for a given event.")
        .alias("why")
        .arg(
            Arg::new("event")
                .value_name("EVENT_ID")
                .required(true)
                .help("ID of an event to be explained."),
        )
        .arg(
            Arg::new("force")
                .long("force")
                .short('f')
                .help("Force full validation flow, even when event is already source mapped."),
        )
}

fn tip<S>(msg: S)
where
    S: std::fmt::Display,
{
    println!("{}", style(format!("ℹ {}", msg)).blue());
}

fn success<S>(msg: S)
where
    S: std::fmt::Display,
{
    println!("{}", style(format!("✔ {}", msg)).green());
}

fn warning<S>(msg: S)
where
    S: std::fmt::Display,
{
    println!("{}", style(format!("⚠ {}", msg)).yellow());
}

fn error<S>(msg: S)
where
    S: std::fmt::Display,
{
    println!("{}", style(format!("✖ {}", msg)).red());
}

fn fetch_event(org: &str, project: &str, event_id: &str) -> Result<ProcessedEvent> {
    match Api::current().get_event(org, Some(project), event_id)? {
        Some(event) => {
            success(format!("Fetched data for event: {}", event_id));
            Ok(event)
        }
        None => {
            error(format!("Could not retrieve event {}", event_id));
            tip("Make sure that event ID you used is valid.");
            Err(QuietExit(1).into())
        }
    }
}

fn extract_top_frame(stacktrace: &Stacktrace) -> Result<&Frame> {
    let in_app_frames: Vec<&Frame> = stacktrace
        .frames
        .iter()
        .filter(|frame| frame.in_app.unwrap_or(false))
        .collect();

    if in_app_frames.is_empty() {
        bail!("Event exception stacktrace has no in_app frames");
    }

    let top_frame = in_app_frames.last().unwrap();
    let abs_path = top_frame
        .abs_path
        .as_ref()
        .ok_or_else(|| format_err!("Top frame is missing an abs_path"))?;

    if let Ok(abs_path) = Url::parse(abs_path) {
        if Path::new(abs_path.path()).extension().is_none() {
            bail!("Top frame of event exception originates from the <script> tag, its not possible to resolve source maps");
        }
    } else {
        bail!("Event exception stacktrace top frame has incorrect abs_path (valid url is required). Found {}", abs_path);
    }

    Ok(top_frame)
}

fn fetch_release_artifacts(org: &str, project: &str, release: &str) -> Result<Vec<Artifact>> {
    Api::current().list_release_files(org, Some(project), release).map(|artifacts| {
        if artifacts.is_empty() {
            error("Release has no artifacts uploaded");
            tip("https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js/#verify-artifacts-are-uploaded");
            return Err(QuietExit(1).into());
        }
        Ok(artifacts)
    })?
}

// Try to find an artifact which matches the path part of the url extracted from the stacktrace frame,
// prefixed with the default `~/`, which is a "glob-like" pattern for matchin any hostname.
//
// We only need the `pathname` portion of the url, so if it's absolute, just extract it.
// If it's relative however, parse any random url (example.com) and join it with our relative url,
// as Rust cannot handle parsing of relative urls.
//
// http://localhost:5000/dist/bundle.min.js => ~/dist/bundle.min.js
// /dist/bundle.js.map => ~/dist/bundle.js.map
// okboomer => error (invalid relative path, no extension)
//
// It should be more generic than using the defaults, but should be sufficient for our current usecase.
fn find_matching_artifact(artifacts: &[Artifact], abs_path: &str) -> Result<Artifact> {
    let abs_path = match Url::parse(abs_path) {
        Ok(path) => Ok(path),
        Err(_) => {
            let base = Url::parse("http://example.com").unwrap();
            base.join(abs_path)
                .map_err(|_| format_err!("Cannot parse source map url {}", abs_path))
        }
    }?;
    let mut filename = String::from("~");
    filename.push_str(abs_path.path());

    let full_match = artifacts.iter().find(|a| a.name == filename);
    let partial_match = artifacts
        .iter()
        .find(|a| a.name.ends_with(filename.split('/').last().unwrap()));

    if full_match.is_none() {
        error(format!(
            "Uploaded artifacts do not include entry: {}",
            filename
        ));

        if let Some(pm) = partial_match {
            tip(format!(
                "Found entry with partially matching filename: {}. \
                Make sure that that --url-prefix is set correctly.",
                pm.name,
            ));
        }

        return Err(QuietExit(1).into());
    }

    success(format!("Artifact {} found.", filename));
    Ok(full_match.cloned().unwrap())
}

fn verify_dists_matches(artifact: &Artifact, dist: Option<&str>) -> Result<()> {
    if artifact.dist.as_deref() != dist {
        error(format!(
            "Release artifact distrubition mismatch. Event: {}, Artifact: {}",
            dist.unwrap_or("[none]"),
            artifact.dist.as_ref().unwrap_or(&String::from("[none]"))
        ));
        tip("Configure 'dist' option in the SDK to match the one used during artifacts upload.\n  \
            https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js/#verify-artifact-distribution-value-matches-value-configured-in-your-sdk");

        return Err(QuietExit(1).into());
    }

    success(format!(
        "Release artifact distrubition matched. Event: {}, Artifact: {}",
        dist.unwrap_or("[none]"),
        artifact.dist.as_ref().unwrap_or(&String::from("[none]"))
    ));
    Ok(())
}

fn fetch_release_artifact_file(
    org: &str,
    project: &str,
    release: &str,
    artifact: &Artifact,
) -> Result<TempFile> {
    let api = Api::current();
    let file = TempFile::create()?;

    api.get_release_file(
        org,
        Some(project),
        release,
        &artifact.id,
        &mut file.open().unwrap(),
    )
    .map(|_| {
        success(format!(
            "Successfully fetched {} file from the server.",
            artifact.name
        ));
        Ok(file)
    })
    .map_err(|err| {
        format_err!(
            "Could not retrieve file {} from release {}: {:?}",
            artifact.name,
            release,
            err
        )
    })?
}

fn fetch_release_artifact_file_metadata(
    org: &str,
    project: &str,
    release: &str,
    artifact: &Artifact,
) -> Result<Artifact> {
    let api = Api::current();
    let file_metadata = api.get_release_file_metadata(org, Some(project), release, &artifact.id)?;
    file_metadata
        .ok_or_else(|| format_err!("Could not retrieve file metadata: {}", &artifact.id))
        .map(|f| {
            success(format!(
                "Successfully fetched {} file metadata from the server.",
                artifact.name
            ));
            f
        })
}

// https://github.com/getsentry/sentry/blob/623c2f5f3313e6dc55e08e2ae2b11d8f90cdbece/src/sentry/lang/javascript/processor.py#L145-L207
fn discover_sourcemaps_location(
    org: &str,
    project: &str,
    release: &str,
    artifact: &Artifact,
) -> Result<String> {
    let file_metadata = fetch_release_artifact_file_metadata(org, project, release, artifact)?;

    if let Some(header) = file_metadata.headers.get("Sourcemap") {
        return Ok(header.to_owned());
    }

    if let Some(header) = file_metadata.headers.get("X-SourceMap") {
        return Ok(header.to_owned());
    }

    let file = fetch_release_artifact_file(org, project, release, artifact)?;

    let mut f = file.open()?;
    let mut buffer = String::new();
    f.read_to_string(&mut buffer)?;

    for line in buffer.lines().rev() {
        if line.starts_with("//# sourceMappingURL=") || line.starts_with("//@ sourceMappingURL=") {
            let possible_sourcemap = line[21..].trim();
            if possible_sourcemap.starts_with("data:application/json") {
                bail!("Found inlined source maps, this tool doesnt support further verification for this scenario yet");
            }
            return Ok(possible_sourcemap.to_owned());
        }
    }

    Err(format_err!("Failed to discover source map url"))
}

fn print_sourcemap(file: &TempFile, line: u32, column: u32) -> Result<()> {
    let mut f = file.open()?;
    let mut buf = vec![];
    f.read_to_end(&mut buf)?;
    let sm = sourcemap::decode_slice(&buf)?;

    if let Some(token) = sm.lookup_token(line, column) {
        if let Some(view) = token.get_source_view() {
            success("Sourcemap position resolves to:");
            print_source(&token, view);
        } else if token.get_source_view().is_none() {
            bail!("cannot find source");
        } else {
            bail!("cannot find source for line {} column {}", line, column);
        }
    } else {
        bail!("invalid sourcemap location");
    }

    Ok(())
}

fn print_mapped_frame(frame: &Frame) {
    println!(
        "{}",
        style(
            frame
                .pre_context
                .iter()
                .map(|l| format!("  {}", l))
                .collect::<Vec<String>>()
                .join("\n")
        )
        .yellow()
    );
    println!(
        "{}",
        style(format!("> {}", frame.context_line.as_ref().unwrap())).yellow()
    );
    println!(
        "{}",
        style(
            frame
                .post_context
                .iter()
                .map(|l| format!("  {}", l))
                .collect::<Vec<String>>()
                .join("\n")
        )
        .yellow()
    );
}

fn extract_release(event: &ProcessedEvent) -> Result<String> {
    if let Some(release) = event.release.as_ref() {
        success(format!("Event has release name: {}", release));
        Ok(release.to_string())
    } else {
        error("Event is missing a release name");
        tip("Configure 'release' option in the SDK.\n  \
            https://docs.sentry.io/platforms/javascript/configuration/options/#release\n  \
            https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js/#verify-a-release-is-configured-in-your-sdk");
        Err(QuietExit(1).into())
    }
}

pub fn execute(matches: &ArgMatches) -> Result<()> {
    let config = Config::current();
    let (org, project) = config.get_org_and_project(matches)?;
    let event_id = matches.value_of("event").unwrap();

    let event = fetch_event(&org, &project, event_id)?;
    let release = extract_release(&event)?;

    if event.exception.values.is_empty() {
        warning("Event has no exception captured, there is no use for source maps");
        return Err(QuietExit(0).into());
    }
    success("Event has a valid exception present");

    let exception = &event.exception.values[0];
    let stacktrace = exception.stacktrace.as_ref().ok_or_else(|| {
        error("Event exception has no stacktrace available");
        QuietExit(1)
    })?;
    success("Event has a valid stacktrace present");

    let mut frame = extract_top_frame(stacktrace).map_err(|err| {
        error(err);
        QuietExit(1)
    })?;

    if exception.raw_stacktrace.is_some() {
        if matches.is_present("force") {
            warning(
                "Exception is already source mapped, however 'force' flag was used. Moving along.",
            );
            let raw_stacktrace = exception.raw_stacktrace.as_ref().unwrap();
            frame = extract_top_frame(raw_stacktrace).map_err(|err| {
                error(err);
                QuietExit(1)
            })?;
        } else {
            warning("Exception is already source mapped and resolves to:\n");
            print_mapped_frame(frame);
            return Err(QuietExit(0).into());
        }
    }

    let artifacts = fetch_release_artifacts(&org, &project, &release)?;
    let matched_artifact = find_matching_artifact(&artifacts, frame.abs_path.as_ref().unwrap())?;

    verify_dists_matches(&matched_artifact, event.dist.as_deref())?;

    let sourcemap_location =
        discover_sourcemaps_location(&org, &project, &release, &matched_artifact).map_err(
            |err| {
                error(err);
                QuietExit(1)
            },
        )?;
    success(format!("Found source map location: {}", sourcemap_location));

    let sourcemap_artifact = find_matching_artifact(&artifacts, &sourcemap_location)?;
    verify_dists_matches(&sourcemap_artifact, event.dist.as_deref())?;

    let sourcemap_file =
        fetch_release_artifact_file(&org, &project, &release, &sourcemap_artifact)?;

    print_sourcemap(
        &sourcemap_file,
        frame.lineno.unwrap() as u32 - 1,
        frame.colno.unwrap() as u32 - 1,
    )
    .map_err(|err| {
        error(err);
        QuietExit(1)
    })?;

    success("Source Maps should be working fine. Have you tried turning it off and on again?");
    Ok(())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::ApiMsg;
use bincode::{serialize, Infinite};
use byteorder::{LittleEndian, WriteBytesExt};
use std::any::TypeId;
use std::fmt::Debug;
use std::fs::File;
use std::io::Write;
use std::mem;
use std::path::PathBuf;

pub static WEBRENDER_RECORDING_HEADER: u64 = 0xbeefbeefbeefbe01u64;

pub trait ApiRecordingReceiver: Send + Debug {
    fn write_msg(&mut self, frame: u32, msg: &ApiMsg);
    fn write_payload(&mut self, frame: u32, data: &[u8]);
}

#[derive(Debug)]
pub struct BinaryRecorder {
    file: File,
}

impl BinaryRecorder {
    pub fn new(dest: &PathBuf) -> BinaryRecorder {
        let mut file = File::create(dest).unwrap();

        // write the header
        let apimsg_type_id = unsafe {
            assert!(mem::size_of::<TypeId>() == mem::size_of::<u64>());
            mem::transmute::<TypeId, u64>(TypeId::of::<ApiMsg>())
        };
        file.write_u64::<LittleEndian>(WEBRENDER_RECORDING_HEADER)
            .ok();
        file.write_u64::<LittleEndian>(apimsg_type_id).ok();

        BinaryRecorder { file }
    }

    fn write_length_and_data(&mut self, data: &[u8]) {
        self.file.write_u32::<LittleEndian>(data.len() as u32).ok();
        self.file.write(data).ok();
    }
}

impl ApiRecordingReceiver for BinaryRecorder {
    fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
        if should_record_msg(msg) {
            let buf = serialize(msg, Infinite).unwrap();
            self.write_length_and_data(&buf);
        }
    }

    fn write_payload(&mut self, _: u32, data: &[u8]) {
        // signal payload with a 0 length
        self.file.write_u32::<LittleEndian>(0).ok();
        self.write_length_and_data(data);
    }
}

pub fn should_record_msg(msg: &ApiMsg) -> bool {
    match *msg {
        ApiMsg::UpdateResources(..) |
        ApiMsg::AddDocument { .. } |
        ApiMsg::UpdateDocument(..) |
        ApiMsg::DeleteDocument(..) => true,
        _ => false,
    }
}
<commit_msg>Auto merge of #1991 - glennw:fix-servo-record, r=jrmuizel<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{ApiMsg, DocumentMsg};
use bincode::{serialize, Infinite};
use byteorder::{LittleEndian, WriteBytesExt};
use std::any::TypeId;
use std::fmt::Debug;
use std::fs::File;
use std::io::Write;
use std::mem;
use std::path::PathBuf;

pub static WEBRENDER_RECORDING_HEADER: u64 = 0xbeefbeefbeefbe01u64;

pub trait ApiRecordingReceiver: Send + Debug {
    fn write_msg(&mut self, frame: u32, msg: &ApiMsg);
    fn write_payload(&mut self, frame: u32, data: &[u8]);
}

#[derive(Debug)]
pub struct BinaryRecorder {
    file: File,
}

impl BinaryRecorder {
    pub fn new(dest: &PathBuf) -> BinaryRecorder {
        let mut file = File::create(dest).unwrap();

        // write the header
        let apimsg_type_id = unsafe {
            assert!(mem::size_of::<TypeId>() == mem::size_of::<u64>());
            mem::transmute::<TypeId, u64>(TypeId::of::<ApiMsg>())
        };
        file.write_u64::<LittleEndian>(WEBRENDER_RECORDING_HEADER)
            .ok();
        file.write_u64::<LittleEndian>(apimsg_type_id).ok();

        BinaryRecorder { file }
    }

    fn write_length_and_data(&mut self, data: &[u8]) {
        self.file.write_u32::<LittleEndian>(data.len() as u32).ok();
        self.file.write(data).ok();
    }
}

impl ApiRecordingReceiver for BinaryRecorder {
    fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
        if should_record_msg(msg) {
            let buf = serialize(msg, Infinite).unwrap();
            self.write_length_and_data(&buf);
        }
    }

    fn write_payload(&mut self, _: u32, data: &[u8]) {
        // signal payload with a 0 length
        self.file.write_u32::<LittleEndian>(0).ok();
        self.write_length_and_data(data);
    }
}

pub fn should_record_msg(msg: &ApiMsg) -> bool {
    match *msg {
        ApiMsg::UpdateResources(..) |
        ApiMsg::AddDocument { .. } |
        ApiMsg::DeleteDocument(..) => true,
        ApiMsg::UpdateDocument(_, ref msg) => {
            match *msg {
                DocumentMsg::GetScrollNodeState(..) |
                DocumentMsg::HitTest(..) => false,
                _ => true,
            }
        }
        _ => false,
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::path::PathBuf;

use bevy::prelude::*;

use crate::config::database::DatabaseConfig;
use crate::model::{Scenario, World};

use self::pruner::Pruner;
use self::sqlite::SqliteStorage;

mod pruner;
pub mod sqlite;

pub struct StoragePlugin;

impl Plugin for StoragePlugin {
    fn build(&self, app: &mut AppBuilder) {
        let dbconfig: DatabaseConfig = app.world().get_resource().cloned().unwrap_or_default();

        if let Some(keep) = dbconfig.max_scenarios_to_keep {
            let prune_conn = open_from_conf(dbconfig.database_path.as_ref());
            app.insert_resource(Pruner::new(keep, prune_conn))
                .insert_resource(PruneTimer(Timer::from_seconds(
                    dbconfig.prune_interval_seconds as f32,
                    true,
                )))
                .add_system(prune_sys.system());
        }

        let main_conn = open_from_conf(dbconfig.database_path.as_ref());
        app.insert_resource(main_conn);
    }
}

fn open_from_conf(path: Option<&PathBuf>) -> SqliteStorage {
    match path {
        Some(path) => SqliteStorage::open(path),
        None => SqliteStorage::open_in_memory(),
    }
    .expect("Unable to open storage")
}

struct PruneTimer(Timer);

fn prune_sys(time: Res<Time>, mut timer: ResMut<PruneTimer>, mut pruner: ResMut<Pruner>) {
    timer.0.tick(time.delta());
    if timer.0.finished() {
        info!("Triggering prune");
        pruner.prune();
    }
}

/// Storage for models.
// TODO(zstewart): fix sqlite storage with some thread local magic so that non-mutating methods can
// use &self instead of &mut self.
pub trait Storage {
    /// Add a new root scenario. This scenario is the new root of a family of scenarios.
    fn add_root_scenario(&mut self, world: World, score: f64) -> Result<Scenario, Box<dyn Error>>;

    /// Add a new scenario that is the child of the specified scenario
    fn add_child_scenario(
        &mut self,
        world: World,
        score: f64,
        parent: &Scenario,
    ) -> Result<Scenario, Box<dyn Error>>;

    /// Returns the number of scenarios available.
    fn num_scenarios(&mut self) -> Result<u64, Box<dyn Error>>;

    /// Gets the nth scenario, in order of score (descending, so lower indexes are higher scoring
    /// scenarios). May return None if the index is outside the number of scenarios.
    fn get_nth_scenario_by_score(&mut self, index: u64)
        -> Result<Option<Scenario>, Box<dyn Error>>;

    /// Removes the bottom scoring scenarios, keeping up to number_to_keep top scoring scenarios.
    /// Returns the number of scenarios pruned.
    fn keep_top_scenarios_by_score(&mut self, number_to_keep: u64) -> Result<u64, Box<dyn Error>>;
}
<commit_msg>make storage dir if not already exists<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::path::PathBuf;

use bevy::prelude::*;

use crate::config::database::DatabaseConfig;
use crate::model::{Scenario, World};

use self::pruner::Pruner;
use self::sqlite::SqliteStorage;

mod pruner;
pub mod sqlite;

pub struct StoragePlugin;

impl Plugin for StoragePlugin {
    fn build(&self, app: &mut AppBuilder) {
        let dbconfig: DatabaseConfig = app.world().get_resource().cloned().unwrap_or_default();

        if let Some(keep) = dbconfig.max_scenarios_to_keep {
            let prune_conn = open_from_conf(dbconfig.database_path.as_ref());
            app.insert_resource(Pruner::new(keep, prune_conn))
                .insert_resource(PruneTimer(Timer::from_seconds(
                    dbconfig.prune_interval_seconds as f32,
                    true,
                )))
                .add_system(prune_sys.system());
        }

        let main_conn = open_from_conf(dbconfig.database_path.as_ref());
        app.insert_resource(main_conn);
    }
}

fn open_from_conf(path: Option<&PathBuf>) -> SqliteStorage {
    match path {
        Some(path) => {
            let parent = path.parent().expect("Storage path has no parent");
            std::fs::create_dir_all(parent).expect("Could not create storage dir");
            SqliteStorage::open(path)
        }
        None => SqliteStorage::open_in_memory(),
    }
    .expect("Unable to open storage")
}

struct PruneTimer(Timer);

fn prune_sys(time: Res<Time>, mut timer: ResMut<PruneTimer>, mut pruner: ResMut<Pruner>) {
    timer.0.tick(time.delta());
    if timer.0.finished() {
        info!("Triggering prune");
        pruner.prune();
    }
}

/// Storage for models.
// TODO(zstewart): fix sqlite storage with some thread local magic so that non-mutating methods can
// use &self instead of &mut self.
pub trait Storage {
    /// Add a new root scenario. This scenario is the new root of a family of scenarios.
    fn add_root_scenario(&mut self, world: World, score: f64) -> Result<Scenario, Box<dyn Error>>;

    /// Add a new scenario that is the child of the specified scenario
    fn add_child_scenario(
        &mut self,
        world: World,
        score: f64,
        parent: &Scenario,
    ) -> Result<Scenario, Box<dyn Error>>;

    /// Returns the number of scenarios available.
    fn num_scenarios(&mut self) -> Result<u64, Box<dyn Error>>;

    /// Gets the nth scenario, in order of score (descending, so lower indexes are higher scoring
    /// scenarios). May return None if the index is outside the number of scenarios.
    fn get_nth_scenario_by_score(&mut self, index: u64)
        -> Result<Option<Scenario>, Box<dyn Error>>;

    /// Removes the bottom scoring scenarios, keeping up to number_to_keep top scoring scenarios.
    /// Returns the number of scenarios pruned.
    fn keep_top_scenarios_by_score(&mut self, number_to_keep: u64) -> Result<u64, Box<dyn Error>>;
}
<|endoftext|>


<commit_before>use core::libc::*;

use allegro5::color::ALLEGRO_COLOR;
use allegro5::rust_util::c_bool;

pub mod C
{
	use core::libc::*;

	use allegro5::color::ALLEGRO_COLOR;
	use allegro5::rust_util::c_bool;

	pub struct ALLEGRO_BITMAP;

	pub extern "C"
	{
		fn al_set_new_bitmap_format(format : c_int);
		fn al_set_new_bitmap_flags(flags : c_int);
		fn al_get_new_bitmap_format() -> c_int;
		fn al_get_new_bitmap_flags() -> c_int;
		fn al_add_new_bitmap_flag(flag : c_int);

		fn al_get_bitmap_width(bitmap : *mut ALLEGRO_BITMAP) -> c_int;
		fn al_get_bitmap_height(bitmap : *mut ALLEGRO_BITMAP) -> c_int;
		fn al_get_bitmap_format(bitmap : *mut ALLEGRO_BITMAP) -> c_int;
		fn al_get_bitmap_flags(bitmap : *mut ALLEGRO_BITMAP) -> c_int;

		fn al_create_bitmap(w : c_int, h : c_int) -> *mut ALLEGRO_BITMAP;
		fn al_create_custom_bitmap(w : c_int, h : c_int, upload : extern "C" fn(bitmap : *mut ALLEGRO_BITMAP, data : *mut c_void) -> c_bool, data : *mut c_void) -> *mut ALLEGRO_BITMAP;
		fn al_destroy_bitmap(bitmap : *mut ALLEGRO_BITMAP);

		fn al_put_pixel(x : c_int, y : c_int, color : ALLEGRO_COLOR);
		fn al_put_blended_pixel(x : c_int, y : c_int, color : ALLEGRO_COLOR);
		fn al_get_pixel(bitmap : *mut ALLEGRO_BITMAP, x : c_int, y : c_int) -> ALLEGRO_COLOR;

		fn al_convert_mask_to_alpha(bitmap : *mut ALLEGRO_BITMAP, mask_color : ALLEGRO_COLOR);

		fn al_set_clipping_rectangle(x : c_int, y : c_int, width : c_int, height : c_int);
		fn al_reset_clipping_rectangle();
		fn al_get_clipping_rectangle(x : *mut c_int, y : *mut c_int, w : *mut c_int, h : *mut c_int);

		fn al_create_sub_bitmap(parent : *mut ALLEGRO_BITMAP, x : c_int, y : c_int, w : c_int, h : c_int) -> *mut ALLEGRO_BITMAP;
		fn al_is_sub_bitmap(bitmap : *mut ALLEGRO_BITMAP) -> c_bool;
		fn al_get_parent_bitmap(bitmap : *mut ALLEGRO_BITMAP) -> *mut ALLEGRO_BITMAP;

		fn al_clone_bitmap(bitmap : *mut ALLEGRO_BITMAP) -> *mut ALLEGRO_BITMAP;
		fn al_convert_bitmap(bitmap : *mut ALLEGRO_BITMAP);
		fn al_convert_bitmaps();
	}
}

pub struct ALLEGRO_BITMAP
{
	Payload : *mut C::ALLEGRO_BITMAP
}

unsafe fn ToOption(c_bmp : *mut C::ALLEGRO_BITMAP) -> Option<ALLEGRO_BITMAP>
{
	match c_bmp
	{
		b if ptr::is_null(b) => None,
		b => Some(ALLEGRO_BITMAP{Payload : b})
	}
}

impl Drop for ALLEGRO_BITMAP
{
	fn finalize(&self)
	{
		debug!("%s", "Finalizing bitmap.");
		unsafe
		{
			C::al_destroy_bitmap(self.Payload);
		}
	}
}

pub static ALLEGRO_MEMORY_BITMAP: i32                 = 0x0001;
pub static _ALLEGRO_KEEP_BITMAP_FORMAT: i32           = 0x0002;
pub static ALLEGRO_FORCE_LOCKING: i32                 = 0x0004;
pub static ALLEGRO_NO_PRESERVE_TEXTURE: i32           = 0x0008;
pub static _ALLEGRO_ALPHA_TEST: i32                   = 0x0010;
pub static _ALLEGRO_INTERNAL_OPENGL: i32              = 0x0020;
pub static ALLEGRO_MIN_LINEAR: i32                    = 0x0040;
pub static ALLEGRO_MAG_LINEAR: i32                    = 0x0080;
pub static ALLEGRO_MIPMAP: i32                        = 0x0100;
pub static _ALLEGRO_NO_PREMULTIPLIED_ALPHA: i32       = 0x0200;
pub static ALLEGRO_VIDEO_BITMAP: i32                  = 0x0400;
pub static ALLEGRO_CONVERT_BITMAP: i32                = 0x1000;

pub fn al_set_new_bitmap_format(format : i32)
{
	unsafe
	{
		C::al_set_new_bitmap_format(format as c_int);
	}
}

pub fn al_set_new_bitmap_flags(flags : i32)
{
	unsafe
	{
		C::al_set_new_bitmap_flags(flags as c_int);
	}
}

pub fn al_get_new_bitmap_format() -> i32
{
	unsafe
	{
		return C::al_get_new_bitmap_format() as i32;
	}
}

pub fn al_get_new_bitmap_flags() -> i32
{
	unsafe
	{
		return C::al_get_new_bitmap_flags() as i32;
	}
}

pub fn al_add_new_bitmap_flag(flag : i32)
{
	unsafe
	{
		C::al_add_new_bitmap_flag(flag as c_int);
	}
}

pub fn al_get_bitmap_width(bitmap : &ALLEGRO_BITMAP) -> i32
{
	unsafe
	{
		return C::al_get_bitmap_width(bitmap.Payload) as i32;
	}
}

pub fn al_get_bitmap_height(bitmap : &ALLEGRO_BITMAP) -> i32
{
	unsafe
	{
		return C::al_get_bitmap_height(bitmap.Payload) as i32;
	}
}

pub fn al_get_bitmap_format(bitmap : &ALLEGRO_BITMAP) -> i32
{
	unsafe
	{
		return C::al_get_bitmap_format(bitmap.Payload) as i32;
	}
}

pub fn al_get_bitmap_flags(bitmap : &ALLEGRO_BITMAP) -> i32
{
	unsafe
	{
		return C::al_get_bitmap_flags(bitmap.Payload) as i32;
	}
}

pub fn al_create_bitmap(w : i32, h : i32) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		return ToOption(C::al_create_bitmap(w as c_int, h as c_int));
	}
}

pub unsafe fn al_create_custom_bitmap(w : i32, h : i32, upload : extern "C" fn(bitmap : *mut C::ALLEGRO_BITMAP, data : *mut c_void) -> c_bool, data : *mut c_void) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		ToOption(C::al_create_custom_bitmap(w as c_int, h as c_int, upload, data))
	}
}

pub fn al_convert_mask_to_alpha(bitmap : &ALLEGRO_BITMAP, mask_color : ALLEGRO_COLOR)
{
	unsafe
	{
		C::al_convert_mask_to_alpha(bitmap.Payload, mask_color);
	}
}

pub fn al_set_clipping_rectangle(x : i32, y : i32, width : i32, height : i32)
{
	unsafe
	{
		C::al_set_clipping_rectangle(x as c_int, y as c_int, width as c_int, height as c_int);
	}
}

pub fn al_reset_clipping_rectangle()
{
	unsafe
	{
		C::al_reset_clipping_rectangle();
	}
}

pub fn al_get_clipping_rectangle(x : &mut i32, y : &mut i32, w : &mut i32, h : &mut i32)
{
	unsafe
	{
		C::al_get_clipping_rectangle(x as *mut c_int, y as *mut c_int, w as *mut c_int, h as *mut c_int);
	}
}

pub fn al_create_sub_bitmap(parent : &ALLEGRO_BITMAP, x : i32, y : i32, w : i32, h : i32) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		return ToOption(C::al_create_sub_bitmap(parent.Payload, x as c_int, y as c_int, w as c_int, h as c_int));
	}
}

pub fn al_is_sub_bitmap(bitmap : &ALLEGRO_BITMAP) -> bool
{
	unsafe
	{
		return C::al_is_sub_bitmap(bitmap.Payload) as bool;
	}
}

pub fn al_get_parent_bitmap(bitmap : &ALLEGRO_BITMAP) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		return ToOption(C::al_get_parent_bitmap(bitmap.Payload));
	}
}

pub fn al_clone_bitmap(bitmap : &ALLEGRO_BITMAP) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		return ToOption(C::al_clone_bitmap(bitmap.Payload));
	}
}

pub fn al_convert_bitmap(bitmap : &ALLEGRO_BITMAP)
{
	unsafe
	{
		C::al_convert_bitmap(bitmap.Payload);
	}
}

pub fn al_convert_bitmaps()
{
	unsafe
	{
		C::al_convert_bitmaps();
	}
}
<commit_msg>Screw around with al_create_custom_bitmap to make it accept Rust function pointers<commit_after>use core::libc::*;

use allegro5::color::ALLEGRO_COLOR;
use allegro5::rust_util::c_bool;

pub mod C
{
	use core::libc::*;

	use allegro5::color::ALLEGRO_COLOR;
	use allegro5::rust_util::c_bool;

	pub struct ALLEGRO_BITMAP;

	pub extern "C"
	{
		fn al_set_new_bitmap_format(format : c_int);
		fn al_set_new_bitmap_flags(flags : c_int);
		fn al_get_new_bitmap_format() -> c_int;
		fn al_get_new_bitmap_flags() -> c_int;
		fn al_add_new_bitmap_flag(flag : c_int);

		fn al_get_bitmap_width(bitmap : *mut ALLEGRO_BITMAP) -> c_int;
		fn al_get_bitmap_height(bitmap : *mut ALLEGRO_BITMAP) -> c_int;
		fn al_get_bitmap_format(bitmap : *mut ALLEGRO_BITMAP) -> c_int;
		fn al_get_bitmap_flags(bitmap : *mut ALLEGRO_BITMAP) -> c_int;

		fn al_create_bitmap(w : c_int, h : c_int) -> *mut ALLEGRO_BITMAP;
		fn al_create_custom_bitmap(w : c_int, h : c_int, upload : extern "C" fn(bitmap : *mut ALLEGRO_BITMAP, data : *mut c_void) -> c_bool, data : *mut c_void) -> *mut ALLEGRO_BITMAP;
		fn al_destroy_bitmap(bitmap : *mut ALLEGRO_BITMAP);

		fn al_put_pixel(x : c_int, y : c_int, color : ALLEGRO_COLOR);
		fn al_put_blended_pixel(x : c_int, y : c_int, color : ALLEGRO_COLOR);
		fn al_get_pixel(bitmap : *mut ALLEGRO_BITMAP, x : c_int, y : c_int) -> ALLEGRO_COLOR;

		fn al_convert_mask_to_alpha(bitmap : *mut ALLEGRO_BITMAP, mask_color : ALLEGRO_COLOR);

		fn al_set_clipping_rectangle(x : c_int, y : c_int, width : c_int, height : c_int);
		fn al_reset_clipping_rectangle();
		fn al_get_clipping_rectangle(x : *mut c_int, y : *mut c_int, w : *mut c_int, h : *mut c_int);

		fn al_create_sub_bitmap(parent : *mut ALLEGRO_BITMAP, x : c_int, y : c_int, w : c_int, h : c_int) -> *mut ALLEGRO_BITMAP;
		fn al_is_sub_bitmap(bitmap : *mut ALLEGRO_BITMAP) -> c_bool;
		fn al_get_parent_bitmap(bitmap : *mut ALLEGRO_BITMAP) -> *mut ALLEGRO_BITMAP;

		fn al_clone_bitmap(bitmap : *mut ALLEGRO_BITMAP) -> *mut ALLEGRO_BITMAP;
		fn al_convert_bitmap(bitmap : *mut ALLEGRO_BITMAP);
		fn al_convert_bitmaps();
	}
}

pub struct ALLEGRO_BITMAP
{
	Payload : *mut C::ALLEGRO_BITMAP
}

unsafe fn ToOption(c_bmp : *mut C::ALLEGRO_BITMAP) -> Option<ALLEGRO_BITMAP>
{
	match c_bmp
	{
		b if ptr::is_null(b) => None,
		b => Some(ALLEGRO_BITMAP{Payload : b})
	}
}

impl Drop for ALLEGRO_BITMAP
{
	fn finalize(&self)
	{
		debug!("%s", "Finalizing bitmap.");
		unsafe
		{
			C::al_destroy_bitmap(self.Payload);
		}
	}
}

pub static ALLEGRO_MEMORY_BITMAP: i32                 = 0x0001;
pub static _ALLEGRO_KEEP_BITMAP_FORMAT: i32           = 0x0002;
pub static ALLEGRO_FORCE_LOCKING: i32                 = 0x0004;
pub static ALLEGRO_NO_PRESERVE_TEXTURE: i32           = 0x0008;
pub static _ALLEGRO_ALPHA_TEST: i32                   = 0x0010;
pub static _ALLEGRO_INTERNAL_OPENGL: i32              = 0x0020;
pub static ALLEGRO_MIN_LINEAR: i32                    = 0x0040;
pub static ALLEGRO_MAG_LINEAR: i32                    = 0x0080;
pub static ALLEGRO_MIPMAP: i32                        = 0x0100;
pub static _ALLEGRO_NO_PREMULTIPLIED_ALPHA: i32       = 0x0200;
pub static ALLEGRO_VIDEO_BITMAP: i32                  = 0x0400;
pub static ALLEGRO_CONVERT_BITMAP: i32                = 0x1000;

pub fn al_set_new_bitmap_format(format : i32)
{
	unsafe
	{
		C::al_set_new_bitmap_format(format as c_int);
	}
}

pub fn al_set_new_bitmap_flags(flags : i32)
{
	unsafe
	{
		C::al_set_new_bitmap_flags(flags as c_int);
	}
}

pub fn al_get_new_bitmap_format() -> i32
{
	unsafe
	{
		return C::al_get_new_bitmap_format() as i32;
	}
}

pub fn al_get_new_bitmap_flags() -> i32
{
	unsafe
	{
		return C::al_get_new_bitmap_flags() as i32;
	}
}

pub fn al_add_new_bitmap_flag(flag : i32)
{
	unsafe
	{
		C::al_add_new_bitmap_flag(flag as c_int);
	}
}

pub fn al_get_bitmap_width(bitmap : &ALLEGRO_BITMAP) -> i32
{
	unsafe
	{
		return C::al_get_bitmap_width(bitmap.Payload) as i32;
	}
}

pub fn al_get_bitmap_height(bitmap : &ALLEGRO_BITMAP) -> i32
{
	unsafe
	{
		return C::al_get_bitmap_height(bitmap.Payload) as i32;
	}
}

pub fn al_get_bitmap_format(bitmap : &ALLEGRO_BITMAP) -> i32
{
	unsafe
	{
		return C::al_get_bitmap_format(bitmap.Payload) as i32;
	}
}

pub fn al_get_bitmap_flags(bitmap : &ALLEGRO_BITMAP) -> i32
{
	unsafe
	{
		return C::al_get_bitmap_flags(bitmap.Payload) as i32;
	}
}

pub fn al_create_bitmap(w : i32, h : i32) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		return ToOption(C::al_create_bitmap(w as c_int, h as c_int));
	}
}

pub fn al_create_custom_bitmap<T>(w : i32, h : i32, upload : &fn(bitmap : Option<ALLEGRO_BITMAP>, data : &T) -> bool, data : &T) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		struct RustData<'self, T>
		{
			Upload : &'self fn(bitmap : Option<ALLEGRO_BITMAP>, &T) -> bool,
			Data : &'self T
		}

		extern "C"
		fn RustCallback<T>(bitmap : *mut C::ALLEGRO_BITMAP, data : *mut c_void) -> c_bool
		{
			unsafe
			{
				let rust_data : &mut RustData<T> = cast::transmute(data);
				return (rust_data.Upload)(ToOption(bitmap), rust_data.Data) as c_bool;
			}
		}

		let mut rust_data = RustData{Upload : upload, Data : data};

		ToOption(C::al_create_custom_bitmap(w as c_int, h as c_int, cast::transmute(RustCallback), cast::transmute(&rust_data)))
	}
}

pub fn al_convert_mask_to_alpha(bitmap : &ALLEGRO_BITMAP, mask_color : ALLEGRO_COLOR)
{
	unsafe
	{
		C::al_convert_mask_to_alpha(bitmap.Payload, mask_color);
	}
}

pub fn al_set_clipping_rectangle(x : i32, y : i32, width : i32, height : i32)
{
	unsafe
	{
		C::al_set_clipping_rectangle(x as c_int, y as c_int, width as c_int, height as c_int);
	}
}

pub fn al_reset_clipping_rectangle()
{
	unsafe
	{
		C::al_reset_clipping_rectangle();
	}
}

pub fn al_get_clipping_rectangle(x : &mut i32, y : &mut i32, w : &mut i32, h : &mut i32)
{
	unsafe
	{
		C::al_get_clipping_rectangle(x as *mut c_int, y as *mut c_int, w as *mut c_int, h as *mut c_int);
	}
}

pub fn al_create_sub_bitmap(parent : &ALLEGRO_BITMAP, x : i32, y : i32, w : i32, h : i32) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		return ToOption(C::al_create_sub_bitmap(parent.Payload, x as c_int, y as c_int, w as c_int, h as c_int));
	}
}

pub fn al_is_sub_bitmap(bitmap : &ALLEGRO_BITMAP) -> bool
{
	unsafe
	{
		return C::al_is_sub_bitmap(bitmap.Payload) as bool;
	}
}

pub fn al_get_parent_bitmap(bitmap : &ALLEGRO_BITMAP) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		return ToOption(C::al_get_parent_bitmap(bitmap.Payload));
	}
}

pub fn al_clone_bitmap(bitmap : &ALLEGRO_BITMAP) -> Option<ALLEGRO_BITMAP>
{
	unsafe
	{
		return ToOption(C::al_clone_bitmap(bitmap.Payload));
	}
}

pub fn al_convert_bitmap(bitmap : &ALLEGRO_BITMAP)
{
	unsafe
	{
		C::al_convert_bitmap(bitmap.Payload);
	}
}

pub fn al_convert_bitmaps()
{
	unsafe
	{
		C::al_convert_bitmaps();
	}
}
<|endoftext|>


<commit_before>use std::vec;
use std::libc::size_t;
use std::ptr;
use std::libc::{c_uint, c_int, c_void};
use std::cast;

use common::*;

#[inline(never)]
pub fn space_adaptive_quadrature(f: & |&[R]| -> R, min_corner: &[R], max_corner: &[R], rel_err: R, abs_err: R) -> R {
  let (val, status) = unsafe {
    let f_dom_space_dims = min_corner.len() as c_uint;
    let f_range_space_dims = 1 as c_uint;
    let f_pv: *c_void = cast::transmute(f);
    let integrand_caller_pv: *c_void = cast::transmute(h_integrand_caller);
    let min_bounds = min_corner.as_ptr();
    let max_bounds = max_corner.as_ptr();
    let max_evals = 0 as size_t;
    let norm_unused = 0u32;
    let mut val = 0 as R;
    let mut err = 0 as R;
    let status =
      hquadrature(f_range_space_dims,
                  integrand_caller_pv,
                  f_pv,
                  f_dom_space_dims, min_bounds, max_bounds,
                  max_evals, rel_err, abs_err,
                  norm_unused, &mut val, &mut err);
    (val, status)
  };

  if (status != 0) { fail!("hquadrature call returned non-zero status"); }

  val
}

// Perform Gaussian-Legendre quadrature of f on [a,b]x[c,d] using n weights per axis, for a total of 2n weights and n^2
// evaluation points.
#[inline(never)]
pub fn gaussian_quadrature_2D_rect(n: uint, f: & |x: R, y: R| -> R, a: R, b: R, c: R, d: R) -> R {
  let gq_order = {
    if n <= 10 { 2*n as uint}
    else if n <= 16 { 32 }
    else if n <= 32 { 64 }
    else if n <= 48 { 96 }
    else if n <= 64 { 128 }
    else if n <= 128 { 256 }
    else if n <= 256 { 512 }
    else { fail!("Degree limit exceeded for Gaussian quadrature.") }
  };
  unsafe {
    let f_pv: *c_void = cast::transmute(f);
    let gq_2D_integrand_caller_pv: *c_void = cast::transmute(gq_2D_integrand_caller);
    gauss_legendre_2D_rect(gq_order as c_int, gq_2D_integrand_caller_pv, f_pv, a, b, c, d)
  }
}

// Perform Gaussian-Legendre quadrature of f on [a,b] using n points.
#[inline(never)]
pub fn gaussian_quadrature(n: uint, f: & |R| -> R, a: R, b: R) -> R {
  let gq_order = {
    if n <= 10 { 2*n as uint}
    else if n <= 16 { 32 }
    else if n <= 32 { 64 }
    else if n <= 48 { 96 }
    else if n <= 64 { 128 }
    else if n <= 128 { 256 }
    else if n <= 256 { 512 }
    else { fail!("Degree limit exceeded for Gaussian quadrature.") }
  };
  unsafe {
    let f_pv: *c_void = cast::transmute(f);
    let gq_1D_integrand_caller_pv: *c_void = cast::transmute(gq_1D_integrand_caller);
    gauss_legendre(gq_order as c_int, gq_1D_integrand_caller_pv, f_pv, a, b)
  }
}

// This is the integrand callback function called directly by the space-adaptive C integration routine.
// Its job is to calculate the integrand value using f_ptr and set that value in *fval.
#[inline(never)]
extern fn h_integrand_caller(ndim: c_uint, x: *R,
                             f_ptr: *|x:&[R]| -> R,
                             _: c_uint, fval: *mut R) -> c_int {
  unsafe {
    let f = ptr::read_ptr(f_ptr);
    *fval = vec::raw::buf_as_slice(x, ndim as uint, f);
  }
  0 as c_int
}

// This is the integrand callback function called directly by the C 2D gaussian quadrature integration routine.
#[inline(never)]
extern fn gq_2D_integrand_caller(x: R, y: R, f_ptr: *|x: R, y: R| -> R) -> R {
  let f: |x: R, y: R| -> R = unsafe { ptr::read_ptr(f_ptr) };
  f(x, y)
}

// This is the integrand callback function called directly by the C 1D gaussian quadrature integration routine.
#[inline(never)]
extern fn gq_1D_integrand_caller(x: R, f_ptr: *|R| -> R) -> R {
  let f: |R| -> R = unsafe { ptr::read_ptr(f_ptr) };
  f(x)
}

// The external C integration routines.
#[link_args = "lib/adaptive_quadrature.o lib/gaussian_quadrature.o"]
extern {

  fn hquadrature(fdim: c_uint,
                 f: *c_void, fdata: *c_void,
                 dim: c_uint, xmin: *R, xmax: *R,
                 maxEval: size_t, reqAbsError: R, reqRelError: R,
                 norm: u32,
                 val: *mut R, err: *mut R) -> c_int;

  fn gauss_legendre_2D_rect(order: c_int,
                            f: *c_void,    // double (*f)(double,double,void*)
                            data: *c_void, // passed as last param to f for each evaluation
                            a: R, b: R, c: R, d: R) -> R;

  fn gauss_legendre(order: c_int,
                    f: *c_void,    // double (*f)(double,void*)
                    data: *c_void, // passed as last param to f for each evaluation
                    a: R, b: R) -> R;
}

#[test]
fn test_h_quadrature() {
  let f1 = |_: &[f64]| 2.0;
  let f2 = |x: &[f64]| 2.0*x[0]*x[1];
  let min_bounds = ~[0.,0.];
  let max_bounds = ~[1.,1.];
  assert_eq!(space_adaptive_quadrature(&f1, min_bounds, max_bounds, 1e-5, 1e-5), 2.0)
  assert_eq!(space_adaptive_quadrature(&f2, min_bounds, max_bounds, 1e-5, 1e-5), 0.5)
  assert_eq!(space_adaptive_quadrature(&f1, min_bounds, max_bounds, 1e-5, 1e-5), 2.0)
}

<commit_msg>Use optimal order in Gaussian quadrature.<commit_after>use std::vec;
use std::libc::size_t;
use std::ptr;
use std::libc::{c_uint, c_int, c_void};
use std::cast;

use common::*;

#[inline(never)]
pub fn space_adaptive_quadrature(f: & |&[R]| -> R, min_corner: &[R], max_corner: &[R], rel_err: R, abs_err: R) -> R {
  let (val, status) = unsafe {
    let f_dom_space_dims = min_corner.len() as c_uint;
    let f_range_space_dims = 1 as c_uint;
    let f_pv: *c_void = cast::transmute(f);
    let integrand_caller_pv: *c_void = cast::transmute(h_integrand_caller);
    let min_bounds = min_corner.as_ptr();
    let max_bounds = max_corner.as_ptr();
    let max_evals = 0 as size_t;
    let norm_unused = 0u32;
    let mut val = 0 as R;
    let mut err = 0 as R;
    let status =
      hquadrature(f_range_space_dims,
                  integrand_caller_pv,
                  f_pv,
                  f_dom_space_dims, min_bounds, max_bounds,
                  max_evals, rel_err, abs_err,
                  norm_unused, &mut val, &mut err);
    (val, status)
  };

  if (status != 0) { fail!("hquadrature call returned non-zero status"); }

  val
}

#[inline]
fn gq_order(n: uint) -> c_int {
  if n <= 20 { n as c_int }
  else if n <= 32 { 32 }
  else if n <= 64 { 64 }
  else if n <= 96 { 96 }
  else if n <= 128 { 128 }
  else if n <= 256 { 256 }
  else if n <= 512 { 512 }
  else { fail!("Degree limit exceeded for Gaussian quadrature.") }
}

// Perform Gaussian-Legendre quadrature of f on [a,b]x[c,d] using n weights per axis, for a total of 2n weights and n^2
// evaluation points.
#[inline(never)]
pub fn gaussian_quadrature_2D_rect(n: uint, f: & |x: R, y: R| -> R, a: R, b: R, c: R, d: R) -> R {
  unsafe {
    let f_pv: *c_void = cast::transmute(f);
    let gq_2D_integrand_caller_pv: *c_void = cast::transmute(gq_2D_integrand_caller);
    gauss_legendre_2D_rect(gq_order(n), gq_2D_integrand_caller_pv, f_pv, a, b, c, d)
  }
}

// Perform Gaussian-Legendre quadrature of f on [a,b] using n points.
#[inline(never)]
pub fn gaussian_quadrature(n: uint, f: & |R| -> R, a: R, b: R) -> R {
  unsafe {
    let f_pv: *c_void = cast::transmute(f);
    let gq_1D_integrand_caller_pv: *c_void = cast::transmute(gq_1D_integrand_caller);
    gauss_legendre(gq_order(n), gq_1D_integrand_caller_pv, f_pv, a, b)
  }
}

// This is the integrand callback function called directly by the space-adaptive C integration routine.
// Its job is to calculate the integrand value using f_ptr and set that value in *fval.
#[inline(never)]
extern fn h_integrand_caller(ndim: c_uint, x: *R,
                             f_ptr: *|x:&[R]| -> R,
                             _: c_uint, fval: *mut R) -> c_int {
  unsafe {
    let f = ptr::read_ptr(f_ptr);
    *fval = vec::raw::buf_as_slice(x, ndim as uint, f);
  }
  0 as c_int
}

// This is the integrand callback function called directly by the C 2D gaussian quadrature integration routine.
#[inline(never)]
extern fn gq_2D_integrand_caller(x: R, y: R, f_ptr: *|x: R, y: R| -> R) -> R {
  let f: |x: R, y: R| -> R = unsafe { ptr::read_ptr(f_ptr) };
  f(x, y)
}

// This is the integrand callback function called directly by the C 1D gaussian quadrature integration routine.
#[inline(never)]
extern fn gq_1D_integrand_caller(x: R, f_ptr: *|R| -> R) -> R {
  let f: |R| -> R = unsafe { ptr::read_ptr(f_ptr) };
  f(x)
}

// The external C integration routines.
#[link_args = "lib/adaptive_quadrature.o lib/gaussian_quadrature.o"]
extern {

  fn hquadrature(fdim: c_uint,
                 f: *c_void, fdata: *c_void,
                 dim: c_uint, xmin: *R, xmax: *R,
                 maxEval: size_t, reqAbsError: R, reqRelError: R,
                 norm: u32,
                 val: *mut R, err: *mut R) -> c_int;

  fn gauss_legendre_2D_rect(order: c_int,
                            f: *c_void,    // double (*f)(double,double,void*)
                            data: *c_void, // passed as last param to f for each evaluation
                            a: R, b: R, c: R, d: R) -> R;

  fn gauss_legendre(order: c_int,
                    f: *c_void,    // double (*f)(double,void*)
                    data: *c_void, // passed as last param to f for each evaluation
                    a: R, b: R) -> R;
}

#[test]
fn test_h_quadrature() {
  let f1 = |_: &[f64]| 2.0;
  let f2 = |x: &[f64]| 2.0*x[0]*x[1];
  let min_bounds = ~[0.,0.];
  let max_bounds = ~[1.,1.];
  assert_eq!(space_adaptive_quadrature(&f1, min_bounds, max_bounds, 1e-5, 1e-5), 2.0)
  assert_eq!(space_adaptive_quadrature(&f2, min_bounds, max_bounds, 1e-5, 1e-5), 0.5)
  assert_eq!(space_adaptive_quadrature(&f1, min_bounds, max_bounds, 1e-5, 1e-5), 2.0)
}

<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use std::collections::HashMap;
use front::ast::FRule;

use middle::analysis::ast::*;
use monad::partial::Partial::*;

use rust;

pub fn rule_duplicate<'a, 'b>(mut grammar: AGrammar<'a, 'b>, rules: Vec<FRule>) -> Partial<AGrammar<'a, 'b>>
{
  DuplicateItem::analyse(&grammar, rules.into_iter(), String::from("rule"))
  .map(|rules|
    rules.into_iter().map(|(_,frule)| Rule::new(frule.name, frule.def)).collect())
  .map(move |rules| { grammar.rules = rules; grammar })
}

pub fn rust_functions_duplicate<'a, 'b>(mut grammar: AGrammar<'a, 'b>,
  items: Vec<RItem>) -> Partial<AGrammar<'a, 'b>>
{
  let mut functions = vec![];
  let mut others = vec![];
  for item in items {
    if let &rust::ItemKind::Fn(..) = &item.node {
      functions.push(item);
    }
    else {
      others.push(item);
    }
  }
  DuplicateItem::analyse(&grammar, functions.into_iter(), String::from("rust function"))
    .map(move |functions| {
      grammar.rust_functions = functions;
      grammar.rust_items = others;
      grammar
    })
}

struct DuplicateItem<'a: 'c, 'b: 'a, 'c, Item>
{
  grammar: &'c AGrammar<'a, 'b>,
  items: HashMap<Ident, Item>,
  has_duplicate: bool,
  what_is_duplicated: String
}

impl<'a, 'b, 'c, Item> DuplicateItem<'a, 'b, 'c, Item> where
 Item: ItemIdent + ItemSpan
{
  pub fn analyse<ItemIter>(grammar: &'c AGrammar<'a, 'b>, iter: ItemIter, item_kind: String)
    -> Partial<HashMap<Ident, Item>> where
   ItemIter: Iterator<Item=Item>
  {
    let (min_size, _) = iter.size_hint();
    DuplicateItem {
      grammar: grammar,
      items: HashMap::with_capacity(min_size),
      has_duplicate: false,
      what_is_duplicated: item_kind
    }.populate(iter)
     .make()
  }

  fn populate<ItemIter: Iterator<Item=Item>>(mut self, iter: ItemIter)
    -> DuplicateItem<'a, 'b, 'c, Item>
  {
    for item in iter {
      let ident = item.ident();
      if self.items.contains_key(&ident) {
        self.duplicate_items(self.items.get(&ident).unwrap(), item);
        self.has_duplicate = true;
      } else {
        self.items.insert(ident, item);
      }
    }
    self
  }

  fn duplicate_items(&self, pre: &Item, current: Item) {
    self.grammar.multi_locations_err(vec![
      (current.span(),
      format!("duplicate definition of {} with name `{}`", self.what_is_duplicated, current.ident())),
      (pre.span(),
      format!("previous definition of `{}` here", pre.ident()))]
    );
  }

  fn make(self) -> Partial<HashMap<Ident, Item>> {
    if self.has_duplicate {
      Fake(self.items)
    } else {
      Value(self.items)
    }
  }
}
<commit_msg>[Analysis] HashMap was re-ordering rules which led to non-deterministic errors. Use a Vector now.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use std::collections::HashMap;
use front::ast::FRule;

use middle::analysis::ast::*;
use monad::partial::Partial::*;

use rust;

pub fn rule_duplicate<'a, 'b>(mut grammar: AGrammar<'a, 'b>, rules: Vec<FRule>) -> Partial<AGrammar<'a, 'b>>
{
  DuplicateItem::analyse(&grammar, rules.into_iter(), String::from("rule"))
  .map(|rules|
    rules.into_iter().map(|(_,frule)| Rule::new(frule.name, frule.def)).collect())
  .map(move |rules| { grammar.rules = rules; grammar })
}

pub fn rust_functions_duplicate<'a, 'b>(mut grammar: AGrammar<'a, 'b>,
  items: Vec<RItem>) -> Partial<AGrammar<'a, 'b>>
{
  let mut functions = vec![];
  let mut others = vec![];
  for item in items {
    if let &rust::ItemKind::Fn(..) = &item.node {
      functions.push(item);
    }
    else {
      others.push(item);
    }
  }
  DuplicateItem::analyse(&grammar, functions.into_iter(), String::from("rust function"))
    .map(move |functions| {
      grammar.rust_functions = functions.into_iter().collect();
      grammar.rust_items = others;
      grammar
    })
}

struct DuplicateItem<'a: 'c, 'b: 'a, 'c, Item>
{
  grammar: &'c AGrammar<'a, 'b>,
  items: Vec<(Ident, Item)>,
  has_duplicate: bool,
  what_is_duplicated: String
}

impl<'a, 'b, 'c, Item> DuplicateItem<'a, 'b, 'c, Item> where
 Item: ItemIdent + ItemSpan
{
  pub fn analyse<ItemIter>(grammar: &'c AGrammar<'a, 'b>, iter: ItemIter, item_kind: String)
    -> Partial<Vec<(Ident, Item)>> where
   ItemIter: Iterator<Item=Item>
  {
    DuplicateItem {
      grammar: grammar,
      items: vec![],
      has_duplicate: false,
      what_is_duplicated: item_kind
    }.populate(iter)
     .make()
  }

  fn populate<ItemIter: Iterator<Item=Item>>(mut self, iter: ItemIter)
    -> DuplicateItem<'a, 'b, 'c, Item>
  {
    for item in iter {
      let ident = item.ident();
      if self.items.iter().any(|&(id,_)| id == ident) {
        let &(_, ref dup_item) = self.items.iter().find(|&&(id,_)| id == ident).unwrap();
        self.duplicate_items(dup_item, item);
        self.has_duplicate = true;
      }
      else {
        self.items.push((ident, item));
      }
    }
    self
  }

  fn duplicate_items(&self, pre: &Item, current: Item) {
    self.grammar.multi_locations_err(vec![
      (current.span(),
      format!("duplicate definition of {} with name `{}`", self.what_is_duplicated, current.ident())),
      (pre.span(),
      format!("previous definition of `{}` here", pre.ident()))]
    );
  }

  fn make(self) -> Partial<Vec<(Ident, Item)>> {
    if self.has_duplicate {
      Fake(self.items)
    } else {
      Value(self.items)
    }
  }
}
<|endoftext|>


<commit_before>import ptr::{null, addr_of};
import result::{result, ok, err};
import libc::c_char;
import name_pool::{name_pool, methods};
import str::unsafe::from_c_str;
import io::writer_util;
import libc::types::common::c99::*;
import jsapi::*;
import jsapi::bindgen::*;

export JSOPTION_STRICT;
export JSOPTION_WERROR;
export JSOPTION_VAROBJFIX;
export JSOPTION_METHODJIT;

export JSCLASS_GLOBAL_FLAGS;

export crust;
export rust;

export jsapi;
export global;

// These are just macros in jsapi.h
import JS_NewRuntime = jsapi::bindgen::JS_Init;
export JS_NewRuntime;
import JS_DestroyRuntime = jsapi::bindgen::JS_Finish;
export JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
import JS_LockRuntime = jsapi::bindgen::JS_Lock;
export JS_LockRuntime;
import JS_UnlockRuntime = jsapi::bindgen::JS_Unlock;
export JS_UnlockRuntime;
*/

export JS_ARGV;
export JS_SET_RVAL;
export JSVAL_VOID;
export JSVAL_NULL;
export JSVAL_ZERO;
export JSVAL_ONE;
export JSVAL_FALSE;
export JSVAL_TRUE;

/* Look in this directory for spidermonkey */
#[link_args = "-L."]
/* Link to the static js library */
#[link_args = "-ljs_static"]
extern mod m { }

// FIXME: Add the remaining options
const JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
const JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
const JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
const JSOPTION_METHODJIT: uint32_t = 0b10000000000000u32;

const JSCLASS_GLOBAL_FLAGS: uint32_t = 0x47d00du32;

const default_heapsize: u32 = 8_u32 * 1024_u32 * 1024_u32;
const default_stacksize: uint = 8192u;
const ERR: JSBool = 0_i32;

const JSVAL_VOID: u64 =  0x0001fff2_00000000_u64;
const JSVAL_NULL: u64 =  0x0001fff6_00000000_u64;
const JSVAL_ZERO: u64 =  0x0001fff1_00000000_u64;
const JSVAL_ONE: u64 =   0x0001fff1_00000001_u64;
const JSVAL_FALSE: u64 = 0x0001fff3_00000000_u64;
const JSVAL_TRUE: u64 =  0x0001fff3_00000001_u64;

fn result(n: JSBool) -> result<(),()> {
    if n != ERR {ok(())} else {err(())}
}

type named_functions = @{
    names: [str],
    funcs: [JSFunctionSpec]
};

impl ptr_methods<T: copy> for *T {
    unsafe fn +(idx: uint) -> *T {
        ptr::offset(self, idx)
    }
    unsafe fn [](idx: uint) -> T {
        *(self + idx)
    }
}

unsafe fn JS_ARGV(_cx: *JSContext, vp: *jsval) -> *jsval {
    vp + 2u
}

unsafe fn JS_SET_RVAL(_cx: *JSContext, vp: *jsval, v: jsval) {
    let vp: *mut jsval = unsafe::reinterpret_cast(vp);
    *vp = v;
}

<commit_msg>Remove cyclic import *s<commit_after>import ptr::{null, addr_of};
import result::{result, ok, err};
import libc::c_char;
import name_pool::{name_pool, methods};
import str::unsafe::from_c_str;
import io::writer_util;
import jsapi::{JSBool, JSClass, JSContext, JSErrorReport, JSFunctionSpec,
               JSObject, JSRuntime, JSString, JSVERSION_LATEST, jsuint, jsval,
               uintN};
import jsapi::bindgen::{JS_free, JS_AddObjectRoot, JS_DefineFunctions,
                        JS_DestroyContext, JS_EncodeString, JS_EvaluateScript,
                        JS_Finish, JS_GetContextPrivate, JS_GetPrivate,
                        JS_Init, JS_InitStandardClasses,
                        JS_NewCompartmentAndGlobalObject, JS_NewContext,
                        JS_RemoveObjectRoot, JS_SetContextPrivate,
                        JS_SetErrorReporter, JS_SetOptions, JS_SetPrivate,
                        JS_SetVersion, JS_ValueToString};
import libc::types::common::c99::{int8_t, int16_t, int32_t, int64_t, uint8_t,
                                  uint16_t, uint32_t, uint64_t};

export JSOPTION_STRICT;
export JSOPTION_WERROR;
export JSOPTION_VAROBJFIX;
export JSOPTION_METHODJIT;

export JSCLASS_GLOBAL_FLAGS;

export crust;
export rust;

export jsapi;
export global;

// These are just macros in jsapi.h
import JS_NewRuntime = jsapi::bindgen::JS_Init;
export JS_NewRuntime;
import JS_DestroyRuntime = jsapi::bindgen::JS_Finish;
export JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
import JS_LockRuntime = jsapi::bindgen::JS_Lock;
export JS_LockRuntime;
import JS_UnlockRuntime = jsapi::bindgen::JS_Unlock;
export JS_UnlockRuntime;
*/

export JS_ARGV;
export JS_SET_RVAL;
export JSVAL_VOID;
export JSVAL_NULL;
export JSVAL_ZERO;
export JSVAL_ONE;
export JSVAL_FALSE;
export JSVAL_TRUE;

/* Look in this directory for spidermonkey */
#[link_args = "-L."]
/* Link to the static js library */
#[link_args = "-ljs_static"]
extern mod m { }

// FIXME: Add the remaining options
const JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
const JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
const JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
const JSOPTION_METHODJIT: uint32_t = 0b10000000000000u32;

const JSCLASS_GLOBAL_FLAGS: uint32_t = 0x47d00du32;

const default_heapsize: u32 = 8_u32 * 1024_u32 * 1024_u32;
const default_stacksize: uint = 8192u;
const ERR: JSBool = 0_i32;

const JSVAL_VOID: u64 =  0x0001fff2_00000000_u64;
const JSVAL_NULL: u64 =  0x0001fff6_00000000_u64;
const JSVAL_ZERO: u64 =  0x0001fff1_00000000_u64;
const JSVAL_ONE: u64 =   0x0001fff1_00000001_u64;
const JSVAL_FALSE: u64 = 0x0001fff3_00000000_u64;
const JSVAL_TRUE: u64 =  0x0001fff3_00000001_u64;

fn result(n: JSBool) -> result<(),()> {
    if n != ERR {ok(())} else {err(())}
}

type named_functions = @{
    names: [str],
    funcs: [JSFunctionSpec]
};

impl ptr_methods<T: copy> for *T {
    unsafe fn +(idx: uint) -> *T {
        ptr::offset(self, idx)
    }
    unsafe fn [](idx: uint) -> T {
        *(self + idx)
    }
}

unsafe fn JS_ARGV(_cx: *JSContext, vp: *jsval) -> *jsval {
    vp + 2u
}

unsafe fn JS_SET_RVAL(_cx: *JSContext, vp: *jsval, v: jsval) {
    let vp: *mut jsval = unsafe::reinterpret_cast(vp);
    *vp = v;
}

<|endoftext|>


<commit_before>#![warn(missing_docs, missing_debug_implementations)]

//! EGL utilities
//!
//! This module contains bindings to the `libwayland-egl.so` library.
//!
//! This library is used to interface with the OpenGL stack, and creating
//! EGL surfaces from a wayland surface.
//!
//! See WlEglSurface documentation for details.

use std::os::raw::c_void;

use wayland_backend::{client::InvalidId, sys::client::ObjectId};
use wayland_sys::{client::wl_proxy, egl::*, ffi_dispatch};

/// Checks if the wayland-egl lib is available and can be used
///
/// Trying to create an `WlEglSurface` while this function returns
/// `false` will result in a panic.
pub fn is_available() -> bool {
    is_lib_available()
}

unsafe impl Send for WlEglSurface {}
unsafe impl Sync for WlEglSurface {}

/// EGL surface
///
/// This object is a simple wrapper around a `WlSurface` to add the EGL
/// capabilities. Just use the `ptr` method once this object is created
/// to get the window pointer your OpenGL library is needing to initialize the
/// EGL context (you'll most likely need the display ptr as well, that you can
/// get via the `ptr` method of the `Proxy` trait on the `WlDisplay` object).
#[derive(Debug)]
pub struct WlEglSurface {
    ptr: *mut wl_egl_window,
}

impl WlEglSurface {
    /// Create an EGL surface from a wayland surface
    ///
    /// This method will check that the provided `ObjectId` is still alive and from the
    /// correct interface (`wl_surface`).
    pub fn new(surface: ObjectId, width: i32, height: i32) -> Result<WlEglSurface, InvalidId> {
        if surface.interface().name != "wl_surface" {
            return Err(InvalidId);
        }

        let ptr = surface.as_ptr();
        if ptr.is_null() {
            Err(InvalidId)
        } else {
            Ok(unsafe { WlEglSurface::new_from_raw(ptr, width, height) })
        }
    }

    /// Create an EGL surface from a raw pointer to a wayland surface
    ///
    /// # Safety
    ///
    /// The provided pointer must be a valid `wl_surface` pointer from `libwayland-client`.
    pub unsafe fn new_from_raw(surface: *mut wl_proxy, width: i32, height: i32) -> WlEglSurface {
        let ptr = ffi_dispatch!(WAYLAND_EGL_HANDLE, wl_egl_window_create, surface, width, height);
        WlEglSurface { ptr }
    }

    /// Fetch current size of the EGL surface
    pub fn get_size(&self) -> (i32, i32) {
        let mut w = 0i32;
        let mut h = 0i32;
        unsafe {
            ffi_dispatch!(
                WAYLAND_EGL_HANDLE,
                wl_egl_window_get_attached_size,
                self.ptr,
                &mut w as *mut i32,
                &mut h as *mut i32
            );
        }
        (w, h)
    }

    /// Resize the EGL surface
    ///
    /// The two first arguments `(width, height)` are the new size of
    /// the surface, the two others `(dx, dy)` represent the displacement
    /// of the top-left corner of the surface. It allows you to control the
    /// direction of the resizing if necessary.
    pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) {
        unsafe {
            ffi_dispatch!(WAYLAND_EGL_HANDLE, wl_egl_window_resize, self.ptr, width, height, dx, dy)
        }
    }

    /// Raw pointer to the EGL surface
    ///
    /// You'll need this pointer to initialize the EGL context in your
    /// favourite OpenGL lib.
    pub fn ptr(&self) -> *const c_void {
        self.ptr as *const c_void
    }
}

impl Drop for WlEglSurface {
    fn drop(&mut self) {
        unsafe {
            ffi_dispatch!(WAYLAND_EGL_HANDLE, wl_egl_window_destroy, self.ptr);
        }
    }
}
<commit_msg>wayland-egl: remove unsafe Sync impl<commit_after>#![warn(missing_docs, missing_debug_implementations)]

//! EGL utilities
//!
//! This module contains bindings to the `libwayland-egl.so` library.
//!
//! This library is used to interface with the OpenGL stack, and creating
//! EGL surfaces from a wayland surface.
//!
//! See WlEglSurface documentation for details.

use std::os::raw::c_void;

use wayland_backend::{client::InvalidId, sys::client::ObjectId};
use wayland_sys::{client::wl_proxy, egl::*, ffi_dispatch};

/// Checks if the wayland-egl lib is available and can be used
///
/// Trying to create an `WlEglSurface` while this function returns
/// `false` will result in a panic.
pub fn is_available() -> bool {
    is_lib_available()
}

/// EGL surface
///
/// This object is a simple wrapper around a `WlSurface` to add the EGL
/// capabilities. Just use the `ptr` method once this object is created
/// to get the window pointer your OpenGL library is needing to initialize the
/// EGL context (you'll most likely need the display ptr as well, that you can
/// get via the `ptr` method of the `Proxy` trait on the `WlDisplay` object).
#[derive(Debug)]
pub struct WlEglSurface {
    ptr: *mut wl_egl_window,
}

impl WlEglSurface {
    /// Create an EGL surface from a wayland surface
    ///
    /// This method will check that the provided `ObjectId` is still alive and from the
    /// correct interface (`wl_surface`).
    pub fn new(surface: ObjectId, width: i32, height: i32) -> Result<WlEglSurface, InvalidId> {
        if surface.interface().name != "wl_surface" {
            return Err(InvalidId);
        }

        let ptr = surface.as_ptr();
        if ptr.is_null() {
            Err(InvalidId)
        } else {
            // SAFETY: We are sure the pointer is valid and the interface is correct.
            Ok(unsafe { WlEglSurface::new_from_raw(ptr, width, height) })
        }
    }

    /// Create an EGL surface from a raw pointer to a wayland surface.
    ///
    /// # Safety
    ///
    /// The provided pointer must be a valid `wl_surface` pointer from `libwayland-client`.
    pub unsafe fn new_from_raw(surface: *mut wl_proxy, width: i32, height: i32) -> WlEglSurface {
        let ptr = ffi_dispatch!(WAYLAND_EGL_HANDLE, wl_egl_window_create, surface, width, height);
        WlEglSurface { ptr }
    }

    /// Fetch current size of the EGL surface
    pub fn get_size(&self) -> (i32, i32) {
        let mut w = 0i32;
        let mut h = 0i32;
        unsafe {
            ffi_dispatch!(
                WAYLAND_EGL_HANDLE,
                wl_egl_window_get_attached_size,
                self.ptr,
                &mut w as *mut i32,
                &mut h as *mut i32
            );
        }
        (w, h)
    }

    /// Resize the EGL surface
    ///
    /// The two first arguments `(width, height)` are the new size of
    /// the surface, the two others `(dx, dy)` represent the displacement
    /// of the top-left corner of the surface. It allows you to control the
    /// direction of the resizing if necessary.
    pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) {
        unsafe {
            ffi_dispatch!(WAYLAND_EGL_HANDLE, wl_egl_window_resize, self.ptr, width, height, dx, dy)
        }
    }

    /// Raw pointer to the EGL surface
    ///
    /// You'll need this pointer to initialize the EGL context in your
    /// favourite OpenGL lib.
    pub fn ptr(&self) -> *const c_void {
        self.ptr as *const c_void
    }
}

// SAFETY: We own the pointer to the wl_egl_window and can therefore be transferred to another thread.
unsafe impl Send for WlEglSurface {}
// Note that WlEglSurface is !Sync. This is because the pointer performs no internal synchronization.

impl Drop for WlEglSurface {
    fn drop(&mut self) {
        unsafe {
            ffi_dispatch!(WAYLAND_EGL_HANDLE, wl_egl_window_destroy, self.ptr);
        }
    }
}
<|endoftext|>


<commit_before>//! Fully integrated benchmarks for rust-analyzer, which load real cargo
//! projects.
//!
//! The benchmark here is used to debug specific performance regressions. If you
//! notice that, eg, completion is slow in some specific case, you can  modify
//! code here exercise this specific completion, and thus have a fast
//! edit/compile/test cycle.
//!
//! Note that "Rust Analyzer: Run" action does not allow running a single test
//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line"
//! which you can use to paste the command in terminal and add `--release` manually.

use std::sync::Arc;

use ide::Change;
use test_utils::project_root;
use vfs::{AbsPathBuf, VfsPath};

use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};

#[test]
fn benchmark_integrated_highlighting() {
    // Don't run slow benchmark by default
    if true {
        return;
    }

    // Load rust-analyzer itself.
    let workspace_to_load = project_root();
    let file = "./crates/ide_db/src/apply_change.rs";

    let cargo_config = Default::default();
    let load_cargo_config = LoadCargoConfig {
        load_out_dirs_from_check: true,
        wrap_rustc: false,
        with_proc_macro: false,
    };

    let (mut host, vfs, _proc_macro) = {
        let _it = stdx::timeit("workspace loading");
        load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
    };

    let file_id = {
        let file = workspace_to_load.join(file);
        let path = VfsPath::from(AbsPathBuf::assert(file));
        vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
    };

    {
        let _it = stdx::timeit("initial");
        let analysis = host.analysis();
        analysis.highlight_as_html(file_id, false).unwrap();
    }

    profile::init_from("*>100");
    // let _s = profile::heartbeat_span();

    {
        let _it = stdx::timeit("change");
        let mut text = host.analysis().file_text(file_id).unwrap().to_string();
        text.push_str("\npub fn _dummy() {}\n");
        let mut change = Change::new();
        change.change_file(file_id, Some(Arc::new(text)));
        host.apply_change(change);
    }

    {
        let _it = stdx::timeit("after change");
        let _span = profile::cpu_span();
        let analysis = host.analysis();
        analysis.highlight_as_html(file_id, false).unwrap();
    }
}
<commit_msg>More searchable name<commit_after>//! Fully integrated benchmarks for rust-analyzer, which load real cargo
//! projects.
//!
//! The benchmark here is used to debug specific performance regressions. If you
//! notice that, eg, completion is slow in some specific case, you can  modify
//! code here exercise this specific completion, and thus have a fast
//! edit/compile/test cycle.
//!
//! Note that "Rust Analyzer: Run" action does not allow running a single test
//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line"
//! which you can use to paste the command in terminal and add `--release` manually.

use std::sync::Arc;

use ide::Change;
use test_utils::project_root;
use vfs::{AbsPathBuf, VfsPath};

use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};

#[test]
fn integrated_highlighting_benchmark() {
    // Don't run slow benchmark by default
    if true {
        return;
    }

    // Load rust-analyzer itself.
    let workspace_to_load = project_root();
    let file = "./crates/ide_db/src/apply_change.rs";

    let cargo_config = Default::default();
    let load_cargo_config = LoadCargoConfig {
        load_out_dirs_from_check: true,
        wrap_rustc: false,
        with_proc_macro: false,
    };

    let (mut host, vfs, _proc_macro) = {
        let _it = stdx::timeit("workspace loading");
        load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
    };

    let file_id = {
        let file = workspace_to_load.join(file);
        let path = VfsPath::from(AbsPathBuf::assert(file));
        vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
    };

    {
        let _it = stdx::timeit("initial");
        let analysis = host.analysis();
        analysis.highlight_as_html(file_id, false).unwrap();
    }

    profile::init_from("*>100");
    // let _s = profile::heartbeat_span();

    {
        let _it = stdx::timeit("change");
        let mut text = host.analysis().file_text(file_id).unwrap().to_string();
        text.push_str("\npub fn _dummy() {}\n");
        let mut change = Change::new();
        change.change_file(file_id, Some(Arc::new(text)));
        host.apply_change(change);
    }

    {
        let _it = stdx::timeit("after change");
        let _span = profile::cpu_span();
        let analysis = host.analysis();
        analysis.highlight_as_html(file_id, false).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate itertools;

use itertools::{Unfold, Itertools};
use std::str::FromStr;
use std::iter::Rev;
use std::vec::IntoIter;

fn number_to_digits(number: usize) -> Rev<IntoIter<usize>> {
    Unfold::new(number, |n| {
        if *n > 0 {
            let res = *n % 10;
            *n /= 10;
            Some(res)
        } else {
            None
        }
    })
        .collect::<Vec<_>>()
        .into_iter()
        .rev()
}

fn get_next_number<'a, I>(number: I) -> Vec<usize>
    where I: IntoIterator<Item = &'a usize>
{
    number.into_iter()
          .group_by(|&n| *n)
          .flat_map(|(key, group)| {
              number_to_digits(group.len()).into_iter().chain(vec![key].into_iter())
          })
          .collect()
}

fn get_number_after_n_iterations<'a, I>(number: I, n: usize) -> Vec<usize>
    where I: IntoIterator<Item = &'a usize>
{
    (0..n).fold(number.into_iter().cloned().collect(),
                |n, _| get_next_number(&n))
}

fn main() {
    let n = match std::env::args().nth(1).and_then(|arg| usize::from_str(&arg).ok()) {
        Some(arg) => arg,
        None => {
            println!("Call with: day-10 <iterations>");
            return;
        }
    };

    let input = [3, 1, 1, 3, 3, 2, 2, 1, 1, 3];

    let n_iterations = get_number_after_n_iterations(&input, n);
    println!("Length of Number after {} iterations: {}",
             n,
             n_iterations.len());
}

#[test]
fn test_next_number() {
    assert_eq!(get_next_number(&[1]), [1, 1]);
    assert_eq!(get_next_number(&[1, 1]), [2, 1]);
    assert_eq!(get_next_number(&[2, 1]), [1, 2, 1, 1]);
    assert_eq!(get_next_number(&[1, 2, 1, 1]), [1, 1, 1, 2, 2, 1]);
    assert_eq!(get_next_number(&[1, 1, 1, 2, 2, 1]), [3, 1, 2, 2, 1, 1]);

    assert_eq!(get_next_number(&[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]),
               [1, 2, 3]);
}

#[test]
fn test_number_after_n_iterations() {
    assert_eq!(get_number_after_n_iterations(&[1], 0), [1]);
    assert_eq!(get_number_after_n_iterations(&[1], 1), [1, 1]);
    assert_eq!(get_number_after_n_iterations(&[1], 2), [2, 1]);
    assert_eq!(get_number_after_n_iterations(&[1], 3), [1, 2, 1, 1]);
    assert_eq!(get_number_after_n_iterations(&[1], 4), [1, 1, 1, 2, 2, 1]);
    assert_eq!(get_number_after_n_iterations(&[1], 5), [3, 1, 2, 2, 1, 1]);
}
<commit_msg>Get rid of some unnecessary assumptions<commit_after>extern crate itertools;

use itertools::Itertools;
use std::str::FromStr;

fn get_next_number<'a, I>(number: I) -> Vec<u8>
    where I: IntoIterator<Item = &'a u8>
{
    number.into_iter()
          .group_by(|&n| *n)
          .flat_map(|(key, group)| {
              vec![group.len() as u8, key]
          })
          .collect()
}

fn get_number_after_n_iterations<'a, I>(number: I, n: usize) -> Vec<u8>
    where I: IntoIterator<Item = &'a u8>
{
    (0..n).fold(number.into_iter().cloned().collect(),
                |n, _| get_next_number(&n))
}

fn main() {
    let n = match std::env::args().nth(1).and_then(|arg| usize::from_str(&arg).ok()) {
        Some(arg) => arg,
        None => {
            println!("Call with: day-10 <iterations>");
            return;
        }
    };

    let input = [3, 1, 1, 3, 3, 2, 2, 1, 1, 3];

    let n_iterations = get_number_after_n_iterations(&input, n);
    println!("Length of Number after {} iterations: {}",
             n,
             n_iterations.len());
}

#[test]
fn test_next_number() {
    assert_eq!(get_next_number(&[1]), [1, 1]);
    assert_eq!(get_next_number(&[1, 1]), [2, 1]);
    assert_eq!(get_next_number(&[2, 1]), [1, 2, 1, 1]);
    assert_eq!(get_next_number(&[1, 2, 1, 1]), [1, 1, 1, 2, 2, 1]);
    assert_eq!(get_next_number(&[1, 1, 1, 2, 2, 1]), [3, 1, 2, 2, 1, 1]);

    assert_eq!(get_next_number(&[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]),
               [1, 2, 3]);
}

#[test]
fn test_number_after_n_iterations() {
    assert_eq!(get_number_after_n_iterations(&[1], 0), [1]);
    assert_eq!(get_number_after_n_iterations(&[1], 1), [1, 1]);
    assert_eq!(get_number_after_n_iterations(&[1], 2), [2, 1]);
    assert_eq!(get_number_after_n_iterations(&[1], 3), [1, 2, 1, 1]);
    assert_eq!(get_number_after_n_iterations(&[1], 4), [1, 1, 1, 2, 2, 1]);
    assert_eq!(get_number_after_n_iterations(&[1], 5), [3, 1, 2, 2, 1, 1]);
}
<|endoftext|>


<commit_before>use std::process;

fn main() {
    let protoc_bin_path = match protoc_bin_vendored::protoc_bin_path() {
        Ok(p) => p,
        Err(e) => {
            eprintln!("protoc binary not found: {}", e);
            process::exit(1);
        },
    };
    println!("{}", protoc_bin_path.display());
}
<commit_msg>Cargo fmt<commit_after>use std::process;

fn main() {
    let protoc_bin_path = match protoc_bin_vendored::protoc_bin_path() {
        Ok(p) => p,
        Err(e) => {
            eprintln!("protoc binary not found: {}", e);
            process::exit(1);
        }
    };
    println!("{}", protoc_bin_path.display());
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! vagrant/virtualbox metadata fetcher

use std::collections::HashMap;
use std::net::IpAddr;
use std::thread;
use std::time::Duration;

use openssh_keys::PublicKey;
use slog_scope::{info, warn};

use crate::errors::*;
use crate::network;
use crate::providers::MetadataProvider;

#[derive(Clone, Copy, Debug)]
pub struct VagrantVirtualboxProvider;

impl VagrantVirtualboxProvider {
    pub fn new() -> VagrantVirtualboxProvider {
        VagrantVirtualboxProvider
    }

    fn get_ip() -> Result<String> {
        let max_attempts = 30;
        for _ in 0..max_attempts {
            let iface = VagrantVirtualboxProvider::find_eth1();
            if let Some(iface) = iface {
                for a in iface.ips {
                    if let IpAddr::V4(a) = a.ip() {
                        return Ok(format!("{}", a));
                    }
                }
            }
            info!("eth1 not found or is lacking an ipv4 address; waiting 2 seconds");
            thread::sleep(Duration::from_secs(2));
        }
        Err("eth1 was not found!".into())
    }

    fn find_eth1() -> Option<pnet_datalink::NetworkInterface> {
        let mut ifaces = pnet_datalink::interfaces();
        ifaces.retain(|i| i.name == "eth1");
        if !ifaces.is_empty() {
            Some(ifaces[0].clone())
        } else {
            None
        }
    }
}

impl MetadataProvider for VagrantVirtualboxProvider {
    fn attributes(&self) -> Result<HashMap<String, String>> {
        let mut out = HashMap::with_capacity(2);

        let hostname = hostname::get()
            .chain_err(|| "unable to get hostname")?
            .to_string_lossy()
            .into_owned();
        let ip = VagrantVirtualboxProvider::get_ip()?;

        out.insert("VAGRANT_VIRTUALBOX_HOSTNAME".to_string(), hostname);
        out.insert("VAGRANT_VIRTUALBOX_PRIVATE_IPV4".to_string(), ip);

        Ok(out)
    }

    fn hostname(&self) -> Result<Option<String>> {
        let hostname = hostname::get()
            .chain_err(|| "unable to get hostname")?
            .to_string_lossy()
            .into_owned();
        Ok(Some(hostname))
    }

    fn ssh_keys(&self) -> Result<Vec<PublicKey>> {
        Ok(vec![])
    }

    fn networks(&self) -> Result<Vec<network::Interface>> {
        Ok(vec![])
    }

    fn virtual_network_devices(&self) -> Result<Vec<network::VirtualNetDev>> {
        warn!("virtual network devices metadata requested, but not supported on this platform");
        Ok(vec![])
    }

    fn boot_checkin(&self) -> Result<()> {
        warn!("boot check-in requested, but not supported on this platform");
        Ok(())
    }
}
<commit_msg>provider/vagrant: do not loop back local system hostname<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! vagrant/virtualbox metadata fetcher

use std::collections::HashMap;
use std::net::IpAddr;
use std::thread;
use std::time::Duration;

use openssh_keys::PublicKey;
use slog_scope::{info, warn};

use crate::errors::*;
use crate::network;
use crate::providers::MetadataProvider;

#[derive(Clone, Copy, Debug)]
pub struct VagrantVirtualboxProvider;

impl VagrantVirtualboxProvider {
    pub fn new() -> Self {
        Self
    }

    fn get_ip() -> Result<String> {
        let max_attempts = 30;
        for _ in 0..max_attempts {
            if let Some(iface) = Self::find_eth1() {
                for a in iface.ips {
                    if let IpAddr::V4(a) = a.ip() {
                        return Ok(format!("{}", a));
                    }
                }
            }
            info!("eth1 not found or is lacking an ipv4 address; waiting 2 seconds");
            thread::sleep(Duration::from_secs(2));
        }
        Err("eth1 was not found!".into())
    }

    fn find_eth1() -> Option<pnet_datalink::NetworkInterface> {
        pnet_datalink::interfaces()
            .into_iter()
            .find(|i| i.name == "eth1")
    }

    /// Get the hostname from local system settings.
    fn system_hostname() -> Result<String> {
        let hostname = hostname::get()
            .chain_err(|| "unable to get hostname")?
            .to_string_lossy()
            .into_owned();
        Ok(hostname)
    }
}

impl MetadataProvider for VagrantVirtualboxProvider {
    fn attributes(&self) -> Result<HashMap<String, String>> {
        let hostname = Self::system_hostname()?;
        let ip = Self::get_ip()?;

        let attributes = maplit::hashmap! {
            "VAGRANT_VIRTUALBOX_HOSTNAME".to_string() => hostname,
            "VAGRANT_VIRTUALBOX_PRIVATE_IPV4".to_string() => ip,
        };

        Ok(attributes)
    }

    fn hostname(&self) -> Result<Option<String>> {
        Ok(None)
    }

    fn ssh_keys(&self) -> Result<Vec<PublicKey>> {
        Ok(vec![])
    }

    fn networks(&self) -> Result<Vec<network::Interface>> {
        Ok(vec![])
    }

    fn virtual_network_devices(&self) -> Result<Vec<network::VirtualNetDev>> {
        warn!("virtual network devices metadata requested, but not supported on this platform");
        Ok(vec![])
    }

    fn boot_checkin(&self) -> Result<()> {
        warn!("boot check-in requested, but not supported on this platform");
        Ok(())
    }
}
<|endoftext|>


<commit_before><commit_msg>Use From<ipconfig::error::Error> on Windows only<commit_after><|endoftext|>