<commit_before>//! Module converting command-line arguments into test configuration.

use std::env;
use std::path::PathBuf;
use getopts;

use super::options::{RunIgnored, ColorConfig, OutputFormat, Options};
use super::time::TestTimeOptions;
use super::helpers::isatty;

#[derive(Debug)]
pub struct TestOpts {
    pub list: bool,
    pub filter: Option<String>,
    pub filter_exact: bool,
    pub exclude_should_panic: bool,
    pub run_ignored: RunIgnored,
    pub run_tests: bool,
    pub bench_benchmarks: bool,
    pub logfile: Option<PathBuf>,
    pub nocapture: bool,
    pub color: ColorConfig,
    pub format: OutputFormat,
    pub test_threads: Option<usize>,
    pub skip: Vec<String>,
    pub time_options: Option<TestTimeOptions>,
    pub options: Options,
}

impl TestOpts {
    pub fn use_color(&self) -> bool {
        match self.color {
            ColorConfig::AutoColor => !self.nocapture && isatty::stdout_isatty(),
            ColorConfig::AlwaysColor => true,
            ColorConfig::NeverColor => false,
        }
    }
}

/// Result of parsing the options.
pub type OptRes = Result<TestOpts, String>;
/// Result of parsing the option part.
type OptPartRes<T> = Result<Option<T>, String>;

fn optgroups() -> getopts::Options {
    let mut opts = getopts::Options::new();
    opts.optflag("", "include-ignored", "Run ignored and not ignored tests")
        .optflag("", "ignored", "Run only ignored tests")
        .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic")
        .optflag("", "test", "Run tests and not benchmarks")
        .optflag("", "bench", "Run benchmarks instead of tests")
        .optflag("", "list", "List all tests and benchmarks")
        .optflag("h", "help", "Display this message (longer with --help)")
        .optopt(
            "",
            "logfile",
            "Write logs to the specified file instead \
             of stdout",
            "PATH",
        )
        .optflag(
            "",
            "nocapture",
            "don't capture stdout/stderr of each \
             task, allow printing directly",
        )
        .optopt(
            "",
            "test-threads",
            "Number of threads used for running tests \
             in parallel",
            "n_threads",
        )
        .optmulti(
            "",
            "skip",
            "Skip tests whose names contain FILTER (this flag can \
             be used multiple times)",
            "FILTER",
        )
        .optflag(
            "q",
            "quiet",
            "Display one character per test instead of one line. \
             Alias to --format=terse",
        )
        .optflag(
            "",
            "exact",
            "Exactly match filters rather than by substring",
        )
        .optopt(
            "",
            "color",
            "Configure coloring of output:
            auto   = colorize if stdout is a tty and tests are run on serially (default);
            always = always colorize output;
            never  = never colorize output;",
            "auto|always|never",
        )
        .optopt(
            "",
            "format",
            "Configure formatting of output:
            pretty = Print verbose output;
            terse  = Display one character per test;
            json   = Output a json document",
            "pretty|terse|json",
        )
        .optflag(
            "",
            "show-output",
            "Show captured stdout of successful tests"
        )
        .optopt(
            "Z",
            "",
            "Enable nightly-only flags:
            unstable-options = Allow use of experimental features",
            "unstable-options",
        )
        .optflagopt(
            "",
            "report-time",
            "Show execution time of each test. Awailable values:
            plain   = do not colorize the execution time (default);
            colored = colorize output according to the `color` parameter value;

            Threshold values for colorized output can be configured via
            `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
            `RUST_TEST_TIME_DOCTEST` environment variables.

            Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.

            Not available for --format=terse",
            "plain|colored"
        )
        .optflag(
            "",
            "ensure-time",
            "Treat excess of the test execution time limit as error.

            Threshold values for this option can be configured via
            `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
            `RUST_TEST_TIME_DOCTEST` environment variables.

            Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.

            `CRITICAL_TIME` here means the limit that should not be exceeded by test.
            "
        );
    return opts;
}

fn usage(binary: &str, options: &getopts::Options) {
    let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
    println!(
        r#"{usage}

The FILTER string is tested against the name of all tests, and only those
tests whose names contain the filter are run.

By default, all tests are run in parallel. This can be altered with the
--test-threads flag or the RUST_TEST_THREADS environment variable when running
tests (set it to 1).

All tests have their standard output and standard error captured by default.
This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
environment variable to a value other than "0". Logging is not captured by default.

Test Attributes:

    `#[test]`        - Indicates a function is a test to be run. This function
                       takes no arguments.
    `#[bench]`       - Indicates a function is a benchmark to be run. This
                       function takes one argument (test::Bencher).
    `#[should_panic]` - This function (also labeled with `#[test]`) will only pass if
                        the code causes a panic (an assertion failure or panic!)
                        A message may be provided, which the failure string must
                        contain: #[should_panic(expected = "foo")].
    `#[ignore]`       - When applied to a function which is already attributed as a
                        test, then the test runner will ignore these tests during
                        normal test runs. Running with --ignored or --include-ignored will run
                        these tests."#,
        usage = options.usage(&message)
    );
}

// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
fn is_nightly() -> bool {
    // Whether this is a feature-staged build, i.e., on the beta or stable channel
    let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
    // Whether we should enable unstable features for bootstrapping
    let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();

    bootstrap || !disable_unstable_features
}

// Gets the option value and checks if unstable features are enabled.
macro_rules! unstable_optflag {
    ($matches:ident, $allow_unstable:ident, $option_name:literal) => {{
        let opt = $matches.opt_present($option_name);
        if !$allow_unstable && opt {
            return Some(Err(format!(
                "The \"{}\" flag is only accepted on the nightly compiler",
                $option_name
            )));
        }

        opt
    }};
}

// Gets the CLI options assotiated with `report-time` feature.
fn get_time_options(
    matches: &getopts::Matches,
    allow_unstable: bool)
-> Option<OptPartRes<TestTimeOptions>> {
    let report_time = unstable_optflag!(matches, allow_unstable, "report-time");
    let colored_opt_str = matches.opt_str("report-time");
    let mut report_time_colored = report_time && colored_opt_str == Some("colored".into());
    let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time");

    // If `ensure-test-time` option is provided, time output is enforced,
    // so user won't be confused if any of tests will silently fail.
    let options = if report_time || ensure_test_time {
        if ensure_test_time && !report_time {
            report_time_colored = true;
        }
        Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored))
    } else {
        None
    };

    Some(Ok(options))
}

// Parses command line arguments into test options
pub fn parse_opts(args: &[String]) -> Option<OptRes> {
    let mut allow_unstable = false;
    let opts = optgroups();
    let args = args.get(1..).unwrap_or(args);
    let matches = match opts.parse(args) {
        Ok(m) => m,
        Err(f) => return Some(Err(f.to_string())),
    };

    if let Some(opt) = matches.opt_str("Z") {
        if !is_nightly() {
            return Some(Err(
                "the option `Z` is only accepted on the nightly compiler".into(),
            ));
        }

        match &*opt {
            "unstable-options" => {
                allow_unstable = true;
            }
            _ => {
                return Some(Err("Unrecognized option to `Z`".into()));
            }
        }
    };

    if matches.opt_present("h") {
        usage(&args[0], &opts);
        return None;
    }

    let filter = if !matches.free.is_empty() {
        Some(matches.free[0].clone())
    } else {
        None
    };

    let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic");

    let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored");

    let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
        (true, true) => {
            return Some(Err(
                "the options --include-ignored and --ignored are mutually exclusive".into(),
            ));
        }
        (true, false) => RunIgnored::Yes,
        (false, true) => RunIgnored::Only,
        (false, false) => RunIgnored::No,
    };
    let quiet = matches.opt_present("quiet");
    let exact = matches.opt_present("exact");
    let list = matches.opt_present("list");

    let logfile = matches.opt_str("logfile");
    let logfile = logfile.map(|s| PathBuf::from(&s));

    let bench_benchmarks = matches.opt_present("bench");
    let run_tests = !bench_benchmarks || matches.opt_present("test");

    let mut nocapture = matches.opt_present("nocapture");
    if !nocapture {
        nocapture = match env::var("RUST_TEST_NOCAPTURE") {
            Ok(val) => &val != "0",
            Err(_) => false,
        };
    }

    let time_options = match get_time_options(&matches, allow_unstable) {
        Some(Ok(val)) => val,
        Some(Err(e)) => return Some(Err(e)),
        None => panic!("Unexpected output from `get_time_options`"),
    };

    let test_threads = match matches.opt_str("test-threads") {
        Some(n_str) => match n_str.parse::<usize>() {
            Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())),
            Ok(n) => Some(n),
            Err(e) => {
                return Some(Err(format!(
                    "argument for --test-threads must be a number > 0 \
                     (error: {})",
                    e
                )));
            }
        },
        None => None,
    };

    let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
        Some("auto") | None => ColorConfig::AutoColor,
        Some("always") => ColorConfig::AlwaysColor,
        Some("never") => ColorConfig::NeverColor,

        Some(v) => {
            return Some(Err(format!(
                "argument for --color must be auto, always, or never (was \
                 {})",
                v
            )));
        }
    };

    let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
        None if quiet => OutputFormat::Terse,
        Some("pretty") | None => OutputFormat::Pretty,
        Some("terse") => OutputFormat::Terse,
        Some("json") => {
            if !allow_unstable {
                return Some(Err(
                    "The \"json\" format is only accepted on the nightly compiler".into(),
                ));
            }
            OutputFormat::Json
        }

        Some(v) => {
            return Some(Err(format!(
                "argument for --format must be pretty, terse, or json (was \
                 {})",
                v
            )));
        }
    };

    let test_opts = TestOpts {
        list,
        filter,
        filter_exact: exact,
        exclude_should_panic,
        run_ignored,
        run_tests,
        bench_benchmarks,
        logfile,
        nocapture,
        color,
        format,
        test_threads,
        skip: matches.opt_strs("skip"),
        time_options,
        options: Options::new().display_output(matches.opt_present("show-output")),
    };

    Some(Ok(test_opts))
}
<commit_msg>Split options parsing into several functions<commit_after>//! Module converting command-line arguments into test configuration.

use std::env;
use std::path::PathBuf;
use getopts;

use super::options::{RunIgnored, ColorConfig, OutputFormat, Options};
use super::time::TestTimeOptions;
use super::helpers::isatty;

#[derive(Debug)]
pub struct TestOpts {
    pub list: bool,
    pub filter: Option<String>,
    pub filter_exact: bool,
    pub exclude_should_panic: bool,
    pub run_ignored: RunIgnored,
    pub run_tests: bool,
    pub bench_benchmarks: bool,
    pub logfile: Option<PathBuf>,
    pub nocapture: bool,
    pub color: ColorConfig,
    pub format: OutputFormat,
    pub test_threads: Option<usize>,
    pub skip: Vec<String>,
    pub time_options: Option<TestTimeOptions>,
    pub options: Options,
}

impl TestOpts {
    pub fn use_color(&self) -> bool {
        match self.color {
            ColorConfig::AutoColor => !self.nocapture && isatty::stdout_isatty(),
            ColorConfig::AlwaysColor => true,
            ColorConfig::NeverColor => false,
        }
    }
}

/// Result of parsing the options.
pub type OptRes = Result<TestOpts, String>;
/// Result of parsing the option part.
type OptPartRes<T> = Result<T, String>;

fn optgroups() -> getopts::Options {
    let mut opts = getopts::Options::new();
    opts.optflag("", "include-ignored", "Run ignored and not ignored tests")
        .optflag("", "ignored", "Run only ignored tests")
        .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic")
        .optflag("", "test", "Run tests and not benchmarks")
        .optflag("", "bench", "Run benchmarks instead of tests")
        .optflag("", "list", "List all tests and benchmarks")
        .optflag("h", "help", "Display this message (longer with --help)")
        .optopt(
            "",
            "logfile",
            "Write logs to the specified file instead \
             of stdout",
            "PATH",
        )
        .optflag(
            "",
            "nocapture",
            "don't capture stdout/stderr of each \
             task, allow printing directly",
        )
        .optopt(
            "",
            "test-threads",
            "Number of threads used for running tests \
             in parallel",
            "n_threads",
        )
        .optmulti(
            "",
            "skip",
            "Skip tests whose names contain FILTER (this flag can \
             be used multiple times)",
            "FILTER",
        )
        .optflag(
            "q",
            "quiet",
            "Display one character per test instead of one line. \
             Alias to --format=terse",
        )
        .optflag(
            "",
            "exact",
            "Exactly match filters rather than by substring",
        )
        .optopt(
            "",
            "color",
            "Configure coloring of output:
            auto   = colorize if stdout is a tty and tests are run on serially (default);
            always = always colorize output;
            never  = never colorize output;",
            "auto|always|never",
        )
        .optopt(
            "",
            "format",
            "Configure formatting of output:
            pretty = Print verbose output;
            terse  = Display one character per test;
            json   = Output a json document",
            "pretty|terse|json",
        )
        .optflag(
            "",
            "show-output",
            "Show captured stdout of successful tests"
        )
        .optopt(
            "Z",
            "",
            "Enable nightly-only flags:
            unstable-options = Allow use of experimental features",
            "unstable-options",
        )
        .optflagopt(
            "",
            "report-time",
            "Show execution time of each test. Awailable values:
            plain   = do not colorize the execution time (default);
            colored = colorize output according to the `color` parameter value;

            Threshold values for colorized output can be configured via
            `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
            `RUST_TEST_TIME_DOCTEST` environment variables.

            Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.

            Not available for --format=terse",
            "plain|colored"
        )
        .optflag(
            "",
            "ensure-time",
            "Treat excess of the test execution time limit as error.

            Threshold values for this option can be configured via
            `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
            `RUST_TEST_TIME_DOCTEST` environment variables.

            Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.

            `CRITICAL_TIME` here means the limit that should not be exceeded by test.
            "
        );
    return opts;
}

fn usage(binary: &str, options: &getopts::Options) {
    let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
    println!(
        r#"{usage}

The FILTER string is tested against the name of all tests, and only those
tests whose names contain the filter are run.

By default, all tests are run in parallel. This can be altered with the
--test-threads flag or the RUST_TEST_THREADS environment variable when running
tests (set it to 1).

All tests have their standard output and standard error captured by default.
This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
environment variable to a value other than "0". Logging is not captured by default.

Test Attributes:

    `#[test]`        - Indicates a function is a test to be run. This function
                       takes no arguments.
    `#[bench]`       - Indicates a function is a benchmark to be run. This
                       function takes one argument (test::Bencher).
    `#[should_panic]` - This function (also labeled with `#[test]`) will only pass if
                        the code causes a panic (an assertion failure or panic!)
                        A message may be provided, which the failure string must
                        contain: #[should_panic(expected = "foo")].
    `#[ignore]`       - When applied to a function which is already attributed as a
                        test, then the test runner will ignore these tests during
                        normal test runs. Running with --ignored or --include-ignored will run
                        these tests."#,
        usage = options.usage(&message)
    );
}

/// Parses command line arguments into test options.
/// Returns `None` if help was requested (since we only show help message and don't run tests),
/// returns `Some(Err(..))` if provided arguments are incorrect,
/// otherwise creates a `TestOpts` object and returns it.
pub fn parse_opts(args: &[String]) -> Option<OptRes> {
    // Parse matches.
    let opts = optgroups();
    let args = args.get(1..).unwrap_or(args);
    let matches = match opts.parse(args) {
        Ok(m) => m,
        Err(f) => return Some(Err(f.to_string())),
    };

    // Check if help was requested.
    if matches.opt_present("h") {
        // Show help and do nothing more.
        usage(&args[0], &opts);
        return None;
    }

    // Actually parse the opts.
    let opts_result = parse_opts_impl(matches);

    Some(opts_result)
}

// Gets the option value and checks if unstable features are enabled.
macro_rules! unstable_optflag {
    ($matches:ident, $allow_unstable:ident, $option_name:literal) => {{
        let opt = $matches.opt_present($option_name);
        if !$allow_unstable && opt {
            return Err(format!(
                "The \"{}\" flag is only accepted on the nightly compiler",
                $option_name
            ));
        }

        opt
    }};
}

// Implementation of `parse_opts` that doesn't care about help message
// and returns a `Result`.
fn parse_opts_impl(matches: getopts::Matches) -> OptRes {
    let allow_unstable = get_allow_unstable(&matches)?;

    // Unstable flags
    let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic");
    let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored");
    let time_options = get_time_options(&matches, allow_unstable)?;

    let quiet = matches.opt_present("quiet");
    let exact = matches.opt_present("exact");
    let list = matches.opt_present("list");
    let skip = matches.opt_strs("skip");

    let bench_benchmarks = matches.opt_present("bench");
    let run_tests = !bench_benchmarks || matches.opt_present("test");

    let logfile = get_log_file(&matches)?;
    let run_ignored = get_run_ignored(&matches, include_ignored)?;
    let filter = get_filter(&matches)?;
    let nocapture = get_nocapture(&matches)?;
    let test_threads = get_test_threads(&matches)?;
    let color = get_color_config(&matches)?;
    let format = get_format(&matches, quiet, allow_unstable)?;

    let options = Options::new().display_output(matches.opt_present("show-output"));

    let test_opts = TestOpts {
        list,
        filter,
        filter_exact: exact,
        exclude_should_panic,
        run_ignored,
        run_tests,
        bench_benchmarks,
        logfile,
        nocapture,
        color,
        format,
        test_threads,
        skip,
        time_options,
        options,
    };

    Ok(test_opts)
}

// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
fn is_nightly() -> bool {
    // Whether this is a feature-staged build, i.e., on the beta or stable channel
    let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
    // Whether we should enable unstable features for bootstrapping
    let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();

    bootstrap || !disable_unstable_features
}

// Gets the CLI options assotiated with `report-time` feature.
fn get_time_options(
    matches: &getopts::Matches,
    allow_unstable: bool)
-> OptPartRes<Option<TestTimeOptions>> {
    let report_time = unstable_optflag!(matches, allow_unstable, "report-time");
    let colored_opt_str = matches.opt_str("report-time");
    let mut report_time_colored = report_time && colored_opt_str == Some("colored".into());
    let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time");

    // If `ensure-test-time` option is provided, time output is enforced,
    // so user won't be confused if any of tests will silently fail.
    let options = if report_time || ensure_test_time {
        if ensure_test_time && !report_time {
            report_time_colored = true;
        }
        Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored))
    } else {
        None
    };

    Ok(options)
}

fn get_test_threads(matches: &getopts::Matches) -> OptPartRes<Option<usize>> {
    let test_threads = match matches.opt_str("test-threads") {
        Some(n_str) => match n_str.parse::<usize>() {
            Ok(0) => return Err("argument for --test-threads must not be 0".to_string()),
            Ok(n) => Some(n),
            Err(e) => {
                return Err(format!(
                    "argument for --test-threads must be a number > 0 \
                     (error: {})",
                    e
                ));
            }
        },
        None => None,
    };

    Ok(test_threads)
}

fn get_format(matches: &getopts::Matches, quiet: bool, allow_unstable: bool) -> OptPartRes<OutputFormat> {
    let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
        None if quiet => OutputFormat::Terse,
        Some("pretty") | None => OutputFormat::Pretty,
        Some("terse") => OutputFormat::Terse,
        Some("json") => {
            if !allow_unstable {
                return Err(
                    "The \"json\" format is only accepted on the nightly compiler".into(),
                );
            }
            OutputFormat::Json
        }

        Some(v) => {
            return Err(format!(
                "argument for --format must be pretty, terse, or json (was \
                 {})",
                v
            ));
        }
    };

    Ok(format)
}

fn get_color_config(matches: &getopts::Matches) -> OptPartRes<ColorConfig> {
    let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
        Some("auto") | None => ColorConfig::AutoColor,
        Some("always") => ColorConfig::AlwaysColor,
        Some("never") => ColorConfig::NeverColor,

        Some(v) => {
            return Err(format!(
                "argument for --color must be auto, always, or never (was \
                 {})",
                v
            ));
        }
    };

    Ok(color)
}

fn get_nocapture(matches: &getopts::Matches) -> OptPartRes<bool> {
    let mut nocapture = matches.opt_present("nocapture");
    if !nocapture {
        nocapture = match env::var("RUST_TEST_NOCAPTURE") {
            Ok(val) => &val != "0",
            Err(_) => false,
        };
    }

    Ok(nocapture)
}

fn get_run_ignored(matches: &getopts::Matches, include_ignored: bool) -> OptPartRes<RunIgnored> {
    let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
        (true, true) => {
            return Err(
                "the options --include-ignored and --ignored are mutually exclusive".into(),
            );
        }
        (true, false) => RunIgnored::Yes,
        (false, true) => RunIgnored::Only,
        (false, false) => RunIgnored::No,
    };

    Ok(run_ignored)
}

fn get_filter(matches: &getopts::Matches) -> OptPartRes<Option<String>> {
    let filter = if !matches.free.is_empty() {
        Some(matches.free[0].clone())
    } else {
        None
    };

    Ok(filter)
}

fn get_allow_unstable(matches: &getopts::Matches) -> OptPartRes<bool> {
    let mut allow_unstable = false;

    if let Some(opt) = matches.opt_str("Z") {
        if !is_nightly() {
            return Err(
                "the option `Z` is only accepted on the nightly compiler".into(),
            );
        }

        match &*opt {
            "unstable-options" => {
                allow_unstable = true;
            }
            _ => {
                return Err("Unrecognized option to `Z`".into());
            }
        }
    };

    Ok(allow_unstable)
}

fn get_log_file(matches: &getopts::Matches) -> OptPartRes<Option<PathBuf>> {
    let logfile = matches.opt_str("logfile").map(|s| PathBuf::from(&s));

    Ok(logfile)
}
<|endoftext|>


<commit_before>use ::sodiumoxide::crypto::hash::sha256;
use ::sodiumoxide::crypto::sign;
use ::sodiumoxide::randombytes;
use ::std::io::{Cursor, Read};
use ::bs58;

use serializer::*;

const PUB_ADDRESS_PREFIX: &str = "GOD";
const PRIV_BUF_PREFIX: u8 = 0x01;
const PUB_BUF_PREFIX: u8 = 0x02;

trait Wif<T> {
    fn from_wif(s: &str) -> Option<T>;
    fn to_wif(&self) -> Box<str>;
}

#[derive(Debug, PartialEq)]
pub struct PublicKey {
    key: sign::PublicKey
}

impl PublicKey {
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        self.key.as_ref()
    }

    pub fn verify(&self, msg: &[u8], sig: &sign::Signature) -> bool {
        sign::verify_detached(sig, msg, &self.key)
    }

    pub fn from_bytes(bytes: &[u8]) -> Option<PublicKey> {
        let key = sign::PublicKey::from_slice(bytes)?;
        Some(PublicKey { key })
    }

    pub fn verify_sig_pair(pair: &SigPair, msg: &[u8]) -> bool {
        sign::verify_detached(&pair.signature, msg, &pair.pub_key.key)
    }
}

impl Wif<PublicKey> for PublicKey {
    fn from_wif(s: &str) -> Option<PublicKey> {
        if s.len() < 3 || &s[0..3] != PUB_ADDRESS_PREFIX { return None }
        let raw = bs58::decode(&s[3..]).into_vec().ok()?;
        if raw.len() != 37 || raw[0] != PUB_BUF_PREFIX { return None }

        let prefixed_key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4 .. raw.len()];
            let hash = sha256::hash(prefixed_key);
            let checksum_b = &sha256::hash(hash.as_ref())[0..4];
            if checksum_a != checksum_b { return None }
        }

        let key = &prefixed_key[1 .. prefixed_key.len()];
        Some(PublicKey {
            key: sign::PublicKey::from_slice(key)?
        })
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf: Vec<u8> = Vec::<u8>::with_capacity(37);
        buf.push(PUB_BUF_PREFIX);
        buf.extend_from_slice(self.key.as_ref());

        let checksum = &sha256::hash(sha256::hash(&buf).as_ref())[0..4];
        buf.extend_from_slice(checksum);

        let mut s = bs58::encode(buf).into_string();
        s.insert_str(0, PUB_ADDRESS_PREFIX);
        s.into_boxed_str()
    }
}

pub struct PrivateKey {
    seed: sign::Seed,
    key: sign::SecretKey
}

impl PrivateKey {
    pub fn sign(&self, msg: &[u8]) -> sign::Signature {
        sign::sign_detached(msg, &self.key)
    }
}

impl Wif<KeyPair> for PrivateKey {
    fn from_wif(s: &str) -> Option<KeyPair> {
        let raw = bs58::decode(s).into_vec().ok()?;
        if raw.len() != 37 || raw[0] != PRIV_BUF_PREFIX { return None }

        let key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4 .. raw.len()];
            let hash = sha256::hash(key);
            let checksum_b = &sha256::hash(hash.as_ref())[0..4];
            if checksum_a != checksum_b { return None }
        }

        let seed = sign::Seed::from_slice(&key[1..])?;
        let (pk, sk) = sign::keypair_from_seed(&seed);
        Some(KeyPair(PublicKey {
            key: pk
        }, PrivateKey {
            seed,
            key: sk
        }))
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf = Vec::<u8>::with_capacity(37);
        buf.push(PRIV_BUF_PREFIX);
        buf.extend_from_slice(&self.seed.0);

        let checksum = &sha256::hash(sha256::hash(&buf).as_ref())[0..4];
        buf.extend_from_slice(checksum);

        bs58::encode(buf).into_string().into_boxed_str()
    }
}

pub struct KeyPair(pub PublicKey, pub PrivateKey);

impl KeyPair {
    pub fn gen_keypair() -> KeyPair {
        let mut raw_seed: [u8; sign::SEEDBYTES] = [0; sign::SEEDBYTES];
        randombytes::randombytes_into(&mut raw_seed);
        let seed = sign::Seed::from_slice(&raw_seed).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        KeyPair(PublicKey {
            key: pk
        }, PrivateKey {
            seed,
            key: sk
        })
    }
}

pub struct SigPair {
    pub pub_key: PublicKey,
    pub signature: sign::Signature
}

impl SigPair {
    pub fn encode_as_bytes(vec: &mut Vec<u8>, pairs: &[SigPair]) {
        vec.push_u16(pairs.len() as u16);
        for sig in pairs {
            vec.push_sig_pair(sig);
        }
    }

    pub fn decode_from_bytes<T> (cur: &mut Cursor<T>) -> Option<Vec<SigPair>>
            where T: AsRef<[u8]> + Read {
        let len = cur.take_u16()?;
        let mut vec = Vec::with_capacity(len as usize);
        for _ in 0..len {
            vec.push(cur.take_sig_pair()?);
        }
        Some(vec)
    }
}

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

    #[test]
    fn test_create_and_recover_keys() {
        let kp = KeyPair::gen_keypair();

        let pk = &*kp.0.to_wif();
        assert_eq!(&*PublicKey::from_wif(pk).unwrap().to_wif(), pk);

        let sk = &*kp.1.to_wif();
        assert_eq!(&*PrivateKey::from_wif(sk).unwrap().1.to_wif(), sk);
    }

    #[test]
    fn test_import_keys_from_wif() {
        let kp = PrivateKey::from_wif("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").unwrap();
        assert_eq!(&*kp.1.to_wif(), "3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM");
        assert_eq!(&*kp.0.to_wif(), "GOD52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8");
    }

    #[test]
    fn test_sign_message() {
        let msg = "Hello world!".as_bytes();
        let kp = KeyPair::gen_keypair();

        let sig = &kp.1.sign(msg);
        assert!(kp.0.verify(msg, sig));

        let pair = SigPair {
            pub_key: kp.0,
            signature: *sig
        };
        assert!(PublicKey::verify_sig_pair(&pair, msg));

        // Test bad keys
        let kp = KeyPair::gen_keypair();
        assert!(!kp.0.verify(msg, sig));
    }
}
<commit_msg>Refactor hashing to double_sha256<commit_after>use ::sodiumoxide::crypto::hash;
use ::sodiumoxide::crypto::sign;
use ::sodiumoxide::randombytes;
use ::std::io::{Cursor, Read};
use ::bs58;

use serializer::*;

const PUB_ADDRESS_PREFIX: &str = "GOD";
const PRIV_BUF_PREFIX: u8 = 0x01;
const PUB_BUF_PREFIX: u8 = 0x02;

trait Wif<T> {
    fn from_wif(s: &str) -> Option<T>;
    fn to_wif(&self) -> Box<str>;
}

#[derive(Debug, PartialEq)]
pub struct PublicKey {
    key: sign::PublicKey
}

impl PublicKey {
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        self.key.as_ref()
    }

    pub fn verify(&self, msg: &[u8], sig: &sign::Signature) -> bool {
        sign::verify_detached(sig, msg, &self.key)
    }

    pub fn from_bytes(bytes: &[u8]) -> Option<PublicKey> {
        let key = sign::PublicKey::from_slice(bytes)?;
        Some(PublicKey { key })
    }

    pub fn verify_sig_pair(pair: &SigPair, msg: &[u8]) -> bool {
        sign::verify_detached(&pair.signature, msg, &pair.pub_key.key)
    }
}

impl Wif<PublicKey> for PublicKey {
    fn from_wif(s: &str) -> Option<PublicKey> {
        if s.len() < 3 || &s[0..3] != PUB_ADDRESS_PREFIX { return None }
        let raw = bs58::decode(&s[3..]).into_vec().ok()?;
        if raw.len() != 37 || raw[0] != PUB_BUF_PREFIX { return None }

        let prefixed_key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4 .. raw.len()];
            let checksum_b = &double_sha256(prefixed_key)[0..4];
            if checksum_a != checksum_b { return None }
        }

        let key = &prefixed_key[1 .. prefixed_key.len()];
        Some(PublicKey {
            key: sign::PublicKey::from_slice(key)?
        })
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf: Vec<u8> = Vec::<u8>::with_capacity(37);
        buf.push(PUB_BUF_PREFIX);
        buf.extend_from_slice(self.key.as_ref());

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        let mut s = bs58::encode(buf).into_string();
        s.insert_str(0, PUB_ADDRESS_PREFIX);
        s.into_boxed_str()
    }
}

pub struct PrivateKey {
    seed: sign::Seed,
    key: sign::SecretKey
}

impl PrivateKey {
    pub fn sign(&self, msg: &[u8]) -> sign::Signature {
        sign::sign_detached(msg, &self.key)
    }
}

impl Wif<KeyPair> for PrivateKey {
    fn from_wif(s: &str) -> Option<KeyPair> {
        let raw = bs58::decode(s).into_vec().ok()?;
        if raw.len() != 37 || raw[0] != PRIV_BUF_PREFIX { return None }

        let key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4 .. raw.len()];
            let checksum_b = &double_sha256(key)[0..4];
            if checksum_a != checksum_b { return None }
        }

        let seed = sign::Seed::from_slice(&key[1..])?;
        let (pk, sk) = sign::keypair_from_seed(&seed);
        Some(KeyPair(PublicKey {
            key: pk
        }, PrivateKey {
            seed,
            key: sk
        }))
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf = Vec::<u8>::with_capacity(37);
        buf.push(PRIV_BUF_PREFIX);
        buf.extend_from_slice(&self.seed.0);

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        bs58::encode(buf).into_string().into_boxed_str()
    }
}

pub struct KeyPair(pub PublicKey, pub PrivateKey);

impl KeyPair {
    pub fn gen_keypair() -> KeyPair {
        let mut raw_seed: [u8; sign::SEEDBYTES] = [0; sign::SEEDBYTES];
        randombytes::randombytes_into(&mut raw_seed);
        let seed = sign::Seed::from_slice(&raw_seed).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        KeyPair(PublicKey {
            key: pk
        }, PrivateKey {
            seed,
            key: sk
        })
    }
}

pub struct SigPair {
    pub pub_key: PublicKey,
    pub signature: sign::Signature
}

impl SigPair {
    pub fn encode_as_bytes(vec: &mut Vec<u8>, pairs: &[SigPair]) {
        vec.push_u16(pairs.len() as u16);
        for sig in pairs {
            vec.push_sig_pair(sig);
        }
    }

    pub fn decode_from_bytes<T>(cur: &mut Cursor<T>) -> Option<Vec<SigPair>>
            where T: AsRef<[u8]> + Read {
        let len = cur.take_u16()?;
        let mut vec = Vec::with_capacity(len as usize);
        for _ in 0..len {
            vec.push(cur.take_sig_pair()?);
        }
        Some(vec)
    }
}

#[inline]
fn double_sha256(buf: &[u8]) -> hash::sha256::Digest {
    hash::sha256::hash(hash::sha256::hash(buf).as_ref())
}

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

    #[test]
    fn test_create_and_recover_keys() {
        let kp = KeyPair::gen_keypair();

        let pk = &*kp.0.to_wif();
        assert_eq!(&*PublicKey::from_wif(pk).unwrap().to_wif(), pk);

        let sk = &*kp.1.to_wif();
        assert_eq!(&*PrivateKey::from_wif(sk).unwrap().1.to_wif(), sk);
    }

    #[test]
    fn test_import_keys_from_wif() {
        let kp = PrivateKey::from_wif("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").unwrap();
        assert_eq!(&*kp.1.to_wif(), "3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM");
        assert_eq!(&*kp.0.to_wif(), "GOD52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8");
    }

    #[test]
    fn test_sign_message() {
        let msg = "Hello world!".as_bytes();
        let kp = KeyPair::gen_keypair();

        let sig = &kp.1.sign(msg);
        assert!(kp.0.verify(msg, sig));

        let pair = SigPair {
            pub_key: kp.0,
            signature: *sig
        };
        assert!(PublicKey::verify_sig_pair(&pair, msg));

        // Test bad keys
        let kp = KeyPair::gen_keypair();
        assert!(!kp.0.verify(msg, sig));
    }
}
<|endoftext|>


<commit_before>use std::io;
mod helpers;
mod pizza_base;
mod topping;
mod pizza;

fn main() {
    let stdin = io::stdin();
    let name = helpers::get_name(stdin);
    println!("Hello {}", name);
    str_topping(get_topping());
    println!("Pizza is {}", get_pizza());
}

fn get_pizza<'a>() -> pizza::Pizza<'a> {
    return pizza::Pizza {
               toppings: vec![get_topping(), get_topping()],
               base: pizza_base::Base {
                   vegetarian: false,
                   name: "Test base",
                   height: 12.5f32,
                   thickness: 113f32,
               },
           };
}

fn get_topping<'a>() -> topping::Topping<'a> {
    return topping::Topping {
               name: "Salami",
               price: 0.7,
               vegetarian: false,
           };
}

fn str_topping(topping: topping::Topping) {
    println!("{} - {}", topping.name, topping.price)
}
<commit_msg>Rust, removed unused method<commit_after>use std::io;
mod helpers;
mod pizza_base;
mod topping;
mod pizza;

fn main() {
    let stdin = io::stdin();
    let name = helpers::get_name(stdin);
    println!("Hello {}", name);
    println!("Pizza is {}", get_pizza());
}

fn get_pizza<'a>() -> pizza::Pizza<'a> {
    return pizza::Pizza {
               toppings: vec![get_topping(), get_topping()],
               base: pizza_base::Base {
                   vegetarian: false,
                   name: "Test base",
                   height: 12.5f32,
                   thickness: 113f32,
               },
           };
}

fn get_topping<'a>() -> topping::Topping<'a> {
    return topping::Topping {
               name: "Salami",
               price: 0.7,
               vegetarian: false,
           };
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::ops::*;
use std::*;

pub fn main() {
    return;
}

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

    #[test]
    fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}

// -----------------------------------------------
// Framework
// -----------------------------------------------

#[allow(unused)]
fn rl() -> String {
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

#[allow(unused)]
fn rw<T>() -> Vec<T>
where
    T: std::str::FromStr,
    T::Err: std::fmt::Debug,
{
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.split_whitespace()
        .map(|word| T::from_str(word).unwrap())
        .collect()
}

// -----------------------------------------------
// Polyfill
// -----------------------------------------------

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}
<commit_msg>Move solution to bottom to define macros above<commit_after>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::ops::*;
use std::*;

// -----------------------------------------------
// Framework
// -----------------------------------------------

#[allow(unused)]
fn rl() -> String {
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

#[allow(unused)]
fn rw<T>() -> Vec<T>
where
    T: std::str::FromStr,
    T::Err: std::fmt::Debug,
{
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.split_whitespace()
        .map(|word| T::from_str(word).unwrap())
        .collect()
}

// -----------------------------------------------
// Polyfill
// -----------------------------------------------

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}

// -----------------------------------------------
// Solution
// -----------------------------------------------

pub fn main() {
    return;
}

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

    #[test]
    fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<|endoftext|>


<commit_before>extern crate fuse;
extern crate libc;
extern crate time;
extern crate argparse;

use std::string::String;
use std::fmt;
use std::env;
use std::path::Path;
use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;

use libc::{ENOSYS,c_int,ENOENT};
use time::Timespec;
use argparse::{ArgumentParser, StoreTrue, Store};
use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyEmpty, ReplyDirectory};

const DEBUG : bool = true;
// FIXME I hate macros. Basically the same as println! but with an IF!!!!!
macro_rules! log {
    ($fmt:expr) => (if DEBUG {println!(concat!($fmt, "\n"))});
    ($fmt:expr, $($arg:tt)*) => (if DEBUG {println!(concat!($fmt, "\n"), $($arg)*)});
}
// FIMXE this should output to stderr or to syslog
macro_rules! error {
    ($fmt:expr) => (if DEBUG {println!(concat!($fmt, "\n"))});
    ($fmt:expr, $($arg:tt)*) => (if DEBUG {println!(concat!($fmt, "\n"), $($arg)*)});
}

// FIXME these are ugly as fuck and it seems like a BAD DECISION to have these kind of macros in rust.
// FIXME in any case, clean up our usage of these later.
// from: http://stackoverflow.com/questions/28392008/more-concise-hashmap-initialization
// auto-converts to String
macro_rules! hashmap {
    ($( $key: expr => $val: expr ),*) => {{
         let mut map = ::std::collections::HashMap::new();
         $( map.insert($key.to_string(), $val); )*
         map
    }}
}
// similar to above, jesus christ this is terrible
macro_rules! hashset {
    ($( $x: expr ),* ) => {{
            let mut set = HashSet::new();
            $( set.insert($x.to_string()); )*
            set
    }}
}

const TTL: Timespec = Timespec { sec: 1, nsec: 0 };                 // 1 second

const CREATE_TIME: Timespec = Timespec { sec: 1381237736, nsec: 0 };    // 2013-10-08 08:56

const HELLO_DIR_ATTR: FileAttr = FileAttr {
    ino: 1,
    size: 0,
    blocks: 0,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::Directory,
    perm: 0o755,
    nlink: 2,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

const HELLO_TXT_CONTENT: &'static str = "Hello World!\n";

const HELLO_TXT_ATTR: FileAttr = FileAttr {
    ino: 2,
    size: 13,
    blocks: 1,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::RegularFile,
    perm: 0o644,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

struct UrchinFSEntry {
    display_name: String,
    destination: String,
    metadata: HashMap<String, HashSet<String>>
}

struct UrchinFS {
    entries: Vec<UrchinFSEntry>
}

impl Filesystem for UrchinFS {
    fn lookup (&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        if parent == 1 && name.to_str() == Some("hello.txt") {
            reply.entry(&TTL, &HELLO_TXT_ATTR, 0);
        } else {
            reply.error(ENOENT);
        }
    }

    fn getattr (&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match ino {
            1 => reply.attr(&TTL, &HELLO_DIR_ATTR),
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

    fn read (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, _size: u32, reply: ReplyData) {
        if ino == 2 {
            reply.data(&HELLO_TXT_CONTENT.as_bytes()[offset as usize..]);
        } else {
            reply.error(ENOENT);
        }
    }

    fn readdir (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, mut reply: ReplyDirectory) {
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, ".");
                reply.add(1, 1, FileType::Directory, "..");
                reply.add(2, 2, FileType::RegularFile, "hello.txt");
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }

    fn access (&mut self, _req: &Request, _ino: u64, _mask: u32, reply: ReplyEmpty) {
        reply.error(ENOSYS);
    }
}

fn main () {
    let mut mountpoint = String::new();
    let mut optstr = String::new();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("faceted-search FUSE filesystem");
        ap.refer(&mut optstr).add_option(&["-o", "--options"], Store, "comma-separated mount options");
        ap.refer(&mut mountpoint).add_argument("mountpoint", Store, "the mountpoint").required();
        ap.parse_args_or_exit();
    }

// -o plugin=foo,plugin=bar,source=/home/kellen/films/,glob=*.json,format=json,watch=true,type=directory,formatter=generic
// FIXME dynamically load plugins for globbing/formatting see:
// http://stackoverflow.com/questions/22461457/does-rust-have-a-dlopen-equivalent

    // FIXME seems weird to have to have two variable refs
    let vec;
    let mut options : &[&OsStr] = &[];
    if optstr.trim() != "" {
        vec = optstr.trim().split(",").map(|s| OsStr::new(s)).collect::<Vec<_>>();
        options = &vec;
    }

    if DEBUG {
        if options.len() > 0 {
            println!("using options:");
            for s in options {
                match s.to_str() {
                    Some(y) => {println!("\t{}", y);}
                    None => {}
                }
            }
        }
    }

    // FIMXE do this better
    let easter = UrchinFSEntry {
        display_name: "Easter Parade (1948, color)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1948"], "color" => hashset!["color"]]
    };
    let city = UrchinFSEntry {
        display_name: "The Naked City (1948, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1948"], "color" => hashset!["black-and-white"]]
    };
    let vanish = UrchinFSEntry {
        display_name: "The Lady Vanishes (1938, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1938"], "color" => hashset!["black-and-white"]]
    };
    let kiss = UrchinFSEntry {
        display_name: "Kiss Me Deadly (1955, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1955"], "color" => hashset!["black-and-white"]]
    };

    fuse::mount(UrchinFS {entries: vec![easter, city, vanish, kiss]}, &mountpoint, options);
}
<commit_msg>turns out there are already better versions of this in std<commit_after>extern crate fuse;
extern crate libc;
extern crate time;
extern crate argparse;

use std::string::String;
use std::fmt;
use std::env;
use std::path::Path;
use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;

use libc::{ENOSYS,c_int,ENOENT};
use time::Timespec;
use argparse::{ArgumentParser, StoreTrue, Store};
use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyEmpty, ReplyDirectory};

// FIXME these are ugly as fuck and it seems like a BAD DECISION to have these kind of macros in rust.
// FIXME in any case, clean up our usage of these later.
// from: http://stackoverflow.com/questions/28392008/more-concise-hashmap-initialization
// auto-converts to String
macro_rules! hashmap {
    ($( $key: expr => $val: expr ),*) => {{
         let mut map = ::std::collections::HashMap::new();
         $( map.insert($key.to_string(), $val); )*
         map
    }}
}
// similar to above, jesus christ this is terrible
macro_rules! hashset {
    ($( $x: expr ),* ) => {{
            let mut set = HashSet::new();
            $( set.insert($x.to_string()); )*
            set
    }}
}

const TTL: Timespec = Timespec { sec: 1, nsec: 0 };                 // 1 second

const CREATE_TIME: Timespec = Timespec { sec: 1381237736, nsec: 0 };    // 2013-10-08 08:56

const HELLO_DIR_ATTR: FileAttr = FileAttr {
    ino: 1,
    size: 0,
    blocks: 0,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::Directory,
    perm: 0o755,
    nlink: 2,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

const HELLO_TXT_CONTENT: &'static str = "Hello World!\n";

const HELLO_TXT_ATTR: FileAttr = FileAttr {
    ino: 2,
    size: 13,
    blocks: 1,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::RegularFile,
    perm: 0o644,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

struct UrchinFSEntry {
    display_name: String,
    destination: String,
    metadata: HashMap<String, HashSet<String>>
}

struct UrchinFS {
    entries: Vec<UrchinFSEntry>
}

impl Filesystem for UrchinFS {
    fn lookup (&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        if parent == 1 && name.to_str() == Some("hello.txt") {
            reply.entry(&TTL, &HELLO_TXT_ATTR, 0);
        } else {
            reply.error(ENOENT);
        }
    }

    fn getattr (&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match ino {
            1 => reply.attr(&TTL, &HELLO_DIR_ATTR),
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

    fn read (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, _size: u32, reply: ReplyData) {
        if ino == 2 {
            reply.data(&HELLO_TXT_CONTENT.as_bytes()[offset as usize..]);
        } else {
            reply.error(ENOENT);
        }
    }

    fn readdir (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, mut reply: ReplyDirectory) {
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, ".");
                reply.add(1, 1, FileType::Directory, "..");
                reply.add(2, 2, FileType::RegularFile, "hello.txt");
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }

    fn access (&mut self, _req: &Request, _ino: u64, _mask: u32, reply: ReplyEmpty) {
        reply.error(ENOSYS);
    }
}

fn main () {
    let mut mountpoint = String::new();
    let mut optstr = String::new();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("faceted-search FUSE filesystem");
        ap.refer(&mut optstr).add_option(&["-o", "--options"], Store, "comma-separated mount options");
        ap.refer(&mut mountpoint).add_argument("mountpoint", Store, "the mountpoint").required();
        ap.parse_args_or_exit();
    }

// -o plugin=foo,plugin=bar,source=/home/kellen/films/,glob=*.json,format=json,watch=true,type=directory,formatter=generic
// FIXME dynamically load plugins for globbing/formatting see:
// http://stackoverflow.com/questions/22461457/does-rust-have-a-dlopen-equivalent

    // FIXME seems weird to have to have two variable refs
    let vec;
    let mut options : &[&OsStr] = &[];
    if optstr.trim() != "" {
        vec = optstr.trim().split(",").map(|s| OsStr::new(s)).collect::<Vec<_>>();
        options = &vec;
    }

    if DEBUG {
        if options.len() > 0 {
            println!("using options:");
            for s in options {
                match s.to_str() {
                    Some(y) => {println!("\t{}", y);}
                    None => {}
                }
            }
        }
    }

    // FIMXE do this better
    let easter = UrchinFSEntry {
        display_name: "Easter Parade (1948, color)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1948"], "color" => hashset!["color"]]
    };
    let city = UrchinFSEntry {
        display_name: "The Naked City (1948, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1948"], "color" => hashset!["black-and-white"]]
    };
    let vanish = UrchinFSEntry {
        display_name: "The Lady Vanishes (1938, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1938"], "color" => hashset!["black-and-white"]]
    };
    let kiss = UrchinFSEntry {
        display_name: "Kiss Me Deadly (1955, bw)".to_string(),
        destination: "/home/kellen/test".to_string(),
        metadata: hashmap!["year" => hashset!["1955"], "color" => hashset!["black-and-white"]]
    };

    fuse::mount(UrchinFS {entries: vec![easter, city, vanish, kiss]}, &mountpoint, options);
}
<|endoftext|>


<commit_before>//! Operation result structures and helpers.
//!
//! Most LDAP operations return a [`LdapResult`](struct.LdapResult.html). This module
//! contains its definition, as well as that of a number of wrapper structs and
//! helper methods, which adapt LDAP result and error handling to be a closer
//! match to Rust conventions.

use std::error::Error;
use std::fmt;
use std::io;
use std::result::Result as StdResult;

use crate::controls::Control;
use crate::exop::Exop;
use crate::protocol::{LdapOp, MaybeControls, ResultSender};
use crate::search::parse_refs;
use crate::search::ResultEntry;
use crate::RequestId;

use lber::common::TagClass;
use lber::parse::parse_uint;
use lber::structures::Tag;
use lber::universal::Types;
use lber::IResult;

use thiserror::Error;
use tokio::sync::{mpsc, oneshot};
use tokio::time;

/// Type alias for the standard `Result` with the fixed `LdapError` error part.
pub type Result<T> = std::result::Result<T, LdapError>;

/// Error variants recognized by the library.
#[derive(Debug, Error)]
pub enum LdapError {
    /// No path given for a `ldapi://` URL.
    #[error("empty Unix domain socket path")]
    EmptyUnixPath,

    /// A `ldapi://` URL contains a port spec, which it shouldn't.
    #[error("the port must be empty in the ldapi scheme")]
    PortInUnixPath,

    /// Encapsulated I/O error.
    #[error("I/O error: {source}")]
    Io {
        #[from]
        source: io::Error,
    },

    /// Error while sending an operation to the connection handler.
    #[error("op send error: {source}")]
    OpSend {
        #[from]
        source: mpsc::error::SendError<(RequestId, LdapOp, Tag, MaybeControls, ResultSender)>,
    },

    /// Error while receiving operation results from the connection handler.
    #[error("result recv error: {source}")]
    ResultRecv {
        #[from]
        source: oneshot::error::RecvError,
    },

    /// Error while sending an internal ID scrubbing request to the connection handler.
    #[error("id scrub send error: {source}")]
    IdScrubSend {
        #[from]
        source: mpsc::error::SendError<RequestId>,
    },

    /// Operation or connection timeout.
    #[error("timeout: {elapsed}")]
    Timeout {
        #[from]
        elapsed: time::Elapsed,
    },

    /// Error parsing the string representation of a search filter.
    #[error("filter parse error")]
    FilterParsing,

    /// Premature end of a search stream.
    #[error("premature end of search stream")]
    EndOfStream,

    /// URL parsing error.
    #[error("url parse error: {source}")]
    UrlParsing {
        #[from]
        source: url::ParseError,
    },

    /// Unknown LDAP URL scheme.
    #[error("unknown LDAP URL scheme: {0}")]
    UnknownScheme(String),

    #[cfg(feature = "tls")]
    /// Native TLS library error.
    #[error("native TLS error: {source}")]
    NativeTLS {
        #[from]
        source: native_tls::Error,
    },

    /// LDAP operation result with an error return code.
    #[error("LDAP operation result: {result}")]
    LdapResult {
        #[from]
        result: LdapResult,
    },

    /// No values provided for the Add operation.
    #[error("empty value set for Add")]
    AddNoValues,
}

impl From<LdapError> for io::Error {
    fn from(le: LdapError) -> io::Error {
        match le {
            LdapError::Io { source, .. } => source,
            _ => io::Error::new(io::ErrorKind::Other, format!("{}", le)),
        }
    }
}

/// Common components of an LDAP operation result.
///
/// This structure faithfully replicates the components dictated by the standard,
/// and is distinctly C-like with its reliance on numeric codes for the indication
/// of outcome. It would be tempting to hide it behind an automatic `Result`-like
/// interface, but there are scenarios where this would preclude intentional
/// incorporation of error conditions into query design. Instead, the struct
/// implements helper methods, [`success()`](#method.success) and
/// [`non_error()`](#method.non_error), which may be used for ergonomic error
/// handling when simple condition checking suffices.
#[derive(Clone, Debug)]
pub struct LdapResult {
    /// Result code.
    ///
    /// Generally, the value of zero indicates successful completion, but there's
    /// a number of other non-error codes arising as a result of various operations.
    /// See [Section A.1 of RFC 4511](https://tools.ietf.org/html/rfc4511#appendix-A.1).
    pub rc: u32,
    /// Matched component DN, where applicable.
    pub matched: String,
    /// Additional diagnostic text.
    pub text: String,
    /// Referrals.
    ///
    /// Absence of referrals is represented by an empty vector.
    pub refs: Vec<String>,
    /// Response controls.
    ///
    /// Missing and empty controls are both represented by an empty vector.
    pub ctrls: Vec<Control>,
}

#[doc(hidden)]
impl From<Tag> for LdapResult {
    fn from(t: Tag) -> LdapResult {
        <LdapResultExt as From<Tag>>::from(t).0
    }
}

impl Error for LdapResult {}

impl fmt::Display for LdapResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        fn description(this: &LdapResult) -> &'static str {
            match this.rc {
                0 => "success",
                1 => "operationsError",
                2 => "protocolError",
                3 => "timeLimitExceeded",
                4 => "sizeLimitExceeded",
                5 => "compareFalse",
                6 => "compareTrue",
                7 => "authMethodNotSupported",
                8 => "strongerAuthRequired",
                10 => "referral",
                11 => "adminLimitExceeded",
                12 => "unavailableCriticalExtension",
                13 => "confidentialityRequired",
                14 => "saslBindInProgress",
                16 => "noSuchAttribute",
                17 => "undefinedAttributeType",
                18 => "inappropriateMatching",
                19 => "constraintViolation",
                20 => "attributeOrValueExists",
                21 => "invalidAttributeSyntax",
                32 => "noSuchObject",
                33 => "aliasProblem",
                34 => "invalidDNSyntax",
                36 => "aliasDereferencingProblem",
                48 => "inappropriateAuthentication",
                49 => "invalidCredentials",
                50 => "insufficientAccessRights",
                51 => "busy",
                52 => "unavailable",
                53 => "unwillingToPerform",
                54 => "loopDetect",
                64 => "namingViolation",
                65 => "objectClassViolation",
                66 => "notAllowedOnNonLeaf",
                67 => "notAllowedOnRDN",
                68 => "entryAlreadyExists",
                69 => "objectClassModsProhibited",
                71 => "affectsMultipleDSAs",
                80 => "other",
                88 => "abandoned",
                122 => "assertionFailed",
                _ => "unknown",
            }
        }

        write!(
            f,
            "rc={} ({}), dn: \"{}\", text: \"{}\"",
            self.rc,
            description(self),
            self.matched,
            self.text
        )
    }
}

impl LdapResult {
    /// If the result code is zero, return the instance itself wrapped
    /// in `Ok()`, otherwise wrap the instance in an `io::Error`.
    pub fn success(self) -> Result<Self> {
        if self.rc == 0 {
            Ok(self)
        } else {
            Err(LdapError::from(self))
        }
    }

    /// If the result code is 0 or 10 (referral), return the instance
    /// itself wrapped in `Ok()`, otherwise wrap the instance in an
    /// `io::Error`.
    pub fn non_error(self) -> Result<Self> {
        if self.rc == 0 || self.rc == 10 {
            Ok(self)
        } else {
            Err(LdapError::from(self))
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) struct LdapResultExt(pub LdapResult, pub Exop);

impl From<Tag> for LdapResultExt {
    fn from(t: Tag) -> LdapResultExt {
        let t = match t {
            Tag::StructureTag(t) => t,
            Tag::Null(_) => {
                return LdapResultExt(
                    LdapResult {
                        rc: 0,
                        matched: String::from(""),
                        text: String::from(""),
                        refs: vec![],
                        ctrls: vec![],
                    },
                    Exop {
                        name: None,
                        val: None,
                    },
                )
            }
            _ => unimplemented!(),
        };
        let mut tags = t.expect_constructed().expect("result sequence").into_iter();
        let rc = match parse_uint(
            tags.next()
                .expect("element")
                .match_class(TagClass::Universal)
                .and_then(|t| t.match_id(Types::Enumerated as u64))
                .and_then(|t| t.expect_primitive())
                .expect("result code")
                .as_slice(),
        ) {
            IResult::Done(_, rc) => rc as u32,
            _ => panic!("failed to parse result code"),
        };
        let matched = String::from_utf8(
            tags.next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("matched dn");
        let text = String::from_utf8(
            tags.next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("diagnostic message");
        let mut refs = Vec::new();
        let mut exop_name = None;
        let mut exop_val = None;
        loop {
            match tags.next() {
                None => break,
                Some(comp) => match comp.id {
                    3 => {
                        refs.extend(parse_refs(comp));
                    }
                    10 => {
                        exop_name = Some(
                            String::from_utf8(comp.expect_primitive().expect("octet string"))
                                .expect("exop name"),
                        );
                    }
                    11 => {
                        exop_val = Some(comp.expect_primitive().expect("octet string"));
                    }
                    _ => (),
                },
            }
        }
        LdapResultExt(
            LdapResult {
                rc,
                matched,
                text,
                refs,
                ctrls: vec![],
            },
            Exop {
                name: exop_name,
                val: exop_val,
            },
        )
    }
}

/// Wrapper for results of a Search operation which returns all entries at once.
///
/// The wrapper exists so that methods [`success()`](#method.success) and
/// [`non_error()`](#method.non_error) can be called on an instance. Those methods
/// destructure the wrapper and return its components as elements of an anonymous
/// tuple.
#[derive(Clone, Debug)]
pub struct SearchResult(pub Vec<ResultEntry>, pub LdapResult);

impl SearchResult {
    /// If the result code is zero, return an anonymous tuple of component structs
    /// wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `io::Error`.
    pub fn success(self) -> Result<(Vec<ResultEntry>, LdapResult)> {
        if self.1.rc == 0 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }

    /// If the result code is 0 or 10 (referral), return an anonymous tuple of component
    /// structs wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `io::Error`.
    pub fn non_error(self) -> Result<(Vec<ResultEntry>, LdapResult)> {
        if self.1.rc == 0 || self.1.rc == 10 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }
}

/// Wrapper for the result of a Compare operation.
///
/// Compare uniquely has two non-zero return codes to indicate the outcome of a successful
/// comparison, while other return codes indicate errors, as usual (except 10 for referral).
/// The [`equal()`](#method.equal) method optimizes for the expected case of ignoring
/// referrals; [`non_error()`](#method.non_error) can be used when that's not possible.
#[derive(Clone, Debug)]
pub struct CompareResult(pub LdapResult);

impl CompareResult {
    /// If the result code is 5 (compareFalse) or 6 (compareTrue), return the corresponding
    /// boolean value wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `io::Error`.
    pub fn equal(self) -> Result<bool> {
        match self.0.rc {
            5 => Ok(false),
            6 => Ok(true),
            _ => Err(LdapError::from(self.0)),
        }
    }

    /// If the result code is 5 (compareFalse), 6 (compareTrue),  or 10 (referral), return
    /// the inner `LdapResult`, otherwise rewrap `LdapResult` in an `io::Error`.
    pub fn non_error(self) -> Result<LdapResult> {
        if self.0.rc == 5 || self.0.rc == 6 || self.0.rc == 10 {
            Ok(self.0)
        } else {
            Err(LdapError::from(self.0))
        }
    }
}

/// Wrapper for the result of an Extended operation.
///
/// Similarly to [`SearchResult`](struct.SearchResult.html), methods
/// [`success()`](#method.success) and [`non_error()`](#method.non_error) can be
/// called on an instance, and will destructure the wrapper into an anonymous
/// tuple of its components.
#[derive(Clone, Debug)]
pub struct ExopResult(pub Exop, pub LdapResult);

impl ExopResult {
    /// If the result code is zero, return an anonymous tuple of component structs
    /// wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `io::Error`.
    pub fn success(self) -> Result<(Exop, LdapResult)> {
        if self.1.rc == 0 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }

    /// If the result code is 0 or 10 (referral), return an anonymous tuple of component
    /// structs wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `io::Error`.
    pub fn non_error(self) -> Result<(Exop, LdapResult)> {
        if self.1.rc == 0 || self.1.rc == 10 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }
}
<commit_msg>Update error type in docs<commit_after>//! Operation result structures and helpers.
//!
//! Most LDAP operations return a [`LdapResult`](struct.LdapResult.html). This module
//! contains its definition, as well as that of a number of wrapper structs and
//! helper methods, which adapt LDAP result and error handling to be a closer
//! match to Rust conventions.

use std::error::Error;
use std::fmt;
use std::io;
use std::result::Result as StdResult;

use crate::controls::Control;
use crate::exop::Exop;
use crate::protocol::{LdapOp, MaybeControls, ResultSender};
use crate::search::parse_refs;
use crate::search::ResultEntry;
use crate::RequestId;

use lber::common::TagClass;
use lber::parse::parse_uint;
use lber::structures::Tag;
use lber::universal::Types;
use lber::IResult;

use thiserror::Error;
use tokio::sync::{mpsc, oneshot};
use tokio::time;

/// Type alias for the standard `Result` with the fixed `LdapError` error part.
pub type Result<T> = std::result::Result<T, LdapError>;

/// Error variants recognized by the library.
#[derive(Debug, Error)]
pub enum LdapError {
    /// No path given for a `ldapi://` URL.
    #[error("empty Unix domain socket path")]
    EmptyUnixPath,

    /// A `ldapi://` URL contains a port spec, which it shouldn't.
    #[error("the port must be empty in the ldapi scheme")]
    PortInUnixPath,

    /// Encapsulated I/O error.
    #[error("I/O error: {source}")]
    Io {
        #[from]
        source: io::Error,
    },

    /// Error while sending an operation to the connection handler.
    #[error("op send error: {source}")]
    OpSend {
        #[from]
        source: mpsc::error::SendError<(RequestId, LdapOp, Tag, MaybeControls, ResultSender)>,
    },

    /// Error while receiving operation results from the connection handler.
    #[error("result recv error: {source}")]
    ResultRecv {
        #[from]
        source: oneshot::error::RecvError,
    },

    /// Error while sending an internal ID scrubbing request to the connection handler.
    #[error("id scrub send error: {source}")]
    IdScrubSend {
        #[from]
        source: mpsc::error::SendError<RequestId>,
    },

    /// Operation or connection timeout.
    #[error("timeout: {elapsed}")]
    Timeout {
        #[from]
        elapsed: time::Elapsed,
    },

    /// Error parsing the string representation of a search filter.
    #[error("filter parse error")]
    FilterParsing,

    /// Premature end of a search stream.
    #[error("premature end of search stream")]
    EndOfStream,

    /// URL parsing error.
    #[error("url parse error: {source}")]
    UrlParsing {
        #[from]
        source: url::ParseError,
    },

    /// Unknown LDAP URL scheme.
    #[error("unknown LDAP URL scheme: {0}")]
    UnknownScheme(String),

    #[cfg(feature = "tls")]
    /// Native TLS library error.
    #[error("native TLS error: {source}")]
    NativeTLS {
        #[from]
        source: native_tls::Error,
    },

    /// LDAP operation result with an error return code.
    #[error("LDAP operation result: {result}")]
    LdapResult {
        #[from]
        result: LdapResult,
    },

    /// No values provided for the Add operation.
    #[error("empty value set for Add")]
    AddNoValues,
}

impl From<LdapError> for io::Error {
    fn from(le: LdapError) -> io::Error {
        match le {
            LdapError::Io { source, .. } => source,
            _ => io::Error::new(io::ErrorKind::Other, format!("{}", le)),
        }
    }
}

/// Common components of an LDAP operation result.
///
/// This structure faithfully replicates the components dictated by the standard,
/// and is distinctly C-like with its reliance on numeric codes for the indication
/// of outcome. It would be tempting to hide it behind an automatic `Result`-like
/// interface, but there are scenarios where this would preclude intentional
/// incorporation of error conditions into query design. Instead, the struct
/// implements helper methods, [`success()`](#method.success) and
/// [`non_error()`](#method.non_error), which may be used for ergonomic error
/// handling when simple condition checking suffices.
#[derive(Clone, Debug)]
pub struct LdapResult {
    /// Result code.
    ///
    /// Generally, the value of zero indicates successful completion, but there's
    /// a number of other non-error codes arising as a result of various operations.
    /// See [Section A.1 of RFC 4511](https://tools.ietf.org/html/rfc4511#appendix-A.1).
    pub rc: u32,
    /// Matched component DN, where applicable.
    pub matched: String,
    /// Additional diagnostic text.
    pub text: String,
    /// Referrals.
    ///
    /// Absence of referrals is represented by an empty vector.
    pub refs: Vec<String>,
    /// Response controls.
    ///
    /// Missing and empty controls are both represented by an empty vector.
    pub ctrls: Vec<Control>,
}

#[doc(hidden)]
impl From<Tag> for LdapResult {
    fn from(t: Tag) -> LdapResult {
        <LdapResultExt as From<Tag>>::from(t).0
    }
}

impl Error for LdapResult {}

impl fmt::Display for LdapResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        fn description(this: &LdapResult) -> &'static str {
            match this.rc {
                0 => "success",
                1 => "operationsError",
                2 => "protocolError",
                3 => "timeLimitExceeded",
                4 => "sizeLimitExceeded",
                5 => "compareFalse",
                6 => "compareTrue",
                7 => "authMethodNotSupported",
                8 => "strongerAuthRequired",
                10 => "referral",
                11 => "adminLimitExceeded",
                12 => "unavailableCriticalExtension",
                13 => "confidentialityRequired",
                14 => "saslBindInProgress",
                16 => "noSuchAttribute",
                17 => "undefinedAttributeType",
                18 => "inappropriateMatching",
                19 => "constraintViolation",
                20 => "attributeOrValueExists",
                21 => "invalidAttributeSyntax",
                32 => "noSuchObject",
                33 => "aliasProblem",
                34 => "invalidDNSyntax",
                36 => "aliasDereferencingProblem",
                48 => "inappropriateAuthentication",
                49 => "invalidCredentials",
                50 => "insufficientAccessRights",
                51 => "busy",
                52 => "unavailable",
                53 => "unwillingToPerform",
                54 => "loopDetect",
                64 => "namingViolation",
                65 => "objectClassViolation",
                66 => "notAllowedOnNonLeaf",
                67 => "notAllowedOnRDN",
                68 => "entryAlreadyExists",
                69 => "objectClassModsProhibited",
                71 => "affectsMultipleDSAs",
                80 => "other",
                88 => "abandoned",
                122 => "assertionFailed",
                _ => "unknown",
            }
        }

        write!(
            f,
            "rc={} ({}), dn: \"{}\", text: \"{}\"",
            self.rc,
            description(self),
            self.matched,
            self.text
        )
    }
}

impl LdapResult {
    /// If the result code is zero, return the instance itself wrapped
    /// in `Ok()`, otherwise wrap the instance in an `LdapError`.
    pub fn success(self) -> Result<Self> {
        if self.rc == 0 {
            Ok(self)
        } else {
            Err(LdapError::from(self))
        }
    }

    /// If the result code is 0 or 10 (referral), return the instance
    /// itself wrapped in `Ok()`, otherwise wrap the instance in an
    /// `LdapError`.
    pub fn non_error(self) -> Result<Self> {
        if self.rc == 0 || self.rc == 10 {
            Ok(self)
        } else {
            Err(LdapError::from(self))
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) struct LdapResultExt(pub LdapResult, pub Exop);

impl From<Tag> for LdapResultExt {
    fn from(t: Tag) -> LdapResultExt {
        let t = match t {
            Tag::StructureTag(t) => t,
            Tag::Null(_) => {
                return LdapResultExt(
                    LdapResult {
                        rc: 0,
                        matched: String::from(""),
                        text: String::from(""),
                        refs: vec![],
                        ctrls: vec![],
                    },
                    Exop {
                        name: None,
                        val: None,
                    },
                )
            }
            _ => unimplemented!(),
        };
        let mut tags = t.expect_constructed().expect("result sequence").into_iter();
        let rc = match parse_uint(
            tags.next()
                .expect("element")
                .match_class(TagClass::Universal)
                .and_then(|t| t.match_id(Types::Enumerated as u64))
                .and_then(|t| t.expect_primitive())
                .expect("result code")
                .as_slice(),
        ) {
            IResult::Done(_, rc) => rc as u32,
            _ => panic!("failed to parse result code"),
        };
        let matched = String::from_utf8(
            tags.next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("matched dn");
        let text = String::from_utf8(
            tags.next()
                .expect("element")
                .expect_primitive()
                .expect("octet string"),
        )
        .expect("diagnostic message");
        let mut refs = Vec::new();
        let mut exop_name = None;
        let mut exop_val = None;
        loop {
            match tags.next() {
                None => break,
                Some(comp) => match comp.id {
                    3 => {
                        refs.extend(parse_refs(comp));
                    }
                    10 => {
                        exop_name = Some(
                            String::from_utf8(comp.expect_primitive().expect("octet string"))
                                .expect("exop name"),
                        );
                    }
                    11 => {
                        exop_val = Some(comp.expect_primitive().expect("octet string"));
                    }
                    _ => (),
                },
            }
        }
        LdapResultExt(
            LdapResult {
                rc,
                matched,
                text,
                refs,
                ctrls: vec![],
            },
            Exop {
                name: exop_name,
                val: exop_val,
            },
        )
    }
}

/// Wrapper for results of a Search operation which returns all entries at once.
///
/// The wrapper exists so that methods [`success()`](#method.success) and
/// [`non_error()`](#method.non_error) can be called on an instance. Those methods
/// destructure the wrapper and return its components as elements of an anonymous
/// tuple.
#[derive(Clone, Debug)]
pub struct SearchResult(pub Vec<ResultEntry>, pub LdapResult);

impl SearchResult {
    /// If the result code is zero, return an anonymous tuple of component structs
    /// wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn success(self) -> Result<(Vec<ResultEntry>, LdapResult)> {
        if self.1.rc == 0 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }

    /// If the result code is 0 or 10 (referral), return an anonymous tuple of component
    /// structs wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn non_error(self) -> Result<(Vec<ResultEntry>, LdapResult)> {
        if self.1.rc == 0 || self.1.rc == 10 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }
}

/// Wrapper for the result of a Compare operation.
///
/// Compare uniquely has two non-zero return codes to indicate the outcome of a successful
/// comparison, while other return codes indicate errors, as usual (except 10 for referral).
/// The [`equal()`](#method.equal) method optimizes for the expected case of ignoring
/// referrals; [`non_error()`](#method.non_error) can be used when that's not possible.
#[derive(Clone, Debug)]
pub struct CompareResult(pub LdapResult);

impl CompareResult {
    /// If the result code is 5 (compareFalse) or 6 (compareTrue), return the corresponding
    /// boolean value wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn equal(self) -> Result<bool> {
        match self.0.rc {
            5 => Ok(false),
            6 => Ok(true),
            _ => Err(LdapError::from(self.0)),
        }
    }

    /// If the result code is 5 (compareFalse), 6 (compareTrue),  or 10 (referral), return
    /// the inner `LdapResult`, otherwise rewrap `LdapResult` in an `LdapError`.
    pub fn non_error(self) -> Result<LdapResult> {
        if self.0.rc == 5 || self.0.rc == 6 || self.0.rc == 10 {
            Ok(self.0)
        } else {
            Err(LdapError::from(self.0))
        }
    }
}

/// Wrapper for the result of an Extended operation.
///
/// Similarly to [`SearchResult`](struct.SearchResult.html), methods
/// [`success()`](#method.success) and [`non_error()`](#method.non_error) can be
/// called on an instance, and will destructure the wrapper into an anonymous
/// tuple of its components.
#[derive(Clone, Debug)]
pub struct ExopResult(pub Exop, pub LdapResult);

impl ExopResult {
    /// If the result code is zero, return an anonymous tuple of component structs
    /// wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn success(self) -> Result<(Exop, LdapResult)> {
        if self.1.rc == 0 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }

    /// If the result code is 0 or 10 (referral), return an anonymous tuple of component
    /// structs wrapped in `Ok()`, otherwise wrap the `LdapResult` part in an `LdapError`.
    pub fn non_error(self) -> Result<(Exop, LdapResult)> {
        if self.1.rc == 0 || self.1.rc == 10 {
            Ok((self.0, self.1))
        } else {
            Err(LdapError::from(self.1))
        }
    }
}
<|endoftext|>


<commit_before>use std::io::File;
use std::io::BufferedReader;

pub fn scope_start(src:&str, point:uint) -> uint {
    let s = src.slice(0,point);
    let mut pt = point;
    let mut levels = 0;
    for c in s.chars_rev() {
        if c == '{' {
            if levels == 0 {
                break;
            } else {
                levels -= 1;
            }
        }
        if c == '}' {
            levels += 1;
        }
        pt -= 1;
    }
    return pt;
}

fn gen_mask(mut len: uint) -> ~str {
    let mut s = ~"";
    while len != 0 {
        len -=1;
        s.push_str(" ");
    }
    return s;
}

pub fn mask_comments(src:&str) -> ~str {
    let mut result = ~"";
    let mut s:&str = src;
    let mut in_comment = false;
    let mut res = s.find_str("//");
    let mut pos = 0;
    while res.is_some() {
        let end = res.unwrap();
        if in_comment {
            // mask out the comment
            result.push_str(gen_mask(end));
            s = s.slice_from(end);
            res = s.find_str("//");
            in_comment = false;
        } else {
            result.push_str(s.slice_to(end));
            s = s.slice_from(end);
            res = s.find_str("\n");
            in_comment = true;
        }
        pos += end;
    }
    result.push_str(src.slice_from(pos));
    return result;
}

pub fn mask_sub_scopes(src:&str) -> ~str {
    let mut result = ~"";
    let mut levels = 0;

    for c in src.chars() {
        if c == '}' {
            levels -= 1;
        }

        if c == '\n' {
            result.push_char(c);
        } else if levels > 0 {
            result.push_str(" ");
        } else {
            result.push_char(c);
        }

        if c == '{' {
            levels += 1;
        }
    }
    return result;
}

pub fn coords_to_point(src: &str, mut linenum: uint, col: uint) -> uint {
    let mut point=0;
    for line in src.lines() {
        linenum -= 1;
        if linenum == 0 { break }
        point+=line.len() + 1;  // +1 for the \n
    }
    return point + col;
}

pub fn point_to_coords(src:&str, point:uint) -> (uint, uint) {
    let mut i = 0;
    let mut linestart = 0;
    let mut nlines = 1;  // lines start at 1
    while i != point {
        if src.char_at(i) == '\n' {
            nlines += 1;
            linestart = i+1;
        }
        i+=1;
    }
    return (nlines, point - linestart);
}

pub fn point_to_coords2(path: &Path, point:uint) -> Option<(uint, uint)> {
    let mut lineno = 0;
    let mut file = BufferedReader::new(File::open(path));
    let mut p = 0;
    for line_r in file.lines() {
        let line = line_r.unwrap();
        lineno += 1;
        if point < (p + line.len()) {
            return Some((lineno, point - p));
        }
        p += line.len();
    }
    return None;
}

#[test]
fn coords_to_point_works() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}";
    assert!(coords_to_point(src, 3, 5) == 18);
}

#[test]
fn test_scope_start() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}
";
    let point = coords_to_point(src, 4, 10);
    let start = scope_start(src,point);
    assert!(start == 12);
}

#[test]
fn test_scope_start_handles_sub_scopes() {
    let src = "
fn myfn() {
    let a = 3;
    {
      let b = 4;
    }
    print(a);
}
";
    let point = coords_to_point(src, 7, 10);
    let start = scope_start(src,point);
    assert!(start == 12);
}

#[test]
fn masks_out_comments() {
    let src = "
this is some code
this is a line // with a comment
some more
";
    let r = mask_comments(src.to_owned());
    assert!(src.len() == r.len());
    // characters at the start are the same
    assert!(src[5] == r[5]);
    // characters in the comments are masked
    let commentoffset = coords_to_point(src,3,23);
    assert!(r.char_at(commentoffset) == ' ');
    assert!(src[commentoffset] != r[commentoffset]);
    // characters afterwards are the same
    assert!(src[src.len()-3] == r[src.len()-3]);
}

#[test]
fn masks_out_sub_scopes() {
    let src = "
this is some code
{
  this is a sub-scope
  {
    so is this
  }
  and this
}
some more code
";
    let expected = "
this is some code
{

}
some more code
";
    let res = mask_sub_scopes(src);
    assert!(expected == res);
}

#[test]
fn test_point_to_coords() {
    let src = "
fn myfn(b:uint) {
   let a = 3;
   if b == 12 {
       let a = 24;
       do_something_with(a);
   }
   do_something_with(a);
}
";
    round_trip_point_and_coords(src, 4, 5);
}

fn round_trip_point_and_coords(src:&str, lineno:uint, charno:uint) {
    let (a,b) = point_to_coords(src, coords_to_point(src, lineno, charno));
     assert_eq!((a,b),(lineno,charno));
}

#[test]
fn generates_the_visible_scope() {
    let src = "
fn myfn(b:uint) {
   let a = 3;
   if b == 12 {
       let a = 24;
       do_something_with(a);
   }
   do_something_with(a);
}
";
    let expected = "
   let a = 3;
   if b == 12 {

   }
   do_something_with(";
    let point = coords_to_point(src,8,21);
    let s = mask_comments(src);
    let n = scope_start(s, point);
    let res = mask_sub_scopes(s.slice(n,point));
    assert!(expected == res);
}

<commit_msg>Updated scopes.rs to use StrBuf.<commit_after>use std::io::File;
use std::io::BufferedReader;
use std::strbuf::StrBuf;

pub fn scope_start(src:&str, point:uint) -> uint {
    let s = src.slice(0,point);
    let mut pt = point;
    let mut levels = 0;
    for c in s.chars_rev() {
        if c == '{' {
            if levels == 0 {
                break;
            } else {
                levels -= 1;
            }
        }
        if c == '}' {
            levels += 1;
        }
        pt -= 1;
    }
    return pt;
}

fn gen_mask(mut len: uint) -> ~str {
    let mut s = StrBuf::new();
    while len != 0 {
        len -=1;
        s.push_char(' ');
    }
    return s.into_owned();
}

pub fn mask_comments(src:&str) -> ~str {
    let mut result = StrBuf::new();
    let mut s:&str = src;
    let mut in_comment = false;
    let mut res = s.find_str("//");
    let mut pos = 0;
    while res.is_some() {
        let end = res.unwrap();
        if in_comment {
            // mask out the comment
            result.push_str(gen_mask(end));
            s = s.slice_from(end);
            res = s.find_str("//");
            in_comment = false;
        } else {
            result.push_str(s.slice_to(end));
            s = s.slice_from(end);
            res = s.find_str("\n");
            in_comment = true;
        }
        pos += end;
    }
    result.push_str(src.slice_from(pos));
    return result.into_owned();
}

pub fn mask_sub_scopes(src:&str) -> ~str {
    let mut result = StrBuf::new();
    let mut levels = 0;

    for c in src.chars() {
        if c == '}' {
            levels -= 1;
        }

        if c == '\n' {
            result.push_char(c);
        } else if levels > 0 {
            result.push_char(' ');
        } else {
            result.push_char(c);
        }

        if c == '{' {
            levels += 1;
        }
    }
    return result.into_owned();
}

pub fn coords_to_point(src: &str, mut linenum: uint, col: uint) -> uint {
    let mut point=0;
    for line in src.lines() {
        linenum -= 1;
        if linenum == 0 { break }
        point+=line.len() + 1;  // +1 for the \n
    }
    return point + col;
}

pub fn point_to_coords(src:&str, point:uint) -> (uint, uint) {
    let mut i = 0;
    let mut linestart = 0;
    let mut nlines = 1;  // lines start at 1
    while i != point {
        if src.char_at(i) == '\n' {
            nlines += 1;
            linestart = i+1;
        }
        i+=1;
    }
    return (nlines, point - linestart);
}

pub fn point_to_coords2(path: &Path, point:uint) -> Option<(uint, uint)> {
    let mut lineno = 0;
    let mut file = BufferedReader::new(File::open(path));
    let mut p = 0;
    for line_r in file.lines() {
        let line = line_r.unwrap();
        lineno += 1;
        if point < (p + line.len()) {
            return Some((lineno, point - p));
        }
        p += line.len();
    }
    return None;
}

#[test]
fn coords_to_point_works() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}";
    assert!(coords_to_point(src, 3, 5) == 18);
}

#[test]
fn test_scope_start() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}
";
    let point = coords_to_point(src, 4, 10);
    let start = scope_start(src,point);
    assert!(start == 12);
}

#[test]
fn test_scope_start_handles_sub_scopes() {
    let src = "
fn myfn() {
    let a = 3;
    {
      let b = 4;
    }
    print(a);
}
";
    let point = coords_to_point(src, 7, 10);
    let start = scope_start(src,point);
    assert!(start == 12);
}

#[test]
fn masks_out_comments() {
    let src = "
this is some code
this is a line // with a comment
some more
";
    let r = mask_comments(src.to_owned());
    assert!(src.len() == r.len());
    // characters at the start are the same
    assert!(src[5] == r[5]);
    // characters in the comments are masked
    let commentoffset = coords_to_point(src,3,23);
    assert!(r.char_at(commentoffset) == ' ');
    assert!(src[commentoffset] != r[commentoffset]);
    // characters afterwards are the same
    assert!(src[src.len()-3] == r[src.len()-3]);
}

#[test]
fn masks_out_sub_scopes() {
    let src = "
this is some code
{
  this is a sub-scope
  {
    so is this
  }
  and this
}
some more code
";
    let expected = "
this is some code
{

}
some more code
";
    let res = mask_sub_scopes(src);
    assert!(expected == res);
}

#[test]
fn test_point_to_coords() {
    let src = "
fn myfn(b:uint) {
   let a = 3;
   if b == 12 {
       let a = 24;
       do_something_with(a);
   }
   do_something_with(a);
}
";
    round_trip_point_and_coords(src, 4, 5);
}

fn round_trip_point_and_coords(src:&str, lineno:uint, charno:uint) {
    let (a,b) = point_to_coords(src, coords_to_point(src, lineno, charno));
     assert_eq!((a,b),(lineno,charno));
}

#[test]
fn generates_the_visible_scope() {
    let src = "
fn myfn(b:uint) {
   let a = 3;
   if b == 12 {
       let a = 24;
       do_something_with(a);
   }
   do_something_with(a);
}
";
    let expected = "
   let a = 3;
   if b == 12 {

   }
   do_something_with(";
    let point = coords_to_point(src,8,21);
    let s = mask_comments(src);
    let n = scope_start(s, point);
    let res = mask_sub_scopes(s.slice(n,point));
    assert!(expected == res);
}

<|endoftext|>