<commit_before>use clap;

use clap::{AppSettings, Arg, ArgMatches};

use cargo::core::features;
use cargo::{self, CliResult, Config};

use super::commands;
use super::list_commands;
use crate::command_prelude::*;

pub fn main(config: &mut Config) -> CliResult {
    let args = match cli().get_matches_safe() {
        Ok(args) => args,
        Err(e) => {
            if e.kind == clap::ErrorKind::UnrecognizedSubcommand {
                // An unrecognized subcommand might be an external subcommand.
                let cmd = &e.info.as_ref().unwrap()[0].to_owned();
                return super::execute_external_subcommand(config, cmd, &[cmd, "--help"])
                    .map_err(|_| e.into());
            } else {
                return Err(e)?;
            }
        }
    };

    if args.value_of("unstable-features") == Some("help") {
        println!(
            "
Available unstable (nightly-only) flags:

    -Z avoid-dev-deps   -- Avoid installing dev-dependencies if possible
    -Z minimal-versions -- Install minimal dependency versions instead of maximum
    -Z no-index-update  -- Do not update the registry, avoids a network request for benchmarking
    -Z offline          -- Offline mode that does not perform network requests
    -Z unstable-options -- Allow the usage of unstable options such as --registry
    -Z config-profile   -- Read profiles from .cargo/config files
    -Z install-upgrade  -- `cargo install` will upgrade instead of failing

Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
        );
        if !features::nightly_features_allowed() {
            println!(
                "\nUnstable flags are only available on the nightly channel \
                 of Cargo, but this is the `{}` channel.\n\
                 {}",
                features::channel(),
                features::SEE_CHANNELS
            );
        }
        println!(
            "\nSee https://doc.rust-lang.org/nightly/cargo/reference/unstable.html \
             for more information about these flags."
        );
        return Ok(());
    }

    let is_verbose = args.occurrences_of("verbose") > 0;
    if args.is_present("version") {
        let version = get_version_string(is_verbose);
        print!("{}", version);
        return Ok(());
    }

    if let Some(code) = args.value_of("explain") {
        let mut procss = config.load_global_rustc(None)?.process();
        procss.arg("--explain").arg(code).exec()?;
        return Ok(());
    }

    if args.is_present("list") {
        println!("Installed Commands:");
        for command in list_commands(config) {
            match command {
                CommandInfo::BuiltIn { name, about } => {
                    let summary = about.unwrap_or_default();
                    let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
                    println!("    {:<20} {}", name, summary)
                }
                CommandInfo::External { name, path } => {
                    if is_verbose {
                        println!("    {:<20} {}", name, path.display())
                    } else {
                        println!("    {}", name)
                    }
                }
            }
        }
        return Ok(());
    }

    let args = expand_aliases(config, args)?;

    execute_subcommand(config, &args)
}

pub fn get_version_string(is_verbose: bool) -> String {
    let version = cargo::version();
    let mut version_string = version.to_string();
    version_string.push_str("\n");
    if is_verbose {
        version_string.push_str(&format!(
            "release: {}.{}.{}\n",
            version.major, version.minor, version.patch
        ));
        if let Some(ref cfg) = version.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                version_string.push_str(&format!("commit-hash: {}\n", ci.commit_hash));
                version_string.push_str(&format!("commit-date: {}\n", ci.commit_date));
            }
        }
    }
    version_string
}

fn expand_aliases(
    config: &mut Config,
    args: ArgMatches<'static>,
) -> Result<ArgMatches<'static>, CliError> {
    if let (cmd, Some(args)) = args.subcommand() {
        match (
            commands::builtin_exec(cmd),
            super::aliased_command(config, cmd)?,
        ) {
            (Some(_), Some(_)) => {
                // User alias conflicts with a built-in subcommand
                config.shell().warn(format!(
                    "user-defined alias `{}` is ignored, because it is shadowed by a built-in command",
                    cmd,
                ))?;
            }
            (_, Some(mut alias)) => {
                alias.extend(
                    args.values_of("")
                        .unwrap_or_default()
                        .map(|s| s.to_string()),
                );
                let args = cli()
                    .setting(AppSettings::NoBinaryName)
                    .get_matches_from_safe(alias)?;
                return expand_aliases(config, args);
            }
            (_, None) => {}
        }
    };

    Ok(args)
}

fn execute_subcommand(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let (cmd, subcommand_args) = match args.subcommand() {
        (cmd, Some(args)) => (cmd, args),
        _ => {
            cli().print_help()?;
            return Ok(());
        }
    };

    let arg_target_dir = &subcommand_args.value_of_path("target-dir", config);

    config.configure(
        args.occurrences_of("verbose") as u32,
        if args.is_present("quiet") || subcommand_args.is_present("quiet") {
            Some(true)
        } else {
            None
        },
        &args.value_of("color").map(|s| s.to_string()),
        args.is_present("frozen"),
        args.is_present("locked"),
        arg_target_dir,
        &args
            .values_of_lossy("unstable-features")
            .unwrap_or_default(),
    )?;

    if let Some(exec) = commands::builtin_exec(cmd) {
        return exec(config, subcommand_args);
    }

    let mut ext_args: Vec<&str> = vec![cmd];
    ext_args.extend(subcommand_args.values_of("").unwrap_or_default());
    super::execute_external_subcommand(config, cmd, &ext_args)
}

fn cli() -> App {
    App::new("cargo")
        .settings(&[
            AppSettings::UnifiedHelpMessage,
            AppSettings::DeriveDisplayOrder,
            AppSettings::VersionlessSubcommands,
            AppSettings::AllowExternalSubcommands,
        ])
        .about("")
        .template(
            "\
Rust's package manager

USAGE:
    {usage}

OPTIONS:
{unified}

Some common cargo commands are (see all commands with --list):
    build       Compile the current package
    check       Analyze the current package and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this package's and its dependencies' documentation
    new         Create a new cargo package
    init        Create a new cargo package in an existing directory
    run         Run a binary or example of the local package
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this package to the registry
    install     Install a Rust binary. Default location is $HOME/.cargo/bin
    uninstall   Uninstall a Rust binary

See 'cargo help <command>' for more information on a specific command.\n",
        )
        .arg(opt("version", "Print version info and exit").short("V"))
        .arg(opt("list", "List installed commands"))
        .arg(opt("explain", "Run `rustc --explain CODE`").value_name("CODE"))
        .arg(
            opt(
                "verbose",
                "Use verbose output (-vv very verbose/build.rs output)",
            )
            .short("v")
            .multiple(true)
            .global(true),
        )
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg(
            opt("color", "Coloring: auto, always, never")
                .value_name("WHEN")
                .global(true),
        )
        .arg(opt("frozen", "Require Cargo.lock and cache are up to date").global(true))
        .arg(opt("locked", "Require Cargo.lock is up to date").global(true))
        .arg(
            Arg::with_name("unstable-features")
                .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
                .short("Z")
                .value_name("FLAG")
                .multiple(true)
                .number_of_values(1)
                .global(true),
        )
        .subcommands(commands::builtin())
}
<commit_msg>refactor: Delete about<commit_after>use clap;

use clap::{AppSettings, Arg, ArgMatches};

use cargo::core::features;
use cargo::{self, CliResult, Config};

use super::commands;
use super::list_commands;
use crate::command_prelude::*;

pub fn main(config: &mut Config) -> CliResult {
    let args = match cli().get_matches_safe() {
        Ok(args) => args,
        Err(e) => {
            if e.kind == clap::ErrorKind::UnrecognizedSubcommand {
                // An unrecognized subcommand might be an external subcommand.
                let cmd = &e.info.as_ref().unwrap()[0].to_owned();
                return super::execute_external_subcommand(config, cmd, &[cmd, "--help"])
                    .map_err(|_| e.into());
            } else {
                return Err(e)?;
            }
        }
    };

    if args.value_of("unstable-features") == Some("help") {
        println!(
            "
Available unstable (nightly-only) flags:

    -Z avoid-dev-deps   -- Avoid installing dev-dependencies if possible
    -Z minimal-versions -- Install minimal dependency versions instead of maximum
    -Z no-index-update  -- Do not update the registry, avoids a network request for benchmarking
    -Z offline          -- Offline mode that does not perform network requests
    -Z unstable-options -- Allow the usage of unstable options such as --registry
    -Z config-profile   -- Read profiles from .cargo/config files
    -Z install-upgrade  -- `cargo install` will upgrade instead of failing

Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
        );
        if !features::nightly_features_allowed() {
            println!(
                "\nUnstable flags are only available on the nightly channel \
                 of Cargo, but this is the `{}` channel.\n\
                 {}",
                features::channel(),
                features::SEE_CHANNELS
            );
        }
        println!(
            "\nSee https://doc.rust-lang.org/nightly/cargo/reference/unstable.html \
             for more information about these flags."
        );
        return Ok(());
    }

    let is_verbose = args.occurrences_of("verbose") > 0;
    if args.is_present("version") {
        let version = get_version_string(is_verbose);
        print!("{}", version);
        return Ok(());
    }

    if let Some(code) = args.value_of("explain") {
        let mut procss = config.load_global_rustc(None)?.process();
        procss.arg("--explain").arg(code).exec()?;
        return Ok(());
    }

    if args.is_present("list") {
        println!("Installed Commands:");
        for command in list_commands(config) {
            match command {
                CommandInfo::BuiltIn { name, about } => {
                    let summary = about.unwrap_or_default();
                    let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
                    println!("    {:<20} {}", name, summary)
                }
                CommandInfo::External { name, path } => {
                    if is_verbose {
                        println!("    {:<20} {}", name, path.display())
                    } else {
                        println!("    {}", name)
                    }
                }
            }
        }
        return Ok(());
    }

    let args = expand_aliases(config, args)?;

    execute_subcommand(config, &args)
}

pub fn get_version_string(is_verbose: bool) -> String {
    let version = cargo::version();
    let mut version_string = version.to_string();
    version_string.push_str("\n");
    if is_verbose {
        version_string.push_str(&format!(
            "release: {}.{}.{}\n",
            version.major, version.minor, version.patch
        ));
        if let Some(ref cfg) = version.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                version_string.push_str(&format!("commit-hash: {}\n", ci.commit_hash));
                version_string.push_str(&format!("commit-date: {}\n", ci.commit_date));
            }
        }
    }
    version_string
}

fn expand_aliases(
    config: &mut Config,
    args: ArgMatches<'static>,
) -> Result<ArgMatches<'static>, CliError> {
    if let (cmd, Some(args)) = args.subcommand() {
        match (
            commands::builtin_exec(cmd),
            super::aliased_command(config, cmd)?,
        ) {
            (Some(_), Some(_)) => {
                // User alias conflicts with a built-in subcommand
                config.shell().warn(format!(
                    "user-defined alias `{}` is ignored, because it is shadowed by a built-in command",
                    cmd,
                ))?;
            }
            (_, Some(mut alias)) => {
                alias.extend(
                    args.values_of("")
                        .unwrap_or_default()
                        .map(|s| s.to_string()),
                );
                let args = cli()
                    .setting(AppSettings::NoBinaryName)
                    .get_matches_from_safe(alias)?;
                return expand_aliases(config, args);
            }
            (_, None) => {}
        }
    };

    Ok(args)
}

fn execute_subcommand(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let (cmd, subcommand_args) = match args.subcommand() {
        (cmd, Some(args)) => (cmd, args),
        _ => {
            cli().print_help()?;
            return Ok(());
        }
    };

    let arg_target_dir = &subcommand_args.value_of_path("target-dir", config);

    config.configure(
        args.occurrences_of("verbose") as u32,
        if args.is_present("quiet") || subcommand_args.is_present("quiet") {
            Some(true)
        } else {
            None
        },
        &args.value_of("color").map(|s| s.to_string()),
        args.is_present("frozen"),
        args.is_present("locked"),
        arg_target_dir,
        &args
            .values_of_lossy("unstable-features")
            .unwrap_or_default(),
    )?;

    if let Some(exec) = commands::builtin_exec(cmd) {
        return exec(config, subcommand_args);
    }

    let mut ext_args: Vec<&str> = vec![cmd];
    ext_args.extend(subcommand_args.values_of("").unwrap_or_default());
    super::execute_external_subcommand(config, cmd, &ext_args)
}

fn cli() -> App {
    App::new("cargo")
        .settings(&[
            AppSettings::UnifiedHelpMessage,
            AppSettings::DeriveDisplayOrder,
            AppSettings::VersionlessSubcommands,
            AppSettings::AllowExternalSubcommands,
        ])
        .template(
            "\
Rust's package manager

USAGE:
    {usage}

OPTIONS:
{unified}

Some common cargo commands are (see all commands with --list):
    build       Compile the current package
    check       Analyze the current package and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this package's and its dependencies' documentation
    new         Create a new cargo package
    init        Create a new cargo package in an existing directory
    run         Run a binary or example of the local package
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this package to the registry
    install     Install a Rust binary. Default location is $HOME/.cargo/bin
    uninstall   Uninstall a Rust binary

See 'cargo help <command>' for more information on a specific command.\n",
        )
        .arg(opt("version", "Print version info and exit").short("V"))
        .arg(opt("list", "List installed commands"))
        .arg(opt("explain", "Run `rustc --explain CODE`").value_name("CODE"))
        .arg(
            opt(
                "verbose",
                "Use verbose output (-vv very verbose/build.rs output)",
            )
            .short("v")
            .multiple(true)
            .global(true),
        )
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg(
            opt("color", "Coloring: auto, always, never")
                .value_name("WHEN")
                .global(true),
        )
        .arg(opt("frozen", "Require Cargo.lock and cache are up to date").global(true))
        .arg(opt("locked", "Require Cargo.lock is up to date").global(true))
        .arg(
            Arg::with_name("unstable-features")
                .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
                .short("Z")
                .value_name("FLAG")
                .multiple(true)
                .number_of_values(1)
                .global(true),
        )
        .subcommands(commands::builtin())
}
<|endoftext|>


<commit_before>// Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
// Copyright (c) 2017-2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use super::Muxer;
use ivf::*;
use rav1e::prelude::*;
use std::fs;
use std::fs::File;
use std::io;
use std::io::Write;

use crate::error::*;

pub struct IvfMuxer {
  output: Box<dyn Write>,
}

impl Muxer for IvfMuxer {
  fn write_header(
    &mut self, width: usize, height: usize, framerate_num: usize,
    framerate_den: usize,
  ) {
    write_ivf_header(
      &mut self.output,
      width,
      height,
      framerate_num,
      framerate_den,
    );
  }

  fn write_frame(&mut self, pts: u64, data: &[u8], _frame_type: FrameType) {
    write_ivf_frame(&mut self.output, pts, data);
  }

  fn flush(&mut self) -> io::Result<()> {
    self.output.flush()
  }
}

impl IvfMuxer {
  pub fn check_file(path: &str) -> Result<(), CliError> {
    if fs::metadata(path).is_ok() {
      eprint!("File '{}' already exists. Overwrite ? [y/N] ", path);
      io::stdout().flush().unwrap();

      let mut option_input = String::new();
      io::stdin()
        .read_line(&mut option_input)
        .expect("Failed to read option.");

      match option_input.as_str().trim() {
        "y" | "Y" => return Ok(()),
        _ => return Err(CliError::new("Not overwriting, exiting.")),
      };
    }
    Ok(())
  }

  pub fn open(path: &str) -> Result<Box<dyn Muxer>, CliError> {
    let ivf = IvfMuxer {
      output: match path {
        "-" => Box::new(std::io::stdout()),
        f => Box::new(
          File::create(&f)
            .map_err(|e| e.context("Cannot open output file"))?,
        ),
      },
    };
    Ok(Box::new(ivf))
  }
}
<commit_msg>Check for path existence only when it is a normal file<commit_after>// Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
// Copyright (c) 2017-2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use super::Muxer;
use ivf::*;
use rav1e::prelude::*;
use std::fs;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::Path;

use crate::error::*;

pub struct IvfMuxer {
  output: Box<dyn Write>,
}

impl Muxer for IvfMuxer {
  fn write_header(
    &mut self, width: usize, height: usize, framerate_num: usize,
    framerate_den: usize,
  ) {
    write_ivf_header(
      &mut self.output,
      width,
      height,
      framerate_num,
      framerate_den,
    );
  }

  fn write_frame(&mut self, pts: u64, data: &[u8], _frame_type: FrameType) {
    write_ivf_frame(&mut self.output, pts, data);
  }

  fn flush(&mut self) -> io::Result<()> {
    self.output.flush()
  }
}

cfg_if::cfg_if! {
  if #[cfg(unix)] {
    use std::os::unix::fs::*;
    fn is_file<P: AsRef<Path>>(path: P) -> bool {
      fs::metadata(path).map(|meta| {
        !meta.file_type().is_char_device() && !meta.file_type().is_socket()
      }).unwrap_or(false)
    }
  } else {
    fn is_file<P: AsRef<Path>>(path: P) -> bool {
      fs::metadata(path).is_ok()
    }
  }
}

impl IvfMuxer {
  pub fn check_file(path: &str) -> Result<(), CliError> {
    if is_file(path) {
      eprint!("File '{}' already exists. Overwrite ? [y/N] ", path);
      io::stdout().flush().unwrap();

      let mut option_input = String::new();
      io::stdin()
        .read_line(&mut option_input)
        .expect("Failed to read option.");

      match option_input.as_str().trim() {
        "y" | "Y" => return Ok(()),
        _ => return Err(CliError::new("Not overwriting, exiting.")),
      };
    }
    Ok(())
  }

  pub fn open(path: &str) -> Result<Box<dyn Muxer>, CliError> {
    let ivf = IvfMuxer {
      output: match path {
        "-" => Box::new(std::io::stdout()),
        f => Box::new(
          File::create(&f)
            .map_err(|e| e.context("Cannot open output file"))?,
        ),
      },
    };
    Ok(Box::new(ivf))
  }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
// Copyright © 2014-2018 Miguel Peláez <kernelfreeze@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use core::resource_manager::resource::Resource;
use core::resource_manager::resource_type::ResourceType;
use core::resource_manager::ResourceManager;

use core::settings::Settings;

use std::sync::Arc;

#[test]
fn resource_path_litecraft() {
    let resource = Resource::litecraft("logo", ResourceType::Texture);

    assert_eq!(
        resource.folder("resources"),
        "resources/litecraft/textures/logo.png"
    );
}

#[test]
fn resource_path_minecraft() {
    let resource = Resource::minecraft_path("creeper", "entity", ResourceType::Texture);

    assert_eq!(
        resource.folder("assets"),
        "assets/minecraft/textures/entity/creeper.png"
    );
}

#[test]
#[should_panic]
fn resource_not_found() {
    let settings = Arc::new(Settings::new());
    let resource = Resource::litecraft("panic", ResourceType::Text).load(settings);
}

#[test]
#[should_panic]
fn resource_binary_not_found() {
    let settings = Arc::new(Settings::new());
    let resource = Resource::litecraft("panic", ResourceType::Text).load_binary(settings);
}
<commit_msg>Fixing tests<commit_after>// The MIT License (MIT)
// Copyright © 2014-2018 Miguel Peláez <kernelfreeze@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use core::resource_manager::resource::Resource;
use core::resource_manager::resource_type::ResourceType;

use core::settings::Settings;

#[test]
fn resource_path_litecraft() {
    let resource = Resource::litecraft("logo", ResourceType::Texture);

    assert_eq!(
        resource.folder("resources"),
        "resources/litecraft/textures/logo.png"
    );
}

#[test]
fn resource_path_minecraft() {
    let resource = Resource::minecraft_path("creeper", "entity", ResourceType::Texture);

    assert_eq!(
        resource.folder("assets"),
        "assets/minecraft/textures/entity/creeper.png"
    );
}

#[test]
#[should_panic]
fn resource_not_found() {
    let settings = Settings::new();
    let resource = Resource::litecraft("panic", ResourceType::Text).load(&settings);
}

#[test]
#[should_panic]
fn resource_binary_not_found() {
    let settings = Settings::new();
    let resource = Resource::litecraft("panic", ResourceType::Text).load_binary(&settings);
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate log;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimir;
extern crate rs_es;

use std::collections::HashSet;
use std::collections::HashMap;
use mimirsbrunn::rubber::Rubber;
use mimirsbrunn::objects::{Polygon, MultiPolygon};

pub type AdminsVec = Vec<mimir::Admin>;
pub type StreetsVec = Vec<mimir::Street>;
pub type ParsedPbf = osmpbfreader::OsmPbfReader<std::fs::File>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level>...

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

#[derive(Debug)]
struct AdminMatcher {
    admin_levels: HashSet<u32>,
}
impl AdminMatcher {
    pub fn new(levels: HashSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("boundary").map_or(false, |v| v == "administrative") &&
                rel.tags.get("admin_level").map_or(false, |lvl| {
                    self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                })
            }
            _ => false,
        }
    }
}

struct BoundaryPart {
    nodes: Vec<osmpbfreader::Node>,
}

impl BoundaryPart {
    pub fn new(nodes: Vec<osmpbfreader::Node>) -> BoundaryPart {
        BoundaryPart { nodes: nodes }
    }
    pub fn first(&self) -> i64 {
        self.nodes.first().unwrap().id
    }
    pub fn last(&self) -> i64 {
        self.nodes.last().unwrap().id
    }
}

fn get_nodes(way: &osmpbfreader::Way,
             objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
             -> Vec<osmpbfreader::Node> {
    way.nodes
       .iter()
       .filter_map(|node_id| objects.get(&osmpbfreader::OsmId::Node(*node_id)))
       .filter_map(|node_obj| if let &osmpbfreader::OsmObj::Node(ref node) = node_obj {
           Some(node.clone())
       } else {
           None
       })
       .collect()
}

fn build_boundary(relation: &osmpbfreader::Relation,
                  objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
                  -> Option<MultiPolygon> {
    let mut boundary_parts: Vec<BoundaryPart> =
        relation.refs
                .iter()
                .filter(|rf| rf.role == "outer" || rf.role == "" || rf.role == "enclave")
                .filter_map(|refe| {
                    objects.get(&refe.member).or_else(|| {
                        warn!("missing element for relation {}", relation.id);
                        None
                    })
                })
                .filter_map(|way_obj| if let &osmpbfreader::OsmObj::Way(ref way) = way_obj {
                    Some(way)
                } else {
                    None
                })
                .map(|way| get_nodes(&way, objects))
                .filter(|nodes| nodes.len() > 1)
                .map(|nodes| BoundaryPart::new(nodes))
                .collect();
    let mut multipoly = MultiPolygon { polygons: Vec::new() };
    // we want to try build a polygon for a least each way
    while !boundary_parts.is_empty() {
        let mut current = -1;
        let mut first = 0;
        let mut nb_try = 0;

        let mut outer: Vec<osmpbfreader::Node> = Vec::new();
        // we try to close the polygon, if we can't we want to at least have tried one time per
        // way. We could improve that latter by trying to attach the way to both side of the
        // polygon
        let max_try = boundary_parts.len();
        while current != first && nb_try < max_try {
            let mut i = 0;
            while i < boundary_parts.len() {
                if outer.is_empty() {
                    // our polygon is empty, we initialise it with the current way
                    first = boundary_parts[i].first();
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    // this way has been used, we remove it from the pool
                    boundary_parts.remove(i);
                    continue;
                }
                if current == boundary_parts[i].first() {
                    // the start of current way touch the polygon, we add it and remove it from the
                    // pool
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else if current == boundary_parts[i].last() {
                    // the end of the current way touch the polygon, we reverse the way and add it
                    current = boundary_parts[i].first();
                    boundary_parts[i].nodes.reverse();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else {
                    i += 1;
                    // didnt do anything, we want to explore the next way, if we had do something we
                    // will have removed the current way and there will be no need to increment
                }
                if current == first {
                    // our polygon is closed, we create it and add it to the multipolygon
                    let polygon = Polygon::new(outer.iter()
                                                    .map(|n| {
                                                        mimir::Coord {
                                                            lat: n.lat,
                                                            lon: n.lon,
                                                        }
                                                    })
                                                    .collect());
                    multipoly.polygons.push(polygon);
                    break;
                }
            }
            nb_try += 1;
        }
    }
    debug!("polygon for relation {};{}", relation.id, multipoly.to_wkt());
    if multipoly.polygons.is_empty() {
        None
    } else {
        Some(multipoly)
    }
}

fn parse_osm_pbf(path: &String) -> ParsedPbf {
    let path = std::path::Path::new(&path);
    osmpbfreader::OsmPbfReader::new(std::fs::File::open(&path).unwrap())
}

fn administrative_regions(pbf: &mut ParsedPbf, levels: HashSet<u32>) -> AdminsVec {
    let mut administrative_regions = AdminsVec::new();
    let matcher = AdminMatcher::new(levels);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_admin(o)).unwrap();
    // load administratives regions
    for (_, obj) in &objects {
        if !matcher.is_admin(&obj) {
            continue;
        }
        if let &osmpbfreader::OsmObj::Relation(ref relation) = obj {
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            // admininstrative region without coordinates
            let coord_centre = relation.refs
                                       .iter()
                                       .find(|rf| rf.role == "admin_centre")
                                       .and_then(|r| {
                                           objects.get(&r.member).and_then(|value| {
                                               match value {
                                                   &osmpbfreader::OsmObj::Node(ref node) => {
                                                       Some(mimir::Coord {
                                                           lat: node.lat,
                                                           lon: node.lon,
                                                       })
                                                   }
                                                   _ => None,
                                               }
                                           })
                                       });

            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val.trim_left_matches('0')),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let boundary = build_boundary(&relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: coord_centre,
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    return administrative_regions;
}

fn streets(pbf: &mut ParsedPbf) -> StreetsVec {

    let is_valid_street = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Way(ref way) => {
                way.tags.get("highway").map_or(false, |x: &String| !x.is_empty()) &&
                way.tags.get("name").map_or(false, |x: &String| !x.is_empty())
            }
            _ => false,
        }
    };

    let is_associated_street_relation = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("type").map_or(false, |v| v == "associatedStreet")
            }
            _ => false,
        }
    };

    let mut street_map = osmpbfreader::get_objs_and_deps(pbf, is_valid_street).unwrap();
    let relation_map = osmpbfreader::get_objs_and_deps(pbf, is_associated_street_relation).unwrap();

    for (_, rel_obj) in &relation_map {
        if let &osmpbfreader::OsmObj::Relation(ref rel) = rel_obj {
            let mut found = false;
            for ref_obj in &rel.refs {
                if let &osmpbfreader::OsmId::Way(_) = &ref_obj.member {
                    if !found {
                        found = true;
                        continue;
                    };
                    street_map.remove(&ref_obj.member);
                };
            }
        };
    }

    street_map.iter()
              .filter_map(|(osm_id, obj)| {
                  if let &osmpbfreader::OsmObj::Way(ref way) = obj {
                      if let &osmpbfreader::OsmId::Way(ref way_id) = osm_id {
                          way.tags.get("name").and_then(|way_name| {
                              Some(mimirsbrunn::Street {
                                  id: way_id.to_string(),
                                  street_name: way_name.to_string(),
                                  name: way_name.to_string(),
                                  weight: 1,
                                  administrative_region: None,
                              })
                          })
                      } else {
                          None
                      }
                  } else {
                      None
                  }
              })
              .collect()

}

fn index_osm(es_cnx_string: &str, admins: &AdminsVec, streets: &StreetsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    rubber.create_index();
    match rubber.clean_db_by_doc_type(&["admin", "street"]) {
        Err(e) => panic!("failed to clean data by document type: {}", e),
        Ok(nb) => info!("clean data by document type : {}", nb),
    }
    info!("Add data in elasticsearch db.");
    match rubber.bulk_index(admins.iter()) {
        Err(e) => panic!("failed to index admins of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed adminstrative regions: {}", nb),
    }

    match rubber.bulk_index(streets.iter()) {
        Err(e) => panic!("failed to index streets of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed streets: {}", nb),
    }
}

fn main() {
    mimir::logger_init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());

    let levels = args.flag_level.iter().cloned().collect();
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);
    let admins = administrative_regions(&mut parsed_pbf, levels);
    let streets = streets(&mut parsed_pbf);
    index_osm(&args.flag_connection_string, &admins, &streets);
}
<commit_msg>add comment<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate log;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimir;
extern crate rs_es;

use std::collections::HashSet;
use std::collections::HashMap;
use mimirsbrunn::rubber::Rubber;
use mimirsbrunn::objects::{Polygon, MultiPolygon};

pub type AdminsVec = Vec<mimir::Admin>;
pub type StreetsVec = Vec<mimir::Street>;
pub type ParsedPbf = osmpbfreader::OsmPbfReader<std::fs::File>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level>...

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

#[derive(Debug)]
struct AdminMatcher {
    admin_levels: HashSet<u32>,
}
impl AdminMatcher {
    pub fn new(levels: HashSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("boundary").map_or(false, |v| v == "administrative") &&
                rel.tags.get("admin_level").map_or(false, |lvl| {
                    self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                })
            }
            _ => false,
        }
    }
}

struct BoundaryPart {
    nodes: Vec<osmpbfreader::Node>,
}

impl BoundaryPart {
    pub fn new(nodes: Vec<osmpbfreader::Node>) -> BoundaryPart {
        BoundaryPart { nodes: nodes }
    }
    pub fn first(&self) -> i64 {
        self.nodes.first().unwrap().id
    }
    pub fn last(&self) -> i64 {
        self.nodes.last().unwrap().id
    }
}

fn get_nodes(way: &osmpbfreader::Way,
             objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
             -> Vec<osmpbfreader::Node> {
    way.nodes
       .iter()
       .filter_map(|node_id| objects.get(&osmpbfreader::OsmId::Node(*node_id)))
       .filter_map(|node_obj| if let &osmpbfreader::OsmObj::Node(ref node) = node_obj {
           Some(node.clone())
       } else {
           None
       })
       .collect()
}

fn build_boundary(relation: &osmpbfreader::Relation,
                  objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
                  -> Option<MultiPolygon> {
    let mut boundary_parts: Vec<BoundaryPart> =
        relation.refs
                .iter()
                .filter(|rf| rf.role == "outer" || rf.role == "" || rf.role == "enclave")
                .filter_map(|refe| {
                    objects.get(&refe.member).or_else(|| {
                        warn!("missing element for relation {}", relation.id);
                        None
                    })
                })
                .filter_map(|way_obj| if let &osmpbfreader::OsmObj::Way(ref way) = way_obj {
                    Some(way)
                } else {
                    None
                })
                .map(|way| get_nodes(&way, objects))
                .filter(|nodes| nodes.len() > 1)
                .map(|nodes| BoundaryPart::new(nodes))
                .collect();
    let mut multipoly = MultiPolygon { polygons: Vec::new() };
    // we want to try build a polygon for a least each way
    while !boundary_parts.is_empty() {
        let mut current = -1;
        let mut first = 0;
        let mut nb_try = 0;

        let mut outer: Vec<osmpbfreader::Node> = Vec::new();
        // we try to close the polygon, if we can't we want to at least have tried one time per
        // way. We could improve that latter by trying to attach the way to both side of the
        // polygon
        let max_try = boundary_parts.len();
        while current != first && nb_try < max_try {
            let mut i = 0;
            while i < boundary_parts.len() {
                if outer.is_empty() {
                    // our polygon is empty, we initialise it with the current way
                    first = boundary_parts[i].first();
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    // this way has been used, we remove it from the pool
                    boundary_parts.remove(i);
                    continue;
                }
                if current == boundary_parts[i].first() {
                    // the start of current way touch the polygon, we add it and remove it from the
                    // pool
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else if current == boundary_parts[i].last() {
                    // the end of the current way touch the polygon, we reverse the way and add it
                    current = boundary_parts[i].first();
                    boundary_parts[i].nodes.reverse();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else {
                    i += 1;
                    // didnt do anything, we want to explore the next way, if we had do something we
                    // will have removed the current way and there will be no need to increment
                }
                if current == first {
                    // our polygon is closed, we create it and add it to the multipolygon
                    let polygon = Polygon::new(outer.iter()
                                                    .map(|n| {
                                                        mimir::Coord {
                                                            lat: n.lat,
                                                            lon: n.lon,
                                                        }
                                                    })
                                                    .collect());
                    multipoly.polygons.push(polygon);
                    break;
                }
            }
            nb_try += 1;
        }
    }
    debug!("polygon for relation {};{}", relation.id, multipoly.to_wkt());
    if multipoly.polygons.is_empty() {
        None
    } else {
        Some(multipoly)
    }
}

fn parse_osm_pbf(path: &String) -> ParsedPbf {
    let path = std::path::Path::new(&path);
    osmpbfreader::OsmPbfReader::new(std::fs::File::open(&path).unwrap())
}

fn administrative_regions(pbf: &mut ParsedPbf, levels: HashSet<u32>) -> AdminsVec {
    let mut administrative_regions = AdminsVec::new();
    let matcher = AdminMatcher::new(levels);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_admin(o)).unwrap();
    // load administratives regions
    for (_, obj) in &objects {
        if !matcher.is_admin(&obj) {
            continue;
        }
        if let &osmpbfreader::OsmObj::Relation(ref relation) = obj {
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            // admininstrative region without coordinates
            let coord_centre = relation.refs
                                       .iter()
                                       .find(|rf| rf.role == "admin_centre")
                                       .and_then(|r| {
                                           objects.get(&r.member).and_then(|value| {
                                               match value {
                                                   &osmpbfreader::OsmObj::Node(ref node) => {
                                                       Some(mimir::Coord {
                                                           lat: node.lat,
                                                           lon: node.lon,
                                                       })
                                                   }
                                                   _ => None,
                                               }
                                           })
                                       });

            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val.trim_left_matches('0')),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let boundary = build_boundary(&relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: coord_centre,
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    return administrative_regions;
}

fn streets(pbf: &mut ParsedPbf) -> StreetsVec {

    let is_valid_street = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Way(ref way) => {
                way.tags.get("highway").map_or(false, |x: &String| !x.is_empty()) &&
                way.tags.get("name").map_or(false, |x: &String| !x.is_empty())
            }
            _ => false,
        }
    };

    let is_associated_street_relation = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("type").map_or(false, |v| v == "associatedStreet")
            }
            _ => false,
        }
    };

    let mut street_map = osmpbfreader::get_objs_and_deps(pbf, is_valid_street).unwrap();
    let relation_map = osmpbfreader::get_objs_and_deps(pbf, is_associated_street_relation).unwrap();

    // Sometimes, streets can be devided into several "way"s that still have the same street name.
    // The reason why a street is devided may be that a part of the street become a bridge/tunne/etc.
    // In this case, a "relation" tagged with (type = associatedStreet) is used to group all these "way"s.
    // In order not to have doublons in autocompleion, we should keep only one "way" in the relation
    // and remove all the rest way whose street name is the same.
    for (_, rel_obj) in &relation_map {
        if let &osmpbfreader::OsmObj::Relation(ref rel) = rel_obj {
            let mut found = false;
            for ref_obj in &rel.refs {
                if let &osmpbfreader::OsmId::Way(_) = &ref_obj.member {
                    if !found {
                        found = true;
                        continue;
                    };
                    street_map.remove(&ref_obj.member);
                };
            }
        };
    }

    street_map.iter()
              .filter_map(|(osm_id, obj)| {
                  if let &osmpbfreader::OsmObj::Way(ref way) = obj {
                      if let &osmpbfreader::OsmId::Way(ref way_id) = osm_id {
                          way.tags.get("name").and_then(|way_name| {
                              Some(mimirsbrunn::Street {
                                  id: way_id.to_string(),
                                  street_name: way_name.to_string(),
                                  name: way_name.to_string(),
                                  weight: 1,
                                  administrative_region: None,
                              })
                          })
                      } else {
                          None
                      }
                  } else {
                      None
                  }
              })
              .collect()

}

fn index_osm(es_cnx_string: &str, admins: &AdminsVec, streets: &StreetsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    rubber.create_index();
    match rubber.clean_db_by_doc_type(&["admin", "street"]) {
        Err(e) => panic!("failed to clean data by document type: {}", e),
        Ok(nb) => info!("clean data by document type : {}", nb),
    }
    info!("Add data in elasticsearch db.");
    match rubber.bulk_index(admins.iter()) {
        Err(e) => panic!("failed to index admins of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed adminstrative regions: {}", nb),
    }

    match rubber.bulk_index(streets.iter()) {
        Err(e) => panic!("failed to index streets of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed streets: {}", nb),
    }
}

fn main() {
    mimir::logger_init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());

    let levels = args.flag_level.iter().cloned().collect();
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);
    let admins = administrative_regions(&mut parsed_pbf, levels);
    let streets = streets(&mut parsed_pbf);
    index_osm(&args.flag_connection_string, &admins, &streets);
}
<|endoftext|>


<commit_before>// check-pass

#[repr(C,u8)]
enum Foo {
    A,
    B,
}

#[repr(C)]
#[repr(u8)]
enum Bar {
    A,
    B,
}

fn main() {}
<commit_msg>Add warning annotations for issue-47094 test<commit_after>// check-pass

#[repr(C,u8)] //~ WARNING conflicting representation hints
enum Foo {
    A,
    B,
}

#[repr(C)] //~ WARNING conflicting representation hints
#[repr(u8)]
enum Bar {
    A,
    B,
}

fn main() {}
<|endoftext|>


<commit_before>use std::old_io::{File, Open, ReadWrite};
use std::old_io::IoResult;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;

pub struct Buffer {
    data: GapBuffer,
    file: Option<File>,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```rust
    ///
    /// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
    /// assert_eq!(buffer.data(), "it works!\n");
    pub fn data(&self) -> String {
        self.data.to_string()
    }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
///
/// # Examples
///
/// ```rust
///
/// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, ReadWrite) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    let data = gap_buffer::new(data);

    // Create a new buffer using the loaded data, file, and other defaults.
    Ok(Buffer{ data: data, file: Some(file) })
}
<commit_msg>Remove language specification from documentation. Close code blocks.<commit_after>use std::old_io::{File, Open, ReadWrite};
use std::old_io::IoResult;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;

pub struct Buffer {
    data: GapBuffer,
    file: Option<File>,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
    /// assert_eq!(buffer.data(), "it works!\n");
    /// ```
    pub fn data(&self) -> String {
        self.data.to_string()
    }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// ```
pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, ReadWrite) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    let data = gap_buffer::new(data);

    // Create a new buffer using the loaded data, file, and other defaults.
    Ok(Buffer{ data: data, file: Some(file) })
}
<|endoftext|>


<commit_before>// Copyright 2017 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fs;
use std::io::{Error, ErrorKind, Read, Result};
use std::sync::Mutex;

use prometheus::core::{Collector, Desc};
use prometheus::{self, proto, CounterVec, Opts};

use libc::{self, pid_t};

/// monitor current process's threads.
pub fn monitor_threads<S: Into<String>>(namespace: S) -> Result<()> {
    let pid = unsafe { libc::getpid() };
    let tc = ThreadsColletcor::new(pid, namespace);
    prometheus::register(Box::new(tc)).map_err(|e| to_err(format!("{:?}", e)))?;

    Ok(())
}

struct ThreadsColletcor {
    pid: pid_t,
    descs: Vec<Desc>,
    cpu_totals: Mutex<CounterVec>,
}

impl ThreadsColletcor {
    fn new<S: Into<String>>(pid: pid_t, namespace: S) -> ThreadsColletcor {
        let cpu_totals = CounterVec::new(
            Opts::new(
                "thread_cpu_seconds_total",
                "Total user and system CPU time spent in \
                 seconds by threads.",
            ).namespace(namespace),
            &["name", "tid"],
        ).unwrap();
        let descs = cpu_totals.desc().into_iter().cloned().collect();

        ThreadsColletcor {
            pid,
            descs,
            cpu_totals: Mutex::new(cpu_totals),
        }
    }
}

impl Collector for ThreadsColletcor {
    fn desc(&self) -> Vec<&Desc> {
        self.descs.iter().collect()
    }

    fn collect(&self) -> Vec<proto::MetricFamily> {
        let cpu_totals = self.cpu_totals.lock().unwrap();
        let tids = get_thread_ids(self.pid).unwrap();
        for tid in tids {
            if let Ok((tname, utime, stime)) = get_thread_stat(self.pid, tid) {
                let total = (utime + stime) / *CLK_TCK;
                let cpu_total = cpu_totals
                    .get_metric_with_label_values(&[&tname, &format!("{}", tid)])
                    .unwrap();
                let past = cpu_total.get();
                let delta = total - past;
                if delta > 0.0 {
                    cpu_total.inc_by(delta);
                }
            }
        }

        cpu_totals.collect()
    }
}

fn get_thread_ids(pid: pid_t) -> Result<Vec<pid_t>> {
    let mut tids = Vec::new();
    let dirs = fs::read_dir(format!("/proc/{}/task", pid))?;
    for task in dirs {
        let file_name = match task {
            Ok(t) => t.file_name(),
            Err(e) => {
                error!("fail to read task of {}, error {:?}", pid, e);
                continue;
            }
        };

        let tid = match file_name.to_str() {
            Some(tid) => match tid.parse() {
                Ok(tid) => tid,
                Err(e) => {
                    error!("fail to read task of {}, error {:?}", pid, e);
                    continue;
                }
            },
            None => {
                error!("fail to read task of {}", pid);
                continue;
            }
        };
        tids.push(tid);
    }

    Ok(tids)
}

// get thread name and the index of the last character(including ')').
fn get_thread_name(tid: pid_t, stat: &str) -> Result<(String, usize)> {
    let start = stat.find('(');
    let end = stat.rfind(')');

    if let (Some(start), Some(end)) = (start, end) {
        let raw = &stat[start + 1..end];
        let mut name = String::with_capacity(raw.len());

        // sanitize thread name.
        for c in raw.chars() {
            match c {
                // Prometheus label characters `[a-zA-Z0-9_:]`
                'a'...'z' | 'A'...'Z' | '0'...'9' | '_' | ':' => {
                    name.push(c);
                }
                '-' | ' ' => {
                    name.push('_');
                }
                _ => (),
            }
        }

        if name.is_empty() {
            name = format!("{}", tid)
        }

        return Ok((name, end));
    }

    Err(to_err(format!("can not find thread name, stat: {}", stat)))
}

fn to_err(s: String) -> Error {
    Error::new(ErrorKind::Other, s)
}

// See more man proc.
// Index of utime and stime.
const CPU_INDEX: [usize; 2] = [14 - 1, 15 - 1];

fn get_thread_stat(pid: pid_t, tid: pid_t) -> Result<(String, f64, f64)> {
    let mut stat = String::new();
    fs::File::open(format!("/proc/{}/task/{}/stat", pid, tid))
        .and_then(|mut f| f.read_to_string(&mut stat))?;
    get_thread_stat_internal(tid, &stat)
}

// Extracted from `get_thread_stat`, for test purpose.
fn get_thread_stat_internal(tid: pid_t, stat: &str) -> Result<(String, f64, f64)> {
    let (name, end) = get_thread_name(tid, stat)?;
    let stats: Vec<_> = (&stat[end + 2..]).split_whitespace().collect(); // excluding ") ".
    let utime = stats[CPU_INDEX[0] - 2]; // pid and comm is truncated.
    let stime = stats[CPU_INDEX[1] - 2];
    Ok((name, utime.parse().unwrap(), stime.parse().unwrap()))
}

lazy_static! {
    // getconf CLK_TCK
    static ref CLK_TCK: f64 = {
        unsafe {
            libc::sysconf(libc::_SC_CLK_TCK) as f64
        }
    };
}

#[cfg(test)]
mod tests {
    use std::sync;
    use std::thread;

    use libc;

    #[test]
    fn test_thread_stat() {
        let name = "theadnametest66";
        let (tx, rx) = sync::mpsc::channel();
        let (tx1, rx1) = sync::mpsc::channel();
        let h = thread::Builder::new()
            .name(name.to_owned())
            .spawn(move || {
                tx1.send(()).unwrap();
                rx.recv().unwrap();
            })
            .unwrap();
        rx1.recv().unwrap();

        let pid = unsafe { libc::getpid() };
        let tids = super::get_thread_ids(pid).unwrap();
        assert!(tids.len() >= 2);

        tids.iter()
            .find(|t| {
                super::get_thread_stat(pid, **t)
                    .map(|stat| stat.0 == name)
                    .unwrap_or(false)
            })
            .unwrap();

        tx.send(()).unwrap();
        h.join().unwrap();
    }

    #[test]
    fn test_get_thread_name() {
        let cases = [
            ("(ok123)", "ok123", 6),
            ("(a-b)", "a_b", 4),
            ("(Az_1:)", "Az_1:", 6),
            ("(@123)", "123", 5),
            ("1 (ab) 1", "ab", 5),
            ("1 (a b) 1", "a_b", 6),
            ("1 ((a b )) 1", "a_b_", 9),
        ];
        for &(i, o, idx) in &cases {
            let (name, end) = super::get_thread_name(1, i).unwrap();
            assert_eq!(name, o);
            assert_eq!(end, idx);
        }

        assert_eq!(super::get_thread_name(1, "(@#)").unwrap().0, "1");
        assert!(super::get_thread_name(1, "invalid_stat").is_err());
    }

    #[test]
    fn test_get_thread_stat() {
        let sample = "2810 (test thd) S 2550 2621 2621 0 -1 4210688 2632 0 52 0 839 138 0 \
                      0 20 0 4 0 13862 709652480 3647 18446744073709551615 4194304 4319028 \
                      140732554845776 140732554845392 140439688777693 0 0 4096 16384 0 0 0 17 3 \
                      0 0 245 0 0 6417696 6421000 8478720 140732554851684 140732554851747 \
                      140732554851747 140732554854339 0";

        let (name, utime, stime) = super::get_thread_stat_internal(2810, sample).unwrap();
        assert_eq!(name, "test_thd");
        assert_eq!(utime as i64, 839);
        assert_eq!(stime as i64, 138);
    }
}
<commit_msg>util/metrics: fix some typos in threads metrics (#3177)<commit_after>// Copyright 2017 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fs;
use std::io::{Error, ErrorKind, Read, Result};
use std::sync::Mutex;

use prometheus::core::{Collector, Desc};
use prometheus::{self, proto, CounterVec, Opts};

use libc::{self, pid_t};

/// monitor current process's threads.
pub fn monitor_threads<S: Into<String>>(namespace: S) -> Result<()> {
    let pid = unsafe { libc::getpid() };
    let tc = ThreadsCollector::new(pid, namespace);
    prometheus::register(Box::new(tc)).map_err(|e| to_err(format!("{:?}", e)))?;

    Ok(())
}

struct ThreadsCollector {
    pid: pid_t,
    descs: Vec<Desc>,
    cpu_totals: Mutex<CounterVec>,
}

impl ThreadsCollector {
    fn new<S: Into<String>>(pid: pid_t, namespace: S) -> ThreadsCollector {
        let cpu_totals = CounterVec::new(
            Opts::new(
                "thread_cpu_seconds_total",
                "Total user and system CPU time spent in \
                 seconds by threads.",
            ).namespace(namespace),
            &["name", "tid"],
        ).unwrap();
        let descs = cpu_totals.desc().into_iter().cloned().collect();

        ThreadsCollector {
            pid,
            descs,
            cpu_totals: Mutex::new(cpu_totals),
        }
    }
}

impl Collector for ThreadsCollector {
    fn desc(&self) -> Vec<&Desc> {
        self.descs.iter().collect()
    }

    fn collect(&self) -> Vec<proto::MetricFamily> {
        let cpu_totals = self.cpu_totals.lock().unwrap();
        let tids = get_thread_ids(self.pid).unwrap();
        for tid in tids {
            if let Ok((tname, utime, stime)) = get_thread_stat(self.pid, tid) {
                let total = (utime + stime) / *CLK_TCK;
                let cpu_total = cpu_totals
                    .get_metric_with_label_values(&[&tname, &format!("{}", tid)])
                    .unwrap();
                let past = cpu_total.get();
                let delta = total - past;
                if delta > 0.0 {
                    cpu_total.inc_by(delta);
                }
            }
        }

        cpu_totals.collect()
    }
}

fn get_thread_ids(pid: pid_t) -> Result<Vec<pid_t>> {
    let mut tids = Vec::new();
    let dirs = fs::read_dir(format!("/proc/{}/task", pid))?;
    for task in dirs {
        let file_name = match task {
            Ok(t) => t.file_name(),
            Err(e) => {
                error!("fail to read task of {}, error {:?}", pid, e);
                continue;
            }
        };

        let tid = match file_name.to_str() {
            Some(tid) => match tid.parse() {
                Ok(tid) => tid,
                Err(e) => {
                    error!("fail to read task of {}, error {:?}", pid, e);
                    continue;
                }
            },
            None => {
                error!("fail to read task of {}", pid);
                continue;
            }
        };
        tids.push(tid);
    }

    Ok(tids)
}

// get thread name and the index of the last character(including ')').
fn get_thread_name(tid: pid_t, stat: &str) -> Result<(String, usize)> {
    let start = stat.find('(');
    let end = stat.rfind(')');

    if let (Some(start), Some(end)) = (start, end) {
        let raw = &stat[start + 1..end];
        let mut name = String::with_capacity(raw.len());

        // sanitize thread name.
        for c in raw.chars() {
            match c {
                // Prometheus label characters `[a-zA-Z0-9_:]`
                'a'...'z' | 'A'...'Z' | '0'...'9' | '_' | ':' => {
                    name.push(c);
                }
                '-' | ' ' => {
                    name.push('_');
                }
                _ => (),
            }
        }

        if name.is_empty() {
            name = format!("{}", tid)
        }

        return Ok((name, end));
    }

    Err(to_err(format!("can not find thread name, stat: {}", stat)))
}

fn to_err(s: String) -> Error {
    Error::new(ErrorKind::Other, s)
}

// See more man proc.
// Index of utime and stime.
const CPU_INDEX: [usize; 2] = [14 - 1, 15 - 1];

fn get_thread_stat(pid: pid_t, tid: pid_t) -> Result<(String, f64, f64)> {
    let mut stat = String::new();
    fs::File::open(format!("/proc/{}/task/{}/stat", pid, tid))
        .and_then(|mut f| f.read_to_string(&mut stat))?;
    get_thread_stat_internal(tid, &stat)
}

// Extracted from `get_thread_stat`, for test purpose.
fn get_thread_stat_internal(tid: pid_t, stat: &str) -> Result<(String, f64, f64)> {
    let (name, end) = get_thread_name(tid, stat)?;
    let stats: Vec<_> = (&stat[end + 2..]).split_whitespace().collect(); // excluding ") ".
    let utime = stats[CPU_INDEX[0] - 2]; // pid and comm is truncated.
    let stime = stats[CPU_INDEX[1] - 2];
    Ok((name, utime.parse().unwrap(), stime.parse().unwrap()))
}

lazy_static! {
    // getconf CLK_TCK
    static ref CLK_TCK: f64 = {
        unsafe {
            libc::sysconf(libc::_SC_CLK_TCK) as f64
        }
    };
}

#[cfg(test)]
mod tests {
    use std::sync;
    use std::thread;

    use libc;

    #[test]
    fn test_thread_stat() {
        let name = "theadnametest66";
        let (tx, rx) = sync::mpsc::channel();
        let (tx1, rx1) = sync::mpsc::channel();
        let h = thread::Builder::new()
            .name(name.to_owned())
            .spawn(move || {
                tx1.send(()).unwrap();
                rx.recv().unwrap();
            })
            .unwrap();
        rx1.recv().unwrap();

        let pid = unsafe { libc::getpid() };
        let tids = super::get_thread_ids(pid).unwrap();
        assert!(tids.len() >= 2);

        tids.iter()
            .find(|t| {
                super::get_thread_stat(pid, **t)
                    .map(|stat| stat.0 == name)
                    .unwrap_or(false)
            })
            .unwrap();

        tx.send(()).unwrap();
        h.join().unwrap();
    }

    #[test]
    fn test_get_thread_name() {
        let cases = [
            ("(ok123)", "ok123", 6),
            ("(a-b)", "a_b", 4),
            ("(Az_1:)", "Az_1:", 6),
            ("(@123)", "123", 5),
            ("1 (ab) 1", "ab", 5),
            ("1 (a b) 1", "a_b", 6),
            ("1 ((a b )) 1", "a_b_", 9),
        ];
        for &(i, o, idx) in &cases {
            let (name, end) = super::get_thread_name(1, i).unwrap();
            assert_eq!(name, o);
            assert_eq!(end, idx);
        }

        assert_eq!(super::get_thread_name(1, "(@#)").unwrap().0, "1");
        assert!(super::get_thread_name(1, "invalid_stat").is_err());
    }

    #[test]
    fn test_get_thread_stat() {
        let sample = "2810 (test thd) S 2550 2621 2621 0 -1 4210688 2632 0 52 0 839 138 0 \
                      0 20 0 4 0 13862 709652480 3647 18446744073709551615 4194304 4319028 \
                      140732554845776 140732554845392 140439688777693 0 0 4096 16384 0 0 0 17 3 \
                      0 0 245 0 0 6417696 6421000 8478720 140732554851684 140732554851747 \
                      140732554851747 140732554854339 0";

        let (name, utime, stime) = super::get_thread_stat_internal(2810, sample).unwrap();
        assert_eq!(name, "test_thd");
        assert_eq!(utime as i64, 839);
        assert_eq!(stime as i64, 138);
    }
}
<|endoftext|>


<commit_before>pub use self::cargo_clean::{clean, CleanOptions};
pub use self::cargo_compile::{compile, compile_with_exec, compile_ws, CompileOptions};
pub use self::cargo_compile::{CompileFilter, FilterRule, Packages};
pub use self::cargo_read_manifest::{read_package, read_packages};
pub use self::cargo_run::run;
pub use self::cargo_install::{install, install_list, uninstall};
pub use self::cargo_new::{init, new, NewOptions, VersionControl};
pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_generate_lockfile::generate_lockfile;
pub use self::cargo_generate_lockfile::update_lockfile;
pub use self::cargo_generate_lockfile::UpdateOptions;
pub use self::lockfile::{load_pkg_lockfile, write_pkg_lockfile};
pub use self::cargo_test::{run_benches, run_tests, TestOptions};
pub use self::cargo_package::{package, PackageOpts};
pub use self::registry::{publish, registry_configuration, RegistryConfig};
pub use self::registry::{http_handle, needs_custom_http_transport, registry_login, search};
pub use self::registry::{modify_owners, yank, OwnersOptions, PublishOpts};
pub use self::registry::configure_http_handle;
pub use self::cargo_fetch::{fetch, FetchOptions};
pub use self::cargo_pkgid::pkgid;
pub use self::resolve::{resolve_with_previous, resolve_ws, resolve_ws_precisely,
                        resolve_ws_with_method};
pub use self::cargo_output_metadata::{output_metadata, ExportInfo, OutputMetadataOptions};

mod cargo_clean;
mod cargo_compile;
mod cargo_doc;
mod cargo_fetch;
mod cargo_generate_lockfile;
mod cargo_install;
mod cargo_new;
mod cargo_output_metadata;
mod cargo_package;
mod cargo_pkgid;
mod cargo_read_manifest;
mod cargo_run;
mod cargo_test;
mod lockfile;
mod registry;
mod resolve;
<commit_msg>Add missing reexport for #5572<commit_after>pub use self::cargo_clean::{clean, CleanOptions};
pub use self::cargo_compile::{compile, compile_with_exec, compile_ws, CompileOptions};
pub use self::cargo_compile::{CompileFilter, FilterRule, Packages};
pub use self::cargo_read_manifest::{read_package, read_packages};
pub use self::cargo_run::run;
pub use self::cargo_install::{install, install_list, uninstall};
pub use self::cargo_new::{init, new, NewOptions, VersionControl};
pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_generate_lockfile::generate_lockfile;
pub use self::cargo_generate_lockfile::update_lockfile;
pub use self::cargo_generate_lockfile::UpdateOptions;
pub use self::lockfile::{load_pkg_lockfile, write_pkg_lockfile};
pub use self::cargo_test::{run_benches, run_tests, TestOptions};
pub use self::cargo_package::{package, PackageOpts};
pub use self::registry::{publish, registry_configuration, RegistryConfig};
pub use self::registry::{http_handle, needs_custom_http_transport, registry_login, search};
pub use self::registry::{modify_owners, yank, OwnersOptions, PublishOpts};
pub use self::registry::configure_http_handle;
pub use self::cargo_fetch::{fetch, FetchOptions};
pub use self::cargo_pkgid::pkgid;
pub use self::resolve::{add_overrides, get_resolved_packages, resolve_with_previous, resolve_ws,
                        resolve_ws_precisely, resolve_ws_with_method};
pub use self::cargo_output_metadata::{output_metadata, ExportInfo, OutputMetadataOptions};

mod cargo_clean;
mod cargo_compile;
mod cargo_doc;
mod cargo_fetch;
mod cargo_generate_lockfile;
mod cargo_install;
mod cargo_new;
mod cargo_output_metadata;
mod cargo_package;
mod cargo_pkgid;
mod cargo_read_manifest;
mod cargo_run;
mod cargo_test;
mod lockfile;
mod registry;
mod resolve;
<|endoftext|>


<commit_before>import util.common.ty_mach;
import util.common.ty_mach_to_str;
import std._int;
import std._uint;

type op = tag
    (PLUS(),
     MINUS(),
     STAR(),
     SLASH(),
     PERCENT(),
     EQ(),
     LT(),
     LE(),
     EQEQ(),
     NE(),
     GE(),
     GT(),
     NOT(),
     TILDE(),
     CARET(),
     AND(),
     ANDAND(),
     OR(),
     OROR(),
     LSL(),
     LSR(),
     ASR());

type token = tag
    (OP(op),
     OPEQ(op),
     AS(),
     WITH(),

     /* Structural symbols */
     AT(),
     DOT(),
     COMMA(),
     SEMI(),
     COLON(),
     RARROW(),
     SEND(),
     LARROW(),
     LPAREN(),
     RPAREN(),
     LBRACKET(),
     RBRACKET(),
     LBRACE(),
     RBRACE(),

     /* Module and crate keywords */
     MOD(),
     USE(),
     AUTH(),
     META(),

     /* Metaprogramming keywords */
     SYNTAX(),
     POUND(),

     /* Statement keywords */
     IF(),
     ELSE(),
     DO(),
     WHILE(),
     ALT(),
     CASE(),

     FAIL(),
     DROP(),

     IN(),
     FOR(),
     EACH(),
     PUT(),
     RET(),
     BE(),

     /* Type and type-state keywords */
     TYPE(),
     CHECK(),
     CLAIM(),
     PROVE(),

     /* Effect keywords */
     IO(),
     STATE(),
     UNSAFE(),

     /* Type qualifiers */
     NATIVE(),
     AUTO(),
     MUTABLE(),

     /* Name management */
     IMPORT(),
     EXPORT(),

     /* Value / stmt declarators */
     LET(),

     /* Magic runtime services */
     LOG(),
     SPAWN(),
     BIND(),
     THREAD(),
     YIELD(),
     JOIN(),

     /* Literals */
     LIT_INT(int),
     LIT_UINT(uint),
     LIT_MACH_INT(ty_mach, int),
     LIT_STR(str),
     LIT_CHAR(char),
     LIT_BOOL(bool),

     /* Name components */
     IDENT(str),
     IDX(int),
     UNDERSCORE(),

     /* Reserved type names */
     BOOL(),
     INT(),
     UINT(),
     FLOAT(),
     CHAR(),
     STR(),
     MACH(ty_mach),

     /* Algebraic type constructors */
     REC(),
     TUP(),
     TAG(),
     VEC(),
     ANY(),

     /* Callable type constructors */
     FN(),
     ITER(),

     /* Object type */
     OBJ(),

     /* Comm and task types */
     CHAN(),
     PORT(),
     TASK(),

     BRACEQUOTE(str),
     EOF());

fn to_str(token t) -> str {
    alt (t) {
        case (OP(_)) { ret "<op>"; }
        case (OPEQ(_)) { ret "<op>="; }
        case (AS()) { ret "as"; }
        case (WITH()) { ret "with"; }

        /* Structural symbols */
        case (AT()) { ret "@"; }
        case (DOT()) { ret "."; }
        case (COMMA()) { ret ","; }
        case (SEMI()) { ret ";"; }
        case (COLON()) { ret ":"; }
        case (RARROW()) { ret "->"; }
        case (SEND()) { ret "<|"; }
        case (LARROW()) { ret "<-"; }
        case (LPAREN()) { ret "("; }
        case (RPAREN()) { ret ")"; }
        case (LBRACKET()) { ret "["; }
        case (RBRACKET()) { ret "]"; }
        case (LBRACE()) { ret "{"; }
        case (RBRACE()) { ret "}"; }

        /* Module and crate keywords */
        case (MOD()) { ret "mod"; }
        case (USE()) { ret "use"; }
        case (AUTH()) { ret "auth"; }
        case (META()) { ret "meta"; }

        /* Metaprogramming keywords */
        case (SYNTAX()) { ret "syntax"; }
        case (POUND()) { ret "#"; }

        /* Statement keywords */
        case (IF()) { ret "if"; }
        case (ELSE()) { ret "else"; }
        case (DO()) { ret "do"; }
        case (WHILE()) { ret "while"; }
        case (ALT()) { ret "alt"; }
        case (CASE()) { ret "case"; }

        case (FAIL()) { ret "fail"; }
        case (DROP()) { ret "drop"; }

        case (IN()) { ret "in"; }
        case (FOR()) { ret "for"; }
        case (EACH()) { ret "each"; }
        case (PUT()) { ret "put"; }
        case (RET()) { ret "ret"; }
        case (BE()) { ret "be"; }

        /* Type and type-state keywords */
        case (TYPE()) { ret "type"; }
        case (CHECK()) { ret "check"; }
        case (CLAIM()) { ret "claim"; }
        case (PROVE()) { ret "prove"; }

        /* Effect keywords */
        case (IO()) { ret "io"; }
        case (STATE()) { ret "state"; }
        case (UNSAFE()) { ret "unsafe"; }

        /* Type qualifiers */
        case (NATIVE()) { ret "native"; }
        case (AUTO()) { ret "auto"; }
        case (MUTABLE()) { ret "mutable"; }

        /* Name management */
        case (IMPORT()) { ret "import"; }
        case (EXPORT()) { ret "export"; }

        /* Value / stmt declarators */
        case (LET()) { ret "let"; }

        /* Magic runtime services */
        case (LOG()) { ret "log"; }
        case (SPAWN()) { ret "spawn"; }
        case (BIND()) { ret "bind"; }
        case (THREAD()) { ret "thread"; }
        case (YIELD()) { ret "yield"; }
        case (JOIN()) { ret "join"; }

        /* Literals */
        case (LIT_INT(i)) { ret _int.to_str(i, 10u); }
        case (LIT_UINT(u)) { ret _uint.to_str(u, 10u); }
        case (LIT_MACH_INT(tm, i)) {
            ret  _int.to_str(i, 10u)
                + "_" + ty_mach_to_str(tm);
        }

        case (LIT_STR(s)) {
            // FIXME: escape.
            ret "\"" + s + "\"";
        }
        case (LIT_CHAR(c)) {
            // FIXME: escape and encode.
            auto tmp = "";
            tmp += (c as u8);
            ret tmp;
        }

        case (LIT_BOOL(b)) {
            if (b) { ret "true"; } else { ret "false"; }
        }

        /* Name components */
        case (IDENT(s)) { ret s; }
        case (IDX(i)) { ret "_" + _int.to_str(i, 10u); }
        case (UNDERSCORE()) { ret "_"; }

        /* Reserved type names */
        case (BOOL()) { ret "bool"; }
        case (INT()) { ret "int"; }
        case (UINT()) { ret "uint"; }
        case (FLOAT()) { ret "float"; }
        case (CHAR()) { ret "char"; }
        case (STR()) { ret "str"; }
        case (MACH(tm)) { ret ty_mach_to_str(tm); }

        /* Algebraic type constructors */
        case (REC()) { ret "rec"; }
        case (TUP()) { ret "tup"; }
        case (TAG()) { ret "tag"; }
        case (VEC()) { ret "vec"; }
        case (ANY()) { ret "any"; }

        /* Callable type constructors */
        case (FN()) { ret "fn"; }
        case (ITER()) { ret "iter"; }

        /* Object type */
        case (OBJ()) { ret "obj"; }

        /* Comm and task types */
        case (CHAN()) { ret "chan"; }
        case (PORT()) { ret "port"; }
        case (TASK()) { ret "task"; }

        case (BRACEQUOTE(_)) { ret "<bracequote>"; }
        case (EOF()) { ret "<eof>"; }
    }
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Stringify op tokens.<commit_after>import util.common.ty_mach;
import util.common.ty_mach_to_str;
import std._int;
import std._uint;

type op = tag
    (PLUS(),
     MINUS(),
     STAR(),
     SLASH(),
     PERCENT(),
     EQ(),
     LT(),
     LE(),
     EQEQ(),
     NE(),
     GE(),
     GT(),
     NOT(),
     TILDE(),
     CARET(),
     AND(),
     ANDAND(),
     OR(),
     OROR(),
     LSL(),
     LSR(),
     ASR());

type token = tag
    (OP(op),
     OPEQ(op),
     AS(),
     WITH(),

     /* Structural symbols */
     AT(),
     DOT(),
     COMMA(),
     SEMI(),
     COLON(),
     RARROW(),
     SEND(),
     LARROW(),
     LPAREN(),
     RPAREN(),
     LBRACKET(),
     RBRACKET(),
     LBRACE(),
     RBRACE(),

     /* Module and crate keywords */
     MOD(),
     USE(),
     AUTH(),
     META(),

     /* Metaprogramming keywords */
     SYNTAX(),
     POUND(),

     /* Statement keywords */
     IF(),
     ELSE(),
     DO(),
     WHILE(),
     ALT(),
     CASE(),

     FAIL(),
     DROP(),

     IN(),
     FOR(),
     EACH(),
     PUT(),
     RET(),
     BE(),

     /* Type and type-state keywords */
     TYPE(),
     CHECK(),
     CLAIM(),
     PROVE(),

     /* Effect keywords */
     IO(),
     STATE(),
     UNSAFE(),

     /* Type qualifiers */
     NATIVE(),
     AUTO(),
     MUTABLE(),

     /* Name management */
     IMPORT(),
     EXPORT(),

     /* Value / stmt declarators */
     LET(),

     /* Magic runtime services */
     LOG(),
     SPAWN(),
     BIND(),
     THREAD(),
     YIELD(),
     JOIN(),

     /* Literals */
     LIT_INT(int),
     LIT_UINT(uint),
     LIT_MACH_INT(ty_mach, int),
     LIT_STR(str),
     LIT_CHAR(char),
     LIT_BOOL(bool),

     /* Name components */
     IDENT(str),
     IDX(int),
     UNDERSCORE(),

     /* Reserved type names */
     BOOL(),
     INT(),
     UINT(),
     FLOAT(),
     CHAR(),
     STR(),
     MACH(ty_mach),

     /* Algebraic type constructors */
     REC(),
     TUP(),
     TAG(),
     VEC(),
     ANY(),

     /* Callable type constructors */
     FN(),
     ITER(),

     /* Object type */
     OBJ(),

     /* Comm and task types */
     CHAN(),
     PORT(),
     TASK(),

     BRACEQUOTE(str),
     EOF());

fn op_to_str(op o) -> str {
    alt (o) {
         case (PLUS()) { ret "+"; }
         case (MINUS()) { ret "-"; }
         case (STAR()) { ret "*"; }
         case (SLASH()) { ret "/"; }
         case (PERCENT()) { ret "%"; }
         case (EQ()) { ret "="; }
         case (LT()) { ret "<"; }
         case (LE()) { ret "<="; }
         case (EQEQ()) { ret "=="; }
         case (NE()) { ret "!="; }
         case (GE()) { ret ">="; }
         case (GT()) { ret ">"; }
         case (NOT()) { ret "!"; }
         case (TILDE()) { ret "~"; }
         case (CARET()) { ret "^"; }
         case (AND()) { ret "&"; }
         case (ANDAND()) { ret "&&"; }
         case (OR()) { ret "|"; }
         case (OROR()) { ret "||"; }
         case (LSL()) { ret "<<"; }
         case (LSR()) { ret ">>"; }
         case (ASR()) { ret ">>>"; }
    }
}

fn to_str(token t) -> str {
    alt (t) {
        case (OP(op)) { ret op_to_str(op); }
        case (OPEQ(op)) { ret op_to_str(op) + "="; }
        case (AS()) { ret "as"; }
        case (WITH()) { ret "with"; }

        /* Structural symbols */
        case (AT()) { ret "@"; }
        case (DOT()) { ret "."; }
        case (COMMA()) { ret ","; }
        case (SEMI()) { ret ";"; }
        case (COLON()) { ret ":"; }
        case (RARROW()) { ret "->"; }
        case (SEND()) { ret "<|"; }
        case (LARROW()) { ret "<-"; }
        case (LPAREN()) { ret "("; }
        case (RPAREN()) { ret ")"; }
        case (LBRACKET()) { ret "["; }
        case (RBRACKET()) { ret "]"; }
        case (LBRACE()) { ret "{"; }
        case (RBRACE()) { ret "}"; }

        /* Module and crate keywords */
        case (MOD()) { ret "mod"; }
        case (USE()) { ret "use"; }
        case (AUTH()) { ret "auth"; }
        case (META()) { ret "meta"; }

        /* Metaprogramming keywords */
        case (SYNTAX()) { ret "syntax"; }
        case (POUND()) { ret "#"; }

        /* Statement keywords */
        case (IF()) { ret "if"; }
        case (ELSE()) { ret "else"; }
        case (DO()) { ret "do"; }
        case (WHILE()) { ret "while"; }
        case (ALT()) { ret "alt"; }
        case (CASE()) { ret "case"; }

        case (FAIL()) { ret "fail"; }
        case (DROP()) { ret "drop"; }

        case (IN()) { ret "in"; }
        case (FOR()) { ret "for"; }
        case (EACH()) { ret "each"; }
        case (PUT()) { ret "put"; }
        case (RET()) { ret "ret"; }
        case (BE()) { ret "be"; }

        /* Type and type-state keywords */
        case (TYPE()) { ret "type"; }
        case (CHECK()) { ret "check"; }
        case (CLAIM()) { ret "claim"; }
        case (PROVE()) { ret "prove"; }

        /* Effect keywords */
        case (IO()) { ret "io"; }
        case (STATE()) { ret "state"; }
        case (UNSAFE()) { ret "unsafe"; }

        /* Type qualifiers */
        case (NATIVE()) { ret "native"; }
        case (AUTO()) { ret "auto"; }
        case (MUTABLE()) { ret "mutable"; }

        /* Name management */
        case (IMPORT()) { ret "import"; }
        case (EXPORT()) { ret "export"; }

        /* Value / stmt declarators */
        case (LET()) { ret "let"; }

        /* Magic runtime services */
        case (LOG()) { ret "log"; }
        case (SPAWN()) { ret "spawn"; }
        case (BIND()) { ret "bind"; }
        case (THREAD()) { ret "thread"; }
        case (YIELD()) { ret "yield"; }
        case (JOIN()) { ret "join"; }

        /* Literals */
        case (LIT_INT(i)) { ret _int.to_str(i, 10u); }
        case (LIT_UINT(u)) { ret _uint.to_str(u, 10u); }
        case (LIT_MACH_INT(tm, i)) {
            ret  _int.to_str(i, 10u)
                + "_" + ty_mach_to_str(tm);
        }

        case (LIT_STR(s)) {
            // FIXME: escape.
            ret "\"" + s + "\"";
        }
        case (LIT_CHAR(c)) {
            // FIXME: escape and encode.
            auto tmp = "";
            tmp += (c as u8);
            ret tmp;
        }

        case (LIT_BOOL(b)) {
            if (b) { ret "true"; } else { ret "false"; }
        }

        /* Name components */
        case (IDENT(s)) { ret s; }
        case (IDX(i)) { ret "_" + _int.to_str(i, 10u); }
        case (UNDERSCORE()) { ret "_"; }

        /* Reserved type names */
        case (BOOL()) { ret "bool"; }
        case (INT()) { ret "int"; }
        case (UINT()) { ret "uint"; }
        case (FLOAT()) { ret "float"; }
        case (CHAR()) { ret "char"; }
        case (STR()) { ret "str"; }
        case (MACH(tm)) { ret ty_mach_to_str(tm); }

        /* Algebraic type constructors */
        case (REC()) { ret "rec"; }
        case (TUP()) { ret "tup"; }
        case (TAG()) { ret "tag"; }
        case (VEC()) { ret "vec"; }
        case (ANY()) { ret "any"; }

        /* Callable type constructors */
        case (FN()) { ret "fn"; }
        case (ITER()) { ret "iter"; }

        /* Object type */
        case (OBJ()) { ret "obj"; }

        /* Comm and task types */
        case (CHAN()) { ret "chan"; }
        case (PORT()) { ret "port"; }
        case (TASK()) { ret "task"; }

        case (BRACEQUOTE(_)) { ret "<bracequote>"; }
        case (EOF()) { ret "<eof>"; }
    }
}

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