<commit_before>
use std;
import std::str;

fn test(str actual, str expected) {
    log actual;
    log expected;
    assert (str::eq(actual, expected));
}

fn main() {
    test(#fmt("hello %d friends and %s things", 10, "formatted"),
         "hello 10 friends and formatted things");

    test(#fmt("test"), "test");

    // Simple tests for types

    test(#fmt("%d", 1), "1");
    test(#fmt("%i", 2), "2");
    test(#fmt("%i", -1), "-1");
    test(#fmt("%u", 10u), "10");
    test(#fmt("%s", "test"), "test");
    test(#fmt("%b", true), "true");
    test(#fmt("%b", false), "false");
    test(#fmt("%c", 'A'), "A");
    test(#fmt("%x", 0xff_u), "ff");
    test(#fmt("%X", 0x12ab_u), "12AB");
    test(#fmt("%o", 10u), "12");
    test(#fmt("%t", 0b11010101_u), "11010101");
    // 32-bit limits

    test(#fmt("%i", -2147483648), "-2147483648");
    test(#fmt("%i", 2147483647), "2147483647");
    test(#fmt("%u", 4294967295u), "4294967295");
    test(#fmt("%x", 0xffffffff_u), "ffffffff");
    test(#fmt("%o", 0xffffffff_u), "37777777777");
    test(#fmt("%t", 0xffffffff_u), "11111111111111111111111111111111");
    // Widths

    test(#fmt("%1d", 500), "500");
    test(#fmt("%10d", 500), "       500");
    test(#fmt("%10d", -500), "      -500");
    test(#fmt("%10u", 500u), "       500");
    test(#fmt("%10s", "test"), "      test");
    test(#fmt("%10b", true), "      true");
    test(#fmt("%10x", 0xff_u), "        ff");
    test(#fmt("%10X", 0xff_u), "        FF");
    test(#fmt("%10o", 10u), "        12");
    test(#fmt("%10t", 0xff_u), "  11111111");
    test(#fmt("%10c", 'A'), "         A");
    // Left justify

    test(#fmt("%-10d", 500), "500       ");
    test(#fmt("%-10d", -500), "-500      ");
    test(#fmt("%-10u", 500u), "500       ");
    test(#fmt("%-10s", "test"), "test      ");
    test(#fmt("%-10b", true), "true      ");
    test(#fmt("%-10x", 0xff_u), "ff        ");
    test(#fmt("%-10X", 0xff_u), "FF        ");
    test(#fmt("%-10o", 10u), "12        ");
    test(#fmt("%-10t", 0xff_u), "11111111  ");
    test(#fmt("%-10c", 'A'), "A         ");
    // Precision

    test(#fmt("%.d", 0), "");
    test(#fmt("%.u", 0u), "");
    test(#fmt("%.x", 0u), "");
    test(#fmt("%.t", 0u), "");
    test(#fmt("%.d", 10), "10");
    test(#fmt("%.d", -10), "-10");
    test(#fmt("%.u", 10u), "10");
    test(#fmt("%.s", "test"), "");
    test(#fmt("%.x", 127u), "7f");
    test(#fmt("%.o", 10u), "12");
    test(#fmt("%.t", 3u), "11");
    test(#fmt("%.c", 'A'), "A");
    test(#fmt("%.0d", 0), "");
    test(#fmt("%.0u", 0u), "");
    test(#fmt("%.0x", 0u), "");
    test(#fmt("%.0t", 0u), "");
    test(#fmt("%.0d", 10), "10");
    test(#fmt("%.0d", -10), "-10");
    test(#fmt("%.0u", 10u), "10");
    test(#fmt("%.0s", "test"), "");
    test(#fmt("%.0x", 127u), "7f");
    test(#fmt("%.0o", 10u), "12");
    test(#fmt("%.0t", 3u), "11");
    test(#fmt("%.0c", 'A'), "A");
    test(#fmt("%.1d", 0), "0");
    test(#fmt("%.1u", 0u), "0");
    test(#fmt("%.1x", 0u), "0");
    test(#fmt("%.1t", 0u), "0");
    test(#fmt("%.1d", 10), "10");
    test(#fmt("%.1d", -10), "-10");
    test(#fmt("%.1u", 10u), "10");
    test(#fmt("%.1s", "test"), "t");
    test(#fmt("%.1x", 127u), "7f");
    test(#fmt("%.1o", 10u), "12");
    test(#fmt("%.1t", 3u), "11");
    test(#fmt("%.1c", 'A'), "A");
    test(#fmt("%.5d", 0), "00000");
    test(#fmt("%.5u", 0u), "00000");
    test(#fmt("%.5x", 0u), "00000");
    test(#fmt("%.5t", 0u), "00000");
    test(#fmt("%.5d", 10), "00010");
    test(#fmt("%.5d", -10), "-00010");
    test(#fmt("%.5u", 10u), "00010");
    test(#fmt("%.5s", "test"), "test");
    test(#fmt("%.5x", 127u), "0007f");
    test(#fmt("%.5o", 10u), "00012");
    test(#fmt("%.5t", 3u), "00011");
    test(#fmt("%.5c", 'A'), "A");
    // Bool precision. I'm not sure if it's good or bad to have bool
    // conversions support precision - it's not standard printf so we
    // can do whatever. For now I'm making it behave the same as string
    // conversions.

    test(#fmt("%.b", true), "");
    test(#fmt("%.0b", true), "");
    test(#fmt("%.1b", true), "t");
    // Explicit + sign. Only for signed conversions

    test(#fmt("%+d", 0), "+0");
    test(#fmt("%+d", 1), "+1");
    test(#fmt("%+d", -1), "-1");
    // Leave space for sign

    test(#fmt("% d", 0), " 0");
    test(#fmt("% d", 1), " 1");
    test(#fmt("% d", -1), "-1");
    // Plus overrides space

    test(#fmt("% +d", 0), "+0");
    test(#fmt("%+ d", 0), "+0");
    // 0-padding

    test(#fmt("%05d", 0), "00000");
    test(#fmt("%05d", 1), "00001");
    test(#fmt("%05d", -1), "-0001");
    test(#fmt("%05u", 1u), "00001");
    test(#fmt("%05x", 127u), "0007f");
    test(#fmt("%05X", 127u), "0007F");
    test(#fmt("%05o", 10u), "00012");
    test(#fmt("%05t", 3u), "00011");
    // 0-padding a string is undefined but glibc does this:

    test(#fmt("%05s", "test"), " test");
    test(#fmt("%05c", 'A'), "    A");
    test(#fmt("%05b", true), " true");
    // Left-justify overrides 0-padding

    test(#fmt("%-05d", 0), "0    ");
    test(#fmt("%-05d", 1), "1    ");
    test(#fmt("%-05d", -1), "-1   ");
    test(#fmt("%-05u", 1u), "1    ");
    test(#fmt("%-05x", 127u), "7f   ");
    test(#fmt("%-05X", 127u), "7F   ");
    test(#fmt("%-05o", 10u), "12   ");
    test(#fmt("%-05t", 3u), "11   ");
    test(#fmt("%-05s", "test"), "test ");
    test(#fmt("%-05c", 'A'), "A    ");
    test(#fmt("%-05b", true), "true ");
    // Precision overrides 0-padding

    test(#fmt("%06.5d", 0), " 00000");
    test(#fmt("%06.5u", 0u), " 00000");
    test(#fmt("%06.5x", 0u), " 00000");
    test(#fmt("%06.5d", 10), " 00010");
    test(#fmt("%06.5d", -10), "-00010");
    test(#fmt("%06.5u", 10u), " 00010");
    test(#fmt("%06.5s", "test"), "  test");
    test(#fmt("%06.5c", 'A'), "     A");
    test(#fmt("%06.5x", 127u), " 0007f");
    test(#fmt("%06.5X", 127u), " 0007F");
    test(#fmt("%06.5o", 10u), " 00012");
    // Signed combinations

    test(#fmt("% 5d", 1), "    1");
    test(#fmt("% 5d", -1), "   -1");
    test(#fmt("%+5d", 1), "   +1");
    test(#fmt("%+5d", -1), "   -1");
    test(#fmt("% 05d", 1), " 0001");
    test(#fmt("% 05d", -1), "-0001");
    test(#fmt("%+05d", 1), "+0001");
    test(#fmt("%+05d", -1), "-0001");
    test(#fmt("%- 5d", 1), " 1   ");
    test(#fmt("%- 5d", -1), "-1   ");
    test(#fmt("%-+5d", 1), "+1   ");
    test(#fmt("%-+5d", -1), "-1   ");
    test(#fmt("%- 05d", 1), " 1   ");
    test(#fmt("%- 05d", -1), "-1   ");
    test(#fmt("%-+05d", 1), "+1   ");
    test(#fmt("%-+05d", -1), "-1   ");
}<commit_msg>Make a test compile faster.<commit_after>
use std;
import std::str;

fn test(str actual, str expected) {
    log actual;
    log expected;
    assert (str::eq(actual, expected));
}

fn main() {
    test(#fmt("hello %d friends and %s things", 10, "formatted"),
         "hello 10 friends and formatted things");

    test(#fmt("test"), "test");

    // a quadratic optimization in LLVM (jump-threading) makes this test a
    // bit slow to compile unless we break it up
    part1();
    part2();
    part3();
    part4();
    part5();
    part6();
}

fn part1() {
    // Simple tests for types

    test(#fmt("%d", 1), "1");
    test(#fmt("%i", 2), "2");
    test(#fmt("%i", -1), "-1");
    test(#fmt("%u", 10u), "10");
    test(#fmt("%s", "test"), "test");
    test(#fmt("%b", true), "true");
    test(#fmt("%b", false), "false");
    test(#fmt("%c", 'A'), "A");
    test(#fmt("%x", 0xff_u), "ff");
    test(#fmt("%X", 0x12ab_u), "12AB");
    test(#fmt("%o", 10u), "12");
    test(#fmt("%t", 0b11010101_u), "11010101");
    // 32-bit limits

    test(#fmt("%i", -2147483648), "-2147483648");
    test(#fmt("%i", 2147483647), "2147483647");
    test(#fmt("%u", 4294967295u), "4294967295");
    test(#fmt("%x", 0xffffffff_u), "ffffffff");
    test(#fmt("%o", 0xffffffff_u), "37777777777");
    test(#fmt("%t", 0xffffffff_u), "11111111111111111111111111111111");
}
fn part2() {
    // Widths

    test(#fmt("%1d", 500), "500");
    test(#fmt("%10d", 500), "       500");
    test(#fmt("%10d", -500), "      -500");
    test(#fmt("%10u", 500u), "       500");
    test(#fmt("%10s", "test"), "      test");
    test(#fmt("%10b", true), "      true");
    test(#fmt("%10x", 0xff_u), "        ff");
    test(#fmt("%10X", 0xff_u), "        FF");
    test(#fmt("%10o", 10u), "        12");
    test(#fmt("%10t", 0xff_u), "  11111111");
    test(#fmt("%10c", 'A'), "         A");
    // Left justify

    test(#fmt("%-10d", 500), "500       ");
    test(#fmt("%-10d", -500), "-500      ");
    test(#fmt("%-10u", 500u), "500       ");
    test(#fmt("%-10s", "test"), "test      ");
    test(#fmt("%-10b", true), "true      ");
    test(#fmt("%-10x", 0xff_u), "ff        ");
    test(#fmt("%-10X", 0xff_u), "FF        ");
    test(#fmt("%-10o", 10u), "12        ");
    test(#fmt("%-10t", 0xff_u), "11111111  ");
    test(#fmt("%-10c", 'A'), "A         ");
}

fn part3() {
    // Precision

    test(#fmt("%.d", 0), "");
    test(#fmt("%.u", 0u), "");
    test(#fmt("%.x", 0u), "");
    test(#fmt("%.t", 0u), "");
    test(#fmt("%.d", 10), "10");
    test(#fmt("%.d", -10), "-10");
    test(#fmt("%.u", 10u), "10");
    test(#fmt("%.s", "test"), "");
    test(#fmt("%.x", 127u), "7f");
    test(#fmt("%.o", 10u), "12");
    test(#fmt("%.t", 3u), "11");
    test(#fmt("%.c", 'A'), "A");
    test(#fmt("%.0d", 0), "");
    test(#fmt("%.0u", 0u), "");
    test(#fmt("%.0x", 0u), "");
    test(#fmt("%.0t", 0u), "");
    test(#fmt("%.0d", 10), "10");
    test(#fmt("%.0d", -10), "-10");
    test(#fmt("%.0u", 10u), "10");
    test(#fmt("%.0s", "test"), "");
    test(#fmt("%.0x", 127u), "7f");
    test(#fmt("%.0o", 10u), "12");
    test(#fmt("%.0t", 3u), "11");
    test(#fmt("%.0c", 'A'), "A");
    test(#fmt("%.1d", 0), "0");
    test(#fmt("%.1u", 0u), "0");
    test(#fmt("%.1x", 0u), "0");
    test(#fmt("%.1t", 0u), "0");
    test(#fmt("%.1d", 10), "10");
    test(#fmt("%.1d", -10), "-10");
    test(#fmt("%.1u", 10u), "10");
    test(#fmt("%.1s", "test"), "t");
    test(#fmt("%.1x", 127u), "7f");
    test(#fmt("%.1o", 10u), "12");
    test(#fmt("%.1t", 3u), "11");
    test(#fmt("%.1c", 'A'), "A");
}
fn part4() {
    test(#fmt("%.5d", 0), "00000");
    test(#fmt("%.5u", 0u), "00000");
    test(#fmt("%.5x", 0u), "00000");
    test(#fmt("%.5t", 0u), "00000");
    test(#fmt("%.5d", 10), "00010");
    test(#fmt("%.5d", -10), "-00010");
    test(#fmt("%.5u", 10u), "00010");
    test(#fmt("%.5s", "test"), "test");
    test(#fmt("%.5x", 127u), "0007f");
    test(#fmt("%.5o", 10u), "00012");
    test(#fmt("%.5t", 3u), "00011");
    test(#fmt("%.5c", 'A'), "A");
    // Bool precision. I'm not sure if it's good or bad to have bool
    // conversions support precision - it's not standard printf so we
    // can do whatever. For now I'm making it behave the same as string
    // conversions.

    test(#fmt("%.b", true), "");
    test(#fmt("%.0b", true), "");
    test(#fmt("%.1b", true), "t");
}

fn part5() {
    // Explicit + sign. Only for signed conversions

    test(#fmt("%+d", 0), "+0");
    test(#fmt("%+d", 1), "+1");
    test(#fmt("%+d", -1), "-1");
    // Leave space for sign

    test(#fmt("% d", 0), " 0");
    test(#fmt("% d", 1), " 1");
    test(#fmt("% d", -1), "-1");
    // Plus overrides space

    test(#fmt("% +d", 0), "+0");
    test(#fmt("%+ d", 0), "+0");
    // 0-padding

    test(#fmt("%05d", 0), "00000");
    test(#fmt("%05d", 1), "00001");
    test(#fmt("%05d", -1), "-0001");
    test(#fmt("%05u", 1u), "00001");
    test(#fmt("%05x", 127u), "0007f");
    test(#fmt("%05X", 127u), "0007F");
    test(#fmt("%05o", 10u), "00012");
    test(#fmt("%05t", 3u), "00011");
    // 0-padding a string is undefined but glibc does this:

    test(#fmt("%05s", "test"), " test");
    test(#fmt("%05c", 'A'), "    A");
    test(#fmt("%05b", true), " true");
    // Left-justify overrides 0-padding

    test(#fmt("%-05d", 0), "0    ");
    test(#fmt("%-05d", 1), "1    ");
    test(#fmt("%-05d", -1), "-1   ");
    test(#fmt("%-05u", 1u), "1    ");
    test(#fmt("%-05x", 127u), "7f   ");
    test(#fmt("%-05X", 127u), "7F   ");
    test(#fmt("%-05o", 10u), "12   ");
    test(#fmt("%-05t", 3u), "11   ");
    test(#fmt("%-05s", "test"), "test ");
    test(#fmt("%-05c", 'A'), "A    ");
    test(#fmt("%-05b", true), "true ");
}
fn part6(){
    // Precision overrides 0-padding

    test(#fmt("%06.5d", 0), " 00000");
    test(#fmt("%06.5u", 0u), " 00000");
    test(#fmt("%06.5x", 0u), " 00000");
    test(#fmt("%06.5d", 10), " 00010");
    test(#fmt("%06.5d", -10), "-00010");
    test(#fmt("%06.5u", 10u), " 00010");
    test(#fmt("%06.5s", "test"), "  test");
    test(#fmt("%06.5c", 'A'), "     A");
    test(#fmt("%06.5x", 127u), " 0007f");
    test(#fmt("%06.5X", 127u), " 0007F");
    test(#fmt("%06.5o", 10u), " 00012");
    // Signed combinations

    test(#fmt("% 5d", 1), "    1");
    test(#fmt("% 5d", -1), "   -1");
    test(#fmt("%+5d", 1), "   +1");
    test(#fmt("%+5d", -1), "   -1");
    test(#fmt("% 05d", 1), " 0001");
    test(#fmt("% 05d", -1), "-0001");
    test(#fmt("%+05d", 1), "+0001");
    test(#fmt("%+05d", -1), "-0001");
    test(#fmt("%- 5d", 1), " 1   ");
    test(#fmt("%- 5d", -1), "-1   ");
    test(#fmt("%-+5d", 1), "+1   ");
    test(#fmt("%-+5d", -1), "-1   ");
    test(#fmt("%- 05d", 1), " 1   ");
    test(#fmt("%- 05d", -1), "-1   ");
    test(#fmt("%-+05d", 1), "+1   ");
    test(#fmt("%-+05d", -1), "-1   ");
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use config_builder::{FullNodeConfig, ValidatorConfig};
use libra_config::config::NodeConfig;
use libra_crypto::{
    ed25519::{Ed25519PrivateKey, Ed25519PublicKey},
    test_utils::KeyPair,
};
use parity_multiaddr::Multiaddr;
use std::{
    convert::TryInto,
    fs::{self, File},
    io::Write,
    net::SocketAddr,
    path::PathBuf,
};
use structopt::StructOpt;

const NODE_CONFIG: &str = "node.config.toml";

#[allow(clippy::large_enum_variant)]
#[derive(Debug, StructOpt)]
#[structopt(about = "Tool to create and extend Libra Configs")]
enum Args {
    #[structopt(about = "Generate a Libra faucet key")]
    Faucet(FaucetArgs),
    #[structopt(about = "Create or extend a FullNode network")]
    FullNode(FullNodeCommand),
    #[structopt(about = "Create a new SafetyRules config")]
    SafetyRules(SafetyRulesArgs),
    #[structopt(about = "Create a new validator config")]
    Validator(ValidatorArgs),
}

#[derive(Debug, StructOpt)]
struct FaucetArgs {
    #[structopt(short = "o", long, parse(from_os_str))]
    /// The output directory
    output_dir: PathBuf,
    #[structopt(short = "s", long)]
    /// Use the provided seed for generating keys for each of the validators
    seed: Option<String>,
}

#[derive(Debug, StructOpt)]
enum FullNodeCommand {
    #[structopt(about = "Create a new config")]
    Create(FullNodeArgs),
    #[structopt(about = "Create a new config")]
    Extend(FullNodeArgs),
}

#[derive(Debug, StructOpt)]
struct FullNodeArgs {
    // Describe the validator networrk
    #[structopt(short = "n", long, default_value = "1")]
    /// Specify the number of nodes to configure
    nodes: usize,
    #[structopt(short = "s", long)]
    /// Use the provided seed for generating keys for each of the validators
    seed: Option<String>,

    // Parameters for this full node config
    #[structopt(short = "a", long, parse(from_str = parse_addr))]
    /// Advertised address for this node, if this is null, listen is reused
    advertised: Multiaddr,
    #[structopt(short = "b", long, parse(from_str = parse_addr))]
    /// Advertised address for the first node in this test net
    bootstrap: Multiaddr,
    #[structopt(short = "d", long, parse(from_os_str))]
    /// The data directory for the configs (e.g. /opt/libra/data)
    data_dir: PathBuf,
    #[structopt(short = "c", long)]
    /// Use the provided seed for generating keys for each of the FullNodes
    full_node_seed: Option<String>,
    #[structopt(short = "f", long, default_value = "1")]
    /// Total number of full nodes
    full_nodes: usize,
    #[structopt(short = "i", long, default_value = "0")]
    /// Specify the index into the number of nodes to write to output dir
    index: usize,
    #[structopt(short = "l", long, parse(from_str = parse_addr))]
    /// Listening address for this node
    listen: Multiaddr,
    #[structopt(short = "o", long, parse(from_os_str))]
    /// The output directory, note if a config exists already here, it will be updated to include
    /// this full node network
    output_dir: PathBuf,
    #[structopt(short = "p", long)]
    /// Public network, doesn't use any authentication or encryption
    public: bool,
    #[structopt(short = "t", long, parse(from_os_str))]
    /// Path to a template NodeConfig
    template: Option<PathBuf>,
}

#[derive(Debug, StructOpt)]
struct SafetyRulesArgs {
    #[structopt(flatten)]
    validator_common: ValidatorCommonArgs,
}

#[derive(Debug, StructOpt)]
struct ValidatorArgs {
    #[structopt(short = "a", long, parse(from_str = parse_addr))]
    /// Advertised address for this node, if this is null, listen is reused
    advertised: Multiaddr,
    #[structopt(short = "b", long, parse(from_str = parse_addr))]
    /// Advertised address for the first node in this test net
    bootstrap: Multiaddr,
    #[structopt(short = "l", long, parse(from_str = parse_addr))]
    /// Listening address for this node
    listen: Multiaddr,
    #[structopt(short = "t", long, parse(from_os_str))]
    /// Path to a template NodeConfig
    template: Option<PathBuf>,
    #[structopt(flatten)]
    validator_common: ValidatorCommonArgs,
}

#[derive(Debug, StructOpt)]
struct ValidatorCommonArgs {
    #[structopt(short = "d", long, parse(from_os_str))]
    /// The data directory for the configs (e.g. /opt/libra/etc)
    data_dir: PathBuf,
    #[structopt(short = "i", long, default_value = "0")]
    /// Specify the index into the number of nodes to write to output dir
    index: usize,
    #[structopt(short = "o", long, parse(from_os_str))]
    /// The output directory
    output_dir: PathBuf,
    #[structopt(short = "n", long, default_value = "1")]
    /// Specify the number of nodes to configure
    nodes: usize,
    #[structopt(short = "g", long)]
    /// Specify the number of nodes coded in genesis blob, will use all nodes if unspecified
    nodes_in_genesis: Option<usize>,
    #[structopt(long, parse(from_str = parse_socket_addr))]
    /// Specify the IP:Port for Safety rules. If this is not defined, SafetyRules will run in its
    /// default configuration.
    safety_rules_addr: Option<SocketAddr>,
    /// Specifies the type of backend to use for safety rules: in-memory, on-disk, or vault
    #[structopt(long)]
    safety_rules_backend: Option<String>,
    /// Specifies the host URL for secure storages hosted on remote URLs
    #[structopt(long)]
    safety_rules_host: Option<String>,
    /// Specifies the token for secure storages that use credentials
    #[structopt(long)]
    safety_rules_token: Option<String>,
    /// Specifies a unique namespace for the secure storage
    #[structopt(long)]
    safety_rules_namespace: Option<String>,
    #[structopt(short = "s", long)]
    /// Use the provided seed for generating keys for each of the validators
    seed: Option<String>,
}

fn parse_addr(src: &str) -> Multiaddr {
    src.parse::<Multiaddr>().unwrap()
}

fn parse_socket_addr(src: &str) -> SocketAddr {
    src.parse::<SocketAddr>().unwrap()
}

fn main() {
    let args = Args::from_args();

    match args {
        Args::Faucet(faucet_args) => build_faucet(faucet_args),
        Args::FullNode(full_node_args) => build_full_node(full_node_args),
        Args::SafetyRules(safety_rules_args) => build_safety_rules(safety_rules_args),
        Args::Validator(validator_args) => build_validator(validator_args),
    };
}

fn build_faucet(args: FaucetArgs) {
    let mut config_builder = ValidatorConfig::new();

    if let Some(seed) = args.seed.as_ref() {
        let seed = hex::decode(seed).expect("Invalid hex in seed.");
        config_builder.seed(seed[..32].try_into().expect("Invalid seed"));
    }

    let faucet_key = config_builder.build_faucet_client();
    let key_path = args.output_dir.join("mint.key");
    let faucet_keypair = KeyPair::<Ed25519PrivateKey, Ed25519PublicKey>::from(faucet_key);
    let serialized_keys = lcs::to_bytes(&faucet_keypair).expect("Unable to serialize keys");

    fs::create_dir_all(&args.output_dir).expect("Unable to create output directory");
    let mut key_file = File::create(key_path).expect("Unable to create key file");
    key_file
        .write_all(&serialized_keys)
        .expect("Unable to write to key file");
}

fn build_full_node(command: FullNodeCommand) {
    let config_builder = match &command {
        FullNodeCommand::Create(args) => build_full_node_config_builder(&args),
        FullNodeCommand::Extend(args) => build_full_node_config_builder(&args),
    };

    match command {
        FullNodeCommand::Create(args) => {
            if node_config_exists(&args.output_dir) {
                eprintln!("Node config already exists in this directory");
                return;
            }
            let mut new_config = config_builder.build().expect("ConfigBuilder failed");
            new_config.set_data_dir(args.data_dir);
            save_config(new_config, &args.output_dir);
        }
        FullNodeCommand::Extend(args) => {
            if !node_config_exists(&args.output_dir) {
                eprintln!("No node config in this directory");
                return;
            }

            let config_file = args.output_dir.join(NODE_CONFIG);
            let mut orig_config =
                NodeConfig::load(&config_file).expect("Unable to load node config");
            if orig_config.base.role.is_validator() {
                config_builder
                    .extend_validator(&mut orig_config)
                    .expect("Unable to add full node network to validator");
            } else {
                config_builder
                    .extend(&mut orig_config)
                    .expect("Unable to append full node network");
            }
            save_config(orig_config, &args.output_dir);
        }
    };
}

fn build_full_node_config_builder(args: &FullNodeArgs) -> FullNodeConfig {
    let mut config_builder = FullNodeConfig::new();
    config_builder
        .advertised(args.advertised.clone())
        .bootstrap(args.bootstrap.clone())
        .full_node_index(args.index)
        .full_nodes(args.full_nodes)
        .listen(args.listen.clone())
        .nodes(args.nodes)
        .template(load_template(args.template.clone()));

    if let Some(fn_seed) = args.full_node_seed.as_ref() {
        config_builder.full_node_seed(parse_seed(fn_seed));
    }

    if args.public {
        config_builder.public();
    }

    if let Some(seed) = args.seed.as_ref() {
        config_builder.seed(parse_seed(seed));
    }

    config_builder
}

fn build_safety_rules(args: SafetyRulesArgs) {
    if node_config_exists(&args.validator_common.output_dir) {
        eprintln!("SafetyRules config already exists in this directory");
        return;
    }

    let config_builder = safety_rules_common(&args.validator_common);
    let mut node_config = config_builder.build().expect("ConfigBuilder failed");
    node_config.set_data_dir(args.validator_common.data_dir);
    save_config(node_config, &args.validator_common.output_dir);
}

fn build_validator(args: ValidatorArgs) {
    if node_config_exists(&args.validator_common.output_dir) {
        eprintln!("Node config already exists in this directory");
        return;
    }

    let mut config_builder = safety_rules_common(&args.validator_common);
    config_builder
        .advertised(args.advertised)
        .bootstrap(args.bootstrap)
        .index(args.validator_common.index)
        .listen(args.listen)
        .nodes(args.validator_common.nodes)
        .nodes_in_genesis(args.validator_common.nodes_in_genesis)
        .safety_rules_addr(args.validator_common.safety_rules_addr)
        .safety_rules_backend(args.validator_common.safety_rules_backend)
        .safety_rules_host(args.validator_common.safety_rules_host)
        .safety_rules_namespace(args.validator_common.safety_rules_namespace)
        .safety_rules_token(args.validator_common.safety_rules_token)
        .template(load_template(args.template));

    if let Some(seed) = args.validator_common.seed.as_ref() {
        config_builder.seed(parse_seed(seed));
    }

    let mut node_config = config_builder.build().expect("ConfigBuilder failed");
    node_config.set_data_dir(args.validator_common.data_dir);
    save_config(node_config, &args.validator_common.output_dir);
}

fn safety_rules_common(args: &ValidatorCommonArgs) -> ValidatorConfig {
    let mut config_builder = ValidatorConfig::new();

    config_builder
        .index(args.index)
        .nodes(args.nodes)
        .safety_rules_addr(args.safety_rules_addr.clone())
        .safety_rules_backend(args.safety_rules_backend.clone())
        .safety_rules_host(args.safety_rules_host.clone())
        .safety_rules_namespace(args.safety_rules_namespace.clone())
        .safety_rules_token(args.safety_rules_token.clone());

    if let Some(seed) = args.seed.as_ref() {
        config_builder.seed(parse_seed(seed));
    }

    config_builder
}

fn node_config_exists(output_dir: &PathBuf) -> bool {
    output_dir.join(NODE_CONFIG).exists()
}

fn load_template(template: Option<PathBuf>) -> NodeConfig {
    if let Some(template_path) = template {
        NodeConfig::load(template_path).expect("Unable to load template")
    } else {
        NodeConfig::default()
    }
}

fn parse_seed(seed: &str) -> [u8; 32] {
    let seed = hex::decode(seed).expect("Invalid hex in seed.");
    seed[..32].try_into().expect("Invalid seed")
}

fn save_config(mut node_config: NodeConfig, output_dir: &PathBuf) {
    fs::create_dir_all(output_dir).expect("Unable to create output directory");
    node_config
        .save(output_dir.join(NODE_CONFIG))
        .expect("Unable to save configs");
}
<commit_msg>[config-builder] add template to safety rules<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use config_builder::{FullNodeConfig, ValidatorConfig};
use libra_config::config::NodeConfig;
use libra_crypto::{
    ed25519::{Ed25519PrivateKey, Ed25519PublicKey},
    test_utils::KeyPair,
};
use parity_multiaddr::Multiaddr;
use std::{
    convert::TryInto,
    fs::{self, File},
    io::Write,
    net::SocketAddr,
    path::PathBuf,
};
use structopt::StructOpt;

const NODE_CONFIG: &str = "node.config.toml";

#[allow(clippy::large_enum_variant)]
#[derive(Debug, StructOpt)]
#[structopt(about = "Tool to create and extend Libra Configs")]
enum Args {
    #[structopt(about = "Generate a Libra faucet key")]
    Faucet(FaucetArgs),
    #[structopt(about = "Create or extend a FullNode network")]
    FullNode(FullNodeCommand),
    #[structopt(about = "Create a new SafetyRules config")]
    SafetyRules(SafetyRulesArgs),
    #[structopt(about = "Create a new validator config")]
    Validator(ValidatorArgs),
}

#[derive(Debug, StructOpt)]
struct FaucetArgs {
    #[structopt(short = "o", long, parse(from_os_str))]
    /// The output directory
    output_dir: PathBuf,
    #[structopt(short = "s", long)]
    /// Use the provided seed for generating keys for each of the validators
    seed: Option<String>,
}

#[derive(Debug, StructOpt)]
enum FullNodeCommand {
    #[structopt(about = "Create a new config")]
    Create(FullNodeArgs),
    #[structopt(about = "Create a new config")]
    Extend(FullNodeArgs),
}

#[derive(Debug, StructOpt)]
struct FullNodeArgs {
    // Describe the validator networrk
    #[structopt(short = "n", long, default_value = "1")]
    /// Specify the number of nodes to configure
    nodes: usize,
    #[structopt(short = "s", long)]
    /// Use the provided seed for generating keys for each of the validators
    seed: Option<String>,

    // Parameters for this full node config
    #[structopt(short = "a", long, parse(from_str = parse_addr))]
    /// Advertised address for this node, if this is null, listen is reused
    advertised: Multiaddr,
    #[structopt(short = "b", long, parse(from_str = parse_addr))]
    /// Advertised address for the first node in this test net
    bootstrap: Multiaddr,
    #[structopt(short = "d", long, parse(from_os_str))]
    /// The data directory for the configs (e.g. /opt/libra/data)
    data_dir: PathBuf,
    #[structopt(short = "c", long)]
    /// Use the provided seed for generating keys for each of the FullNodes
    full_node_seed: Option<String>,
    #[structopt(short = "f", long, default_value = "1")]
    /// Total number of full nodes
    full_nodes: usize,
    #[structopt(short = "i", long, default_value = "0")]
    /// Specify the index into the number of nodes to write to output dir
    index: usize,
    #[structopt(short = "l", long, parse(from_str = parse_addr))]
    /// Listening address for this node
    listen: Multiaddr,
    #[structopt(short = "o", long, parse(from_os_str))]
    /// The output directory, note if a config exists already here, it will be updated to include
    /// this full node network
    output_dir: PathBuf,
    #[structopt(short = "p", long)]
    /// Public network, doesn't use any authentication or encryption
    public: bool,
    #[structopt(short = "t", long, parse(from_os_str))]
    /// Path to a template NodeConfig
    template: Option<PathBuf>,
}

#[derive(Debug, StructOpt)]
struct SafetyRulesArgs {
    #[structopt(flatten)]
    validator_common: ValidatorCommonArgs,
}

#[derive(Debug, StructOpt)]
struct ValidatorArgs {
    #[structopt(short = "a", long, parse(from_str = parse_addr))]
    /// Advertised address for this node, if this is null, listen is reused
    advertised: Multiaddr,
    #[structopt(short = "b", long, parse(from_str = parse_addr))]
    /// Advertised address for the first node in this test net
    bootstrap: Multiaddr,
    #[structopt(short = "l", long, parse(from_str = parse_addr))]
    /// Listening address for this node
    listen: Multiaddr,
    #[structopt(flatten)]
    validator_common: ValidatorCommonArgs,
}

#[derive(Debug, StructOpt)]
struct ValidatorCommonArgs {
    #[structopt(short = "d", long, parse(from_os_str))]
    /// The data directory for the configs (e.g. /opt/libra/etc)
    data_dir: PathBuf,
    #[structopt(short = "i", long, default_value = "0")]
    /// Specify the index into the number of nodes to write to output dir
    index: usize,
    #[structopt(short = "o", long, parse(from_os_str))]
    /// The output directory
    output_dir: PathBuf,
    #[structopt(short = "n", long, default_value = "1")]
    /// Specify the number of nodes to configure
    nodes: usize,
    #[structopt(short = "g", long)]
    /// Specify the number of nodes coded in genesis blob, will use all nodes if unspecified
    nodes_in_genesis: Option<usize>,
    #[structopt(long, parse(from_str = parse_socket_addr))]
    /// Specify the IP:Port for Safety rules. If this is not defined, SafetyRules will run in its
    /// default configuration.
    safety_rules_addr: Option<SocketAddr>,
    /// Specifies the type of backend to use for safety rules: in-memory, on-disk, or vault
    #[structopt(long)]
    safety_rules_backend: Option<String>,
    /// Specifies the host URL for secure storages hosted on remote URLs
    #[structopt(long)]
    safety_rules_host: Option<String>,
    /// Specifies the token for secure storages that use credentials
    #[structopt(long)]
    safety_rules_token: Option<String>,
    /// Specifies a unique namespace for the secure storage
    #[structopt(long)]
    safety_rules_namespace: Option<String>,
    #[structopt(short = "s", long)]
    /// Use the provided seed for generating keys for each of the validators
    seed: Option<String>,
    #[structopt(short = "t", long, parse(from_os_str))]
    /// Path to a template NodeConfig
    template: Option<PathBuf>,
}

fn parse_addr(src: &str) -> Multiaddr {
    src.parse::<Multiaddr>().unwrap()
}

fn parse_socket_addr(src: &str) -> SocketAddr {
    src.parse::<SocketAddr>().unwrap()
}

fn main() {
    let args = Args::from_args();

    match args {
        Args::Faucet(faucet_args) => build_faucet(faucet_args),
        Args::FullNode(full_node_args) => build_full_node(full_node_args),
        Args::SafetyRules(safety_rules_args) => build_safety_rules(safety_rules_args),
        Args::Validator(validator_args) => build_validator(validator_args),
    };
}

fn build_faucet(args: FaucetArgs) {
    let mut config_builder = ValidatorConfig::new();

    if let Some(seed) = args.seed.as_ref() {
        let seed = hex::decode(seed).expect("Invalid hex in seed.");
        config_builder.seed(seed[..32].try_into().expect("Invalid seed"));
    }

    let faucet_key = config_builder.build_faucet_client();
    let key_path = args.output_dir.join("mint.key");
    let faucet_keypair = KeyPair::<Ed25519PrivateKey, Ed25519PublicKey>::from(faucet_key);
    let serialized_keys = lcs::to_bytes(&faucet_keypair).expect("Unable to serialize keys");

    fs::create_dir_all(&args.output_dir).expect("Unable to create output directory");
    let mut key_file = File::create(key_path).expect("Unable to create key file");
    key_file
        .write_all(&serialized_keys)
        .expect("Unable to write to key file");
}

fn build_full_node(command: FullNodeCommand) {
    let config_builder = match &command {
        FullNodeCommand::Create(args) => build_full_node_config_builder(&args),
        FullNodeCommand::Extend(args) => build_full_node_config_builder(&args),
    };

    match command {
        FullNodeCommand::Create(args) => {
            if node_config_exists(&args.output_dir) {
                eprintln!("Node config already exists in this directory");
                return;
            }
            let mut new_config = config_builder.build().expect("ConfigBuilder failed");
            new_config.set_data_dir(args.data_dir);
            save_config(new_config, &args.output_dir);
        }
        FullNodeCommand::Extend(args) => {
            if !node_config_exists(&args.output_dir) {
                eprintln!("No node config in this directory");
                return;
            }

            let config_file = args.output_dir.join(NODE_CONFIG);
            let mut orig_config =
                NodeConfig::load(&config_file).expect("Unable to load node config");
            if orig_config.base.role.is_validator() {
                config_builder
                    .extend_validator(&mut orig_config)
                    .expect("Unable to add full node network to validator");
            } else {
                config_builder
                    .extend(&mut orig_config)
                    .expect("Unable to append full node network");
            }
            save_config(orig_config, &args.output_dir);
        }
    };
}

fn build_full_node_config_builder(args: &FullNodeArgs) -> FullNodeConfig {
    let mut config_builder = FullNodeConfig::new();
    config_builder
        .advertised(args.advertised.clone())
        .bootstrap(args.bootstrap.clone())
        .full_node_index(args.index)
        .full_nodes(args.full_nodes)
        .listen(args.listen.clone())
        .nodes(args.nodes)
        .template(load_template(args.template.as_ref()));

    if let Some(fn_seed) = args.full_node_seed.as_ref() {
        config_builder.full_node_seed(parse_seed(fn_seed));
    }

    if args.public {
        config_builder.public();
    }

    if let Some(seed) = args.seed.as_ref() {
        config_builder.seed(parse_seed(seed));
    }

    config_builder
}

fn build_safety_rules(args: SafetyRulesArgs) {
    if node_config_exists(&args.validator_common.output_dir) {
        eprintln!("SafetyRules config already exists in this directory");
        return;
    }

    let config_builder = safety_rules_common(&args.validator_common);
    let mut node_config = config_builder.build().expect("ConfigBuilder failed");
    node_config.set_data_dir(args.validator_common.data_dir);
    save_config(node_config, &args.validator_common.output_dir);
}

fn build_validator(args: ValidatorArgs) {
    if node_config_exists(&args.validator_common.output_dir) {
        eprintln!("Node config already exists in this directory");
        return;
    }

    let mut config_builder = safety_rules_common(&args.validator_common);
    config_builder
        .advertised(args.advertised)
        .bootstrap(args.bootstrap)
        .index(args.validator_common.index)
        .listen(args.listen)
        .nodes(args.validator_common.nodes)
        .nodes_in_genesis(args.validator_common.nodes_in_genesis);

    if let Some(seed) = args.validator_common.seed.as_ref() {
        config_builder.seed(parse_seed(seed));
    }

    let mut node_config = config_builder.build().expect("ConfigBuilder failed");
    node_config.set_data_dir(args.validator_common.data_dir);
    save_config(node_config, &args.validator_common.output_dir);
}

fn safety_rules_common(args: &ValidatorCommonArgs) -> ValidatorConfig {
    let mut config_builder = ValidatorConfig::new();

    config_builder
        .index(args.index)
        .nodes(args.nodes)
        .safety_rules_addr(args.safety_rules_addr.clone())
        .safety_rules_backend(args.safety_rules_backend.clone())
        .safety_rules_host(args.safety_rules_host.clone())
        .safety_rules_namespace(args.safety_rules_namespace.clone())
        .safety_rules_token(args.safety_rules_token.clone())
        .template(load_template(args.template.as_ref()));

    if let Some(seed) = args.seed.as_ref() {
        config_builder.seed(parse_seed(seed));
    }

    config_builder
}

fn node_config_exists(output_dir: &PathBuf) -> bool {
    output_dir.join(NODE_CONFIG).exists()
}

fn load_template(template: Option<&PathBuf>) -> NodeConfig {
    if let Some(template_path) = template {
        NodeConfig::load(template_path).expect("Unable to load template")
    } else {
        NodeConfig::default()
    }
}

fn parse_seed(seed: &str) -> [u8; 32] {
    let seed = hex::decode(seed).expect("Invalid hex in seed.");
    seed[..32].try_into().expect("Invalid seed")
}

fn save_config(mut node_config: NodeConfig, output_dir: &PathBuf) {
    fs::create_dir_all(output_dir).expect("Unable to create output directory");
    node_config
        .save(output_dir.join(NODE_CONFIG))
        .expect("Unable to save configs");
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cargo;
mod error;
mod gen;
mod paths;
mod syntax;

use crate::error::Result;
use crate::gen::error::report;
use crate::gen::{fs, Opt};
use crate::paths::TargetDir;
use cc::Build;
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    out_dir: PathBuf,
    target_dir: TargetDir,
}

impl Project {
    fn init() -> Result<Self> {
        let out_dir = paths::out_dir()?;

        let target_dir = match cargo::target_dir() {
            target_dir @ TargetDir::Path(_) => target_dir,
            // Fallback if Cargo did not work.
            TargetDir::Unknown => paths::search_parents_for_target_dir(&out_dir),
        };

        Ok(Project {
            out_dir,
            target_dir,
        })
    }
}

fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;
    let mut build = paths::cc_build(prj);
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate
    write_header(prj);

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    Ok(build)
}

fn write_header(prj: &Project) {
    let ref cxx_h = paths::include_dir(prj).join("rust").join("cxx.h");
    let _ = write(cxx_h, gen::include::HEADER.as_bytes());
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt::default();
    let generated = gen::generate_from_path(rust_source_file, &opt);

    let header_path = paths::out_with_extension(prj, rust_source_file, ".h")?;
    fs::create_dir_all(header_path.parent().unwrap())?;
    write(&header_path, &generated.header)?;
    paths::symlink_header(prj, &header_path, rust_source_file);

    let implementation_path = paths::out_with_extension(prj, rust_source_file, ".cc")?;
    write(&implementation_path, &generated.implementation)?;
    build.file(&implementation_path);
    Ok(())
}

fn write(path: &Path, content: &[u8]) -> Result<()> {
    if path.exists() {
        if let Ok(existing) = fs::read(path) {
            if existing == content {
                // Avoid bumping modified time with unchanged contents.
                return Ok(());
            }
        }
        let _ = fs::remove_file(path);
    } else {
        let _ = fs::create_dir_all(path.parent().unwrap());
    }
    fs::write(path, content)?;
    Ok(())
}
<commit_msg>Remove redundant create_dir_all<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cargo;
mod error;
mod gen;
mod paths;
mod syntax;

use crate::error::Result;
use crate::gen::error::report;
use crate::gen::{fs, Opt};
use crate::paths::TargetDir;
use cc::Build;
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    out_dir: PathBuf,
    target_dir: TargetDir,
}

impl Project {
    fn init() -> Result<Self> {
        let out_dir = paths::out_dir()?;

        let target_dir = match cargo::target_dir() {
            target_dir @ TargetDir::Path(_) => target_dir,
            // Fallback if Cargo did not work.
            TargetDir::Unknown => paths::search_parents_for_target_dir(&out_dir),
        };

        Ok(Project {
            out_dir,
            target_dir,
        })
    }
}

fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;
    let mut build = paths::cc_build(prj);
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate
    write_header(prj);

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    Ok(build)
}

fn write_header(prj: &Project) {
    let ref cxx_h = paths::include_dir(prj).join("rust").join("cxx.h");
    let _ = write(cxx_h, gen::include::HEADER.as_bytes());
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt::default();
    let generated = gen::generate_from_path(rust_source_file, &opt);

    let header_path = paths::out_with_extension(prj, rust_source_file, ".h")?;
    write(&header_path, &generated.header)?;
    paths::symlink_header(prj, &header_path, rust_source_file);

    let implementation_path = paths::out_with_extension(prj, rust_source_file, ".cc")?;
    write(&implementation_path, &generated.implementation)?;
    build.file(&implementation_path);
    Ok(())
}

fn write(path: &Path, content: &[u8]) -> Result<()> {
    if path.exists() {
        if let Ok(existing) = fs::read(path) {
            if existing == content {
                // Avoid bumping modified time with unchanged contents.
                return Ok(());
            }
        }
        let _ = fs::remove_file(path);
    } else {
        let _ = fs::create_dir_all(path.parent().unwrap());
    }
    fs::write(path, content)?;
    Ok(())
}
<|endoftext|>


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

// min-lldb-version: 310
// ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run

// gdb-command:print x
// gdb-check:$1 = false
// gdb-command:print y
// gdb-check:$2 = true
// gdb-command:continue

// gdb-command:print x
// gdb-check:$3 = 10
// gdb-command:print y
// gdb-check:$4 = true
// gdb-command:continue

// gdb-command:print x
// gdb-check:$5 = 10.5
// gdb-command:print y
// gdb-check:$6 = 20
// gdb-command:continue

// gdb-command:print x
// gdb-check:$5 = 10.5
// gdb-command:print y
// gdb-check:$6 = 20
// gdb-command:continue

// gdb-command:print x
// gdb-check:$5 = 11.5
// gdb-command:print y
// gdb-check:$6 = 20
// gdb-command:continue

// === LLDB TESTS ==================================================================================

// lldb-command:run

// lldb-command:print x
// lldb-check:[...]$0 = false
// lldb-command:print y
// lldb-check:[...]$1 = true
// lldb-command:continue

// lldb-command:print x
// lldb-check:[...]$2 = 10
// lldb-command:print y
// lldb-check:[...]$3 = true
// lldb-command:continue

// lldb-command:print x
// lldb-check:[...]$4 = 10.5
// lldb-command:print y
// lldb-check:[...]$5 = 20
// lldb-command:continue

// lldb-command:print x
// lldb-check:[...]$4 = 10.5
// lldb-command:print y
// lldb-check:[...]$5 = 20
// lldb-command:continue

// lldb-command:print x
// lldb-check:[...]$4 = 11.5
// lldb-command:print y
// lldb-check:[...]$5 = 20
// lldb-command:continue

#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]

fn main() {
    let x = false;
    let y = true;

    zzz(); // #break
    sentinel();

    let x = 10;

    zzz(); // #break
    sentinel();

    let x = 10.5f64;
    let y = 20;

    zzz(); // #break
    sentinel();

    let x = {
        zzz(); // #break
        sentinel();
        11.5
    };

    zzz(); // #break
    sentinel()
}

fn zzz() {()}
fn sentinel() {()}
<commit_msg>Debuginfo Shadowed Variable test: fix check numbering<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// min-lldb-version: 310
// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run

// gdb-command:print x
// gdb-check:$1 = false
// gdb-command:print y
// gdb-check:$2 = true
// gdb-command:continue

// gdb-command:print x
// gdb-check:$3 = 10
// gdb-command:print y
// gdb-check:$4 = true
// gdb-command:continue

// gdb-command:print x
// gdb-check:$5 = 10.5
// gdb-command:print y
// gdb-check:$6 = 20
// gdb-command:continue

// gdb-command:print x
// gdb-check:$7 = 10.5
// gdb-command:print y
// gdb-check:$8 = 20
// gdb-command:continue

// gdb-command:print x
// gdb-check:$9 = 11.5
// gdb-command:print y
// gdb-check:$10 = 20
// gdb-command:continue

// === LLDB TESTS ==================================================================================

// lldb-command:run

// lldb-command:print x
// lldb-check:[...]$0 = false
// lldb-command:print y
// lldb-check:[...]$1 = true
// lldb-command:continue

// lldb-command:print x
// lldb-check:[...]$2 = 10
// lldb-command:print y
// lldb-check:[...]$3 = true
// lldb-command:continue

// lldb-command:print x
// lldb-check:[...]$4 = 10.5
// lldb-command:print y
// lldb-check:[...]$5 = 20
// lldb-command:continue

// lldb-command:print x
// lldb-check:[...]$6 = 10.5
// lldb-command:print y
// lldb-check:[...]$7 = 20
// lldb-command:continue

// lldb-command:print x
// lldb-check:[...]$8 = 11.5
// lldb-command:print y
// lldb-check:[...]$9 = 20
// lldb-command:continue

#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]

fn main() {
    let x = false;
    let y = true;

    zzz(); // #break
    sentinel();

    let x = 10;

    zzz(); // #break
    sentinel();

    let x = 10.5f64;
    let y = 20;

    zzz(); // #break
    sentinel();

    let x = {
        zzz(); // #break
        sentinel();
        11.5
    };

    zzz(); // #break
    sentinel()
}

fn zzz() {()}
fn sentinel() {()}
<|endoftext|>


<commit_before>#![allow(deprecated)]
use std::path::PathBuf;
use std::{io, fs, slice};
use curl::easy::Easy;
use memmap::{Mmap, Protection};
use flate2::{Flush, Decompress};
use std::io::Write;
use utils::data::{DatasetIntfRef, DatasetIntf};
use std::rc::Rc;
use tensor::{Tensor, TensorKind, NumLimits};
use torch;
use std::marker::PhantomData;

type Sample<T> = (Tensor<T>, i64);
type CollatedSample<T> = (Tensor<T>, Tensor<i64>);

static URLS: [&str; 4] = ["http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"];
static RAW_FOLDER: &str = "raw";
static PROCESSED_FOLDER: &str = "processed";
static TRAINING_FILE: &str = "training.pt";
static TEST_FILE: &str = "test.pt";

fn create_dir_f(arg: PathBuf) -> io::Result<()> {
    let result = fs::create_dir(arg);
    if let Some(err) = result.err() {
        match err.kind() {
            io::ErrorKind::AlreadyExists => Ok(()),
            _ => Err(err),
        }
    } else {
        Ok(())
    }
}

fn check_exists(arg: &PathBuf) -> io::Result<bool> {
    let train = fs::metadata(arg.join(TRAINING_FILE))?;
    let test = fs::metadata(arg.join(TEST_FILE))?;

    return Ok(train.is_file() && test.is_file());
}

fn download(root: &String) -> io::Result<()> {
    let raw_path = PathBuf::from(root).join(RAW_FOLDER);
    let processed_path = PathBuf::from(root).join(PROCESSED_FOLDER);
    create_dir_f(raw_path.clone())?;
    create_dir_f(processed_path.clone())?;

    for url in URLS.iter() {
        println!("downloading {}", url);
        let paths: Vec<_> = url.split("/").collect();
        let fname: Vec<_> = paths[5].split("/").collect();
        let file_path = raw_path.join(fname[0]);
        let mut file = fs::OpenOptions::new()
            .write(true)
            .create(true)
            .open(file_path)?;
        let mut data = Vec::new();
        let mut handle = Easy::new();
        handle.url(url).unwrap();
        {
            let mut transfer = handle.transfer();
            transfer
                .write_function(|new_data| {
                                    data.extend_from_slice(new_data);
                                    Ok(new_data.len())
                                })
                .unwrap();
            transfer.perform().unwrap();
        }
        let mut output = Vec::with_capacity(data.len());
        // do we have a header?
        Decompress::new(false)
            .decompress_vec(data.as_slice(), &mut output, Flush::Finish)?;
        file.write_all(output.as_slice())?;
    }
    println!("Proceeding");

    let training_set =
        vec![read_image_file(raw_path.join("train-images-idx3-ubyte"))?,
                            read_label_file(raw_path.join("train-labels-idx1-ubyte"))?];
    let test_set = vec![read_image_file(raw_path.join("t10k-images-idx3-ubyte"))?,
                        read_label_file(raw_path.join("t10k-labels-idx1-ubyte"))?];

    torch::save(processed_path.join(TRAINING_FILE), &training_set)?;
    torch::save(processed_path.join(TEST_FILE), &test_set)?;

    Ok(())
}

fn read_image_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let (length, nrows, ncols);
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const u32, fp.len()) };
        assert_eq!(data[0], 2051);
        length = data[1] as usize;
        nrows = data[2] as usize;
        ncols = data[3] as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut images: Vec<Vec<u8>> = Vec::with_capacity(length);
    let mut idx = 16;
    for _ in 0..length {
        let mut img = Vec::with_capacity(nrows * ncols);
        for _ in 0..nrows * ncols {
            img.push(data[idx]);
            idx += 1;
        }
        images.push(img)
    }
    Ok(torch::byte_tensor(images).view(&[-1, 28, 28]).into())
}

fn read_label_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let length;
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const u32, fp.len()) };
        assert_eq!(data[0], 2049);
        length = data[1] as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut labels: Vec<u8> = Vec::with_capacity(length);
    for i in 0..length {
        labels.push(data[8 + i])
    }
    Ok(torch::byte_tensor(labels).into())
}

pub struct MNIST<T: NumLimits> {
    pub root: String,
    pub train: bool,
    pub data: Tensor<u8>,
    pub labels: Tensor<u8>,
    pub transform: Option<Xfrm>,
    phantom: PhantomData<T>,
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct MNISTArgs {
    root: String,
    #[builder(default="true")]
    train: bool,
    #[builder(default="false")]
    download: bool,
}

type Xfrm = Box<fn(&TensorKind) -> TensorKind>;
impl MNISTArgsBuilder {
    pub fn done<T: NumLimits + 'static>(self,
                                        xfrm: Option<Xfrm>)
                                        -> DatasetIntfRef<CollatedSample<T>> {
        let args = self.build().unwrap();
        Rc::new(MNIST::new(args, xfrm))
    }
}

impl<T: NumLimits> MNIST<T> {
    pub fn build(root: &str) -> MNISTArgsBuilder {
        MNISTArgsBuilder::default().root(root.into())
    }
    pub fn new(args: MNISTArgs, xfrm: Option<Xfrm>) -> Self {
        if args.download {
            download(&args.root).expect("download failed");
        }
        let processed_path = PathBuf::from(&args.root).join(PROCESSED_FOLDER);
        if !check_exists(&processed_path).expect("Dataset not found, try downloading") {
            panic!("Dataset not found, use download=true to download it");
        }
        let mut v: Vec<TensorKind> = if args.train {
            torch::load(processed_path.join(TRAINING_FILE)).expect("torch load failed")
        } else {
            torch::load(processed_path.join(TEST_FILE)).expect("torch load failed")
        };
        let (data, labels) = (v.remove(0), v.remove(0));

        MNIST {
            root: args.root.clone(),
            train: args.train,
            data: data.into(),
            labels: labels.into(),
            transform: xfrm,
            phantom: PhantomData,
        }
    }
    fn index(&self, idx: usize) -> Sample<T> {
        let img = self.data.s(idx);
        let img = if let Some(ref transform) = self.transform {
            transform(&img.into()).into()
        } else {
            img.copy().cast::<T>()
        };
        (img, self.labels[idx].clone() as i64)
    }
}

impl<T: NumLimits> DatasetIntf for MNIST<T> {
    type Batch = CollatedSample<T>;
    fn len(&self) -> usize {
        if self.train { 60000 } else { 10000 }
    }
    fn collate(&self, sample: Vec<usize>) -> Self::Batch {
        let v: Vec<Sample<T>> = sample.into_iter().map(|i| self.index(i)).collect();
        let labels: Vec<i64> = v.iter().map(|&(_, ref t)| *t).collect();
        let imgs: Vec<Tensor<T>> = v.into_iter().map(|(d, _)| d).collect();
        // XXX should check for case of double
        let img_batch = torch::tensor(imgs);
        let label_batch = torch::long_tensor(labels);
        (img_batch, label_batch)
    }
}
<commit_msg>fix data decode issues<commit_after>#![allow(deprecated)]
use std::path::PathBuf;
use std::{io, fs, slice};
use curl::easy::Easy;
use memmap::{Mmap, Protection};
use flate2::{Flush, Decompress};
use std::io::{Read, Write};
use utils::data::{DatasetIntfRef, DatasetIntf};
use std::rc::Rc;
use tensor::{Tensor, TensorKind, NumLimits};
use torch;
use std::marker::PhantomData;

type Sample<T> = (Tensor<T>, i64);
type CollatedSample<T> = (Tensor<T>, Tensor<i64>);

static URLS: [&str; 4] = ["http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"];
static RAW_FOLDER: &str = "raw";
static PROCESSED_FOLDER: &str = "processed";
static TRAINING_FILE: &str = "training.pt";
static TEST_FILE: &str = "test.pt";

fn create_dir_f(arg: PathBuf) -> io::Result<()> {
    let result = fs::create_dir(arg);
    if let Some(err) = result.err() {
        match err.kind() {
            io::ErrorKind::AlreadyExists => Ok(()),
            _ => Err(err),
        }
    } else {
        Ok(())
    }
}

fn check_exists(arg: &PathBuf) -> io::Result<bool> {
    let train = fs::metadata(arg.join(TRAINING_FILE))?;
    let test = fs::metadata(arg.join(TEST_FILE))?;

    return Ok(train.is_file() && test.is_file());
}

fn download(root: &String) -> io::Result<()> {
    let raw_path = PathBuf::from(root).join(RAW_FOLDER);
    let processed_path = PathBuf::from(root).join(PROCESSED_FOLDER);
    create_dir_f(raw_path.clone())?;
    create_dir_f(processed_path.clone())?;

    for url in URLS.iter() {
        println!("downloading {}", url);
        let paths: Vec<_> = url.split("/").collect();
        let mut fname: Vec<_> = paths[5].split("/").collect();
        fname = fname[0].split(".").collect();
        let file_path = raw_path.join(fname[0]);
        let mut file = fs::OpenOptions::new()
            .write(true)
            .create(true)
            .open(file_path)?;
        let mut data = Vec::new();
        let mut handle = Easy::new();
        handle.url(url).unwrap();
        {
            let mut transfer = handle.transfer();
            transfer
                .write_function(|new_data| {
                                    data.extend_from_slice(new_data);
                                    Ok(new_data.len())
                                })
                .unwrap();
            transfer.perform().unwrap();
        }
        let mut output = Vec::with_capacity(data.len() + 1100000);
        let mut gz = ::flate2::read::GzDecoder::new(data.as_slice())?;
        gz.read_to_end(&mut output)?;

        file.write_all(output.as_slice())?;
    }
    println!("Proceeding");

    let training_set =
        vec![read_image_file(raw_path.join("train-images-idx3-ubyte"))?,
                            read_label_file(raw_path.join("train-labels-idx1-ubyte"))?];
    let test_set = vec![read_image_file(raw_path.join("t10k-images-idx3-ubyte"))?,
                        read_label_file(raw_path.join("t10k-labels-idx1-ubyte"))?];

    torch::save(processed_path.join(TRAINING_FILE), &training_set)?;
    torch::save(processed_path.join(TEST_FILE), &test_set)?;

    Ok(())
}

fn read_image_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let (length, nrows, ncols);
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const i32, fp.len()) };
        assert_eq!(i32::from_be(data[0]), 2051);
        length = i32::from_be(data[1]) as usize;
        nrows = i32::from_be(data[2]) as usize;
        ncols = i32::from_be(data[3]) as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut images: Vec<Vec<u8>> = Vec::with_capacity(length);
    let mut idx = 16;
    for _ in 0..length {
        let mut img = Vec::with_capacity(nrows * ncols);
        for _ in 0..nrows * ncols {
            img.push(data[idx]);
            idx += 1;
        }
        images.push(img)
    }
    Ok(torch::byte_tensor(images).view(&[-1, 28, 28]).into())
}

fn read_label_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let length;
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const u32, fp.len()) };
        assert_eq!(data[0], 2049);
        length = data[1] as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut labels: Vec<u8> = Vec::with_capacity(length);
    for i in 0..length {
        labels.push(data[8 + i])
    }
    Ok(torch::byte_tensor(labels).into())
}

pub struct MNIST<T: NumLimits> {
    pub root: String,
    pub train: bool,
    pub data: Tensor<u8>,
    pub labels: Tensor<u8>,
    pub transform: Option<Xfrm>,
    phantom: PhantomData<T>,
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct MNISTArgs {
    root: String,
    #[builder(default="true")]
    train: bool,
    #[builder(default="false")]
    download: bool,
}

type Xfrm = Box<fn(&TensorKind) -> TensorKind>;
impl MNISTArgsBuilder {
    pub fn done<T: NumLimits + 'static>(self,
                                        xfrm: Option<Xfrm>)
                                        -> DatasetIntfRef<CollatedSample<T>> {
        let args = self.build().unwrap();
        Rc::new(MNIST::new(args, xfrm))
    }
}

impl<T: NumLimits> MNIST<T> {
    pub fn build(root: &str) -> MNISTArgsBuilder {
        MNISTArgsBuilder::default().root(root.into())
    }
    pub fn new(args: MNISTArgs, xfrm: Option<Xfrm>) -> Self {
        if args.download {
            download(&args.root).expect("download failed");
        }
        let processed_path = PathBuf::from(&args.root).join(PROCESSED_FOLDER);
        if !check_exists(&processed_path).expect("Dataset not found, try downloading") {
            panic!("Dataset not found, use download=true to download it");
        }
        let mut v: Vec<TensorKind> = if args.train {
            torch::load(processed_path.join(TRAINING_FILE)).expect("torch load failed")
        } else {
            torch::load(processed_path.join(TEST_FILE)).expect("torch load failed")
        };
        let (data, labels) = (v.remove(0), v.remove(0));

        MNIST {
            root: args.root.clone(),
            train: args.train,
            data: data.into(),
            labels: labels.into(),
            transform: xfrm,
            phantom: PhantomData,
        }
    }
    fn index(&self, idx: usize) -> Sample<T> {
        let img = self.data.s(idx);
        let img = if let Some(ref transform) = self.transform {
            transform(&img.into()).into()
        } else {
            img.copy().cast::<T>()
        };
        (img, self.labels[idx].clone() as i64)
    }
}

impl<T: NumLimits> DatasetIntf for MNIST<T> {
    type Batch = CollatedSample<T>;
    fn len(&self) -> usize {
        if self.train { 60000 } else { 10000 }
    }
    fn collate(&self, sample: Vec<usize>) -> Self::Batch {
        let v: Vec<Sample<T>> = sample.into_iter().map(|i| self.index(i)).collect();
        let labels: Vec<i64> = v.iter().map(|&(_, ref t)| *t).collect();
        let imgs: Vec<Tensor<T>> = v.into_iter().map(|(d, _)| d).collect();
        // XXX should check for case of double
        let img_batch = torch::tensor(imgs);
        let label_batch = torch::long_tensor(labels);
        (img_batch, label_batch)
    }
}
<|endoftext|>


<commit_before>//! Module for built-in filter functions
//!
//! Contains all the built-in filter functions for use in templates.
//! Currently, there is no way to define filters outside this module.

#[cfg(feature = "serde-json")]
mod json;

#[cfg(feature = "serde-json")]
pub use self::json::json;

use std::fmt;

use super::Result;
use escaping::{self, MarkupDisplay};

// This is used by the code generator to decide whether a named filter is part of
// Askama or should refer to a local `filters` module. It should contain all the
// filters shipped with Askama, even the optional ones (since optional inclusion
// in the const vector based on features seems impossible right now).
pub const BUILT_IN_FILTERS: [&str; 12] = [
    "e",
    "escape",
    "format",
    "join",
    "lower",
    "lowercase",
    "safe",
    "trim",
    "truncate",
    "upper",
    "uppercase",
    "json", // Optional feature; reserve the name anyway
];

pub fn safe<D, I>(v: I) -> Result<MarkupDisplay<D>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    let res: MarkupDisplay<D> = v.into();
    Ok(res.mark_safe())
}

/// Escapes `&`, `<` and `>` in strings
pub fn escape<D, I>(i: I) -> Result<MarkupDisplay<String>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    let md: MarkupDisplay<D> = i.into();
    Ok(MarkupDisplay::Safe(escaping::escape(md.unsafe_string())))
}

/// Alias for the `escape()` filter
pub fn e<D, I>(i: I) -> Result<MarkupDisplay<String>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    escape(i)
}

/// Formats arguments according to the specified format
///
/// The first argument to this filter must be a string literal (as in normal
/// Rust). All arguments are passed through to the `format!()`
/// [macro](https://doc.rust-lang.org/stable/std/macro.format.html) by
/// the Askama code generator.
pub fn format() {}

/// Converts to lowercase.
pub fn lower(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.to_lowercase())
}

/// Alias for the `lower()` filter.
pub fn lowercase(s: &fmt::Display) -> Result<String> {
    lower(s)
}

/// Converts to uppercase.
pub fn upper(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.to_uppercase())
}

/// Alias for the `upper()` filter.
pub fn uppercase(s: &fmt::Display) -> Result<String> {
    upper(s)
}

/// Strip leading and trailing whitespace.
pub fn trim(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.trim().to_owned())
}

/// Limit string length, appens '...' if truncated {
pub fn truncate(s: &fmt::Display, len: &usize) -> Result<String> {
    let mut s = format!("{}", s);
    if s.len() < *len {
        Ok(s)
    } else {
        s.truncate(*len);
        s.push_str("...");
        Ok(s)
    }
}

/// Joins iterable into a string separated by provided argument
pub fn join<T, I, S>(input: I, separator: S) -> Result<String>
where
    T: fmt::Display,
    I: Iterator<Item = T>,
    S: AsRef<str>,
{
    let separator: &str = separator.as_ref();

    let mut rv = String::new();

    for (num, item) in input.enumerate() {
        if num > 0 {
            rv.push_str(separator);
        }

        rv.push_str(&format!("{}", item));
    }

    Ok(rv)
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_lower() {
        assert_eq!(lower(&"Foo").unwrap(), "foo");
        assert_eq!(lower(&"FOO").unwrap(), "foo");
        assert_eq!(lower(&"FooBar").unwrap(), "foobar");
        assert_eq!(lower(&"foo").unwrap(), "foo");
    }

    #[test]
    fn test_upper() {
        assert_eq!(upper(&"Foo").unwrap(), "FOO");
        assert_eq!(upper(&"FOO").unwrap(), "FOO");
        assert_eq!(upper(&"FooBar").unwrap(), "FOOBAR");
        assert_eq!(upper(&"foo").unwrap(), "FOO");
    }

    #[test]
    fn test_trim() {
        assert_eq!(trim(&" Hello\tworld\t").unwrap(), "Hello\tworld");
    }

    #[test]
    fn test_join() {
        assert_eq!(
            join((&["hello", "world"]).into_iter(), ", ").unwrap(),
            "hello, world"
        );
        assert_eq!(join((&["hello"]).into_iter(), ", ").unwrap(), "hello");

        let empty: &[&str] = &[];
        assert_eq!(join(empty.into_iter(), ", ").unwrap(), "");

        let input: Vec<String> = vec!["foo".into(), "bar".into(), "bazz".into()];
        assert_eq!(
            join((&input).into_iter(), ":".to_string()).unwrap(),
            "foo:bar:bazz"
        );
        assert_eq!(
            join(input.clone().into_iter(), ":").unwrap(),
            "foo:bar:bazz"
        );
        assert_eq!(
            join(input.clone().into_iter(), ":".to_string()).unwrap(),
            "foo:bar:bazz"
        );

        let input: &[String] = &["foo".into(), "bar".into()];
        assert_eq!(join(input.into_iter(), ":").unwrap(), "foo:bar");
        assert_eq!(join(input.into_iter(), ":".to_string()).unwrap(), "foo:bar");

        let real: String = "blah".into();
        let input: Vec<&str> = vec![&real];
        assert_eq!(join(input.into_iter(), ";").unwrap(), "blah");

        assert_eq!(
            join((&&&&&["foo", "bar"]).into_iter(), ", ").unwrap(),
            "foo, bar"
        );
    }
}
<commit_msg>Added linebreaks and linebreaksbr filters<commit_after>//! Module for built-in filter functions
//!
//! Contains all the built-in filter functions for use in templates.
//! Currently, there is no way to define filters outside this module.

#[cfg(feature = "serde-json")]
mod json;

#[cfg(feature = "serde-json")]
pub use self::json::json;

use std::fmt;

use super::Result;
use escaping::{self, MarkupDisplay};

// This is used by the code generator to decide whether a named filter is part of
// Askama or should refer to a local `filters` module. It should contain all the
// filters shipped with Askama, even the optional ones (since optional inclusion
// in the const vector based on features seems impossible right now).
pub const BUILT_IN_FILTERS: [&str; 14] = [
    "e",
    "escape",
    "format",
    "join",
    "linebreaks",
    "linebreaksbr",
    "lower",
    "lowercase",
    "safe",
    "trim",
    "truncate",
    "upper",
    "uppercase",
    "json", // Optional feature; reserve the name anyway
];

pub fn safe<D, I>(v: I) -> Result<MarkupDisplay<D>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    let res: MarkupDisplay<D> = v.into();
    Ok(res.mark_safe())
}

/// Escapes `&`, `<` and `>` in strings
pub fn escape<D, I>(i: I) -> Result<MarkupDisplay<String>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    let md: MarkupDisplay<D> = i.into();
    Ok(MarkupDisplay::Safe(escaping::escape(md.unsafe_string())))
}

/// Alias for the `escape()` filter
pub fn e<D, I>(i: I) -> Result<MarkupDisplay<String>>
where
    D: fmt::Display,
    MarkupDisplay<D>: From,
{
    escape(i)
}

/// Formats arguments according to the specified format
///
/// The first argument to this filter must be a string literal (as in normal
/// Rust). All arguments are passed through to the `format!()`
/// [macro](https://doc.rust-lang.org/stable/std/macro.format.html) by
/// the Askama code generator.
pub fn format() {}

/// Replaces line breaks in plain text with appropriate HTML; a single newline
/// becomes an HTML line break `<br>` and a new line followed by a blank line
/// becomes a paragraph break `<p>`.
pub fn linebreaks(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    let linebroken = s.replace("\n\n", "

").replace("\n", "
");

    Ok(format!("
{}
", linebroken))
}

/// Converts all newlines in a piece of plain text to HTML line breaks.
pub fn linebreaksbr(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.replace("\n", "
"))
}

/// Converts to lowercase.
pub fn lower(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.to_lowercase())
}

/// Alias for the `lower()` filter.
pub fn lowercase(s: &fmt::Display) -> Result<String> {
    lower(s)
}

/// Converts to uppercase.
pub fn upper(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.to_uppercase())
}

/// Alias for the `upper()` filter.
pub fn uppercase(s: &fmt::Display) -> Result<String> {
    upper(s)
}

/// Strip leading and trailing whitespace.
pub fn trim(s: &fmt::Display) -> Result<String> {
    let s = format!("{}", s);
    Ok(s.trim().to_owned())
}

/// Limit string length, appens '...' if truncated {
pub fn truncate(s: &fmt::Display, len: &usize) -> Result<String> {
    let mut s = format!("{}", s);
    if s.len() < *len {
        Ok(s)
    } else {
        s.truncate(*len);
        s.push_str("...");
        Ok(s)
    }
}

/// Joins iterable into a string separated by provided argument
pub fn join<T, I, S>(input: I, separator: S) -> Result<String>
where
    T: fmt::Display,
    I: Iterator<Item = T>,
    S: AsRef<str>,
{
    let separator: &str = separator.as_ref();

    let mut rv = String::new();

    for (num, item) in input.enumerate() {
        if num > 0 {
            rv.push_str(separator);
        }

        rv.push_str(&format!("{}", item));
    }

    Ok(rv)
}

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

    #[test]
    fn test_linebreaks() {
        assert_eq!(linebreaks(&"Foo\nBar Baz").unwrap(), "
Foo
Bar Baz
");
        assert_eq!(linebreaks(&"Foo\nBar\n\nBaz").unwrap(), "
Foo
Bar

Baz
");
    }

    #[test]
    fn test_linebreaksbr() {
        assert_eq!(linebreaksbr(&"Foo\nBar").unwrap(), "Foo
Bar");
        assert_eq!(linebreaksbr(&"Foo\nBar\n\nBaz").unwrap(), "Foo
Bar

Baz");
    }

    #[test]
    fn test_lower() {
        assert_eq!(lower(&"Foo").unwrap(), "foo");
        assert_eq!(lower(&"FOO").unwrap(), "foo");
        assert_eq!(lower(&"FooBar").unwrap(), "foobar");
        assert_eq!(lower(&"foo").unwrap(), "foo");
    }

    #[test]
    fn test_upper() {
        assert_eq!(upper(&"Foo").unwrap(), "FOO");
        assert_eq!(upper(&"FOO").unwrap(), "FOO");
        assert_eq!(upper(&"FooBar").unwrap(), "FOOBAR");
        assert_eq!(upper(&"foo").unwrap(), "FOO");
    }

    #[test]
    fn test_trim() {
        assert_eq!(trim(&" Hello\tworld\t").unwrap(), "Hello\tworld");
    }

    #[test]
    fn test_join() {
        assert_eq!(
            join((&["hello", "world"]).into_iter(), ", ").unwrap(),
            "hello, world"
        );
        assert_eq!(join((&["hello"]).into_iter(), ", ").unwrap(), "hello");

        let empty: &[&str] = &[];
        assert_eq!(join(empty.into_iter(), ", ").unwrap(), "");

        let input: Vec<String> = vec!["foo".into(), "bar".into(), "bazz".into()];
        assert_eq!(
            join((&input).into_iter(), ":".to_string()).unwrap(),
            "foo:bar:bazz"
        );
        assert_eq!(
            join(input.clone().into_iter(), ":").unwrap(),
            "foo:bar:bazz"
        );
        assert_eq!(
            join(input.clone().into_iter(), ":".to_string()).unwrap(),
            "foo:bar:bazz"
        );

        let input: &[String] = &["foo".into(), "bar".into()];
        assert_eq!(join(input.into_iter(), ":").unwrap(), "foo:bar");
        assert_eq!(join(input.into_iter(), ":".to_string()).unwrap(), "foo:bar");

        let real: String = "blah".into();
        let input: Vec<&str> = vec![&real];
        assert_eq!(join(input.into_iter(), ";").unwrap(), "blah");

        assert_eq!(
            join((&&&&&["foo", "bar"]).into_iter(), ", ").unwrap(),
            "foo, bar"
        );
    }
}
<|endoftext|>