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

//! An experimental pass that scources for `#[rustc_mir]` attributes,
//! builds the resulting MIR, and dumps it out into a file for inspection.
//!
//! The attribute formats that are currently accepted are:
//!
//! - `#[rustc_mir(graphviz="file.gv")]`
//! - `#[rustc_mir(pretty="file.mir")]`

extern crate syntax;
extern crate rustc;
extern crate rustc_front;

use build;
use dot;
use repr::Mir;
use std::fs::File;
use tcx::{PatNode, Cx};

use self::rustc::middle::infer;
use self::rustc::middle::region::CodeExtentData;
use self::rustc::middle::ty::{self, Ty};
use self::rustc::util::common::ErrorReported;
use self::rustc_front::hir;
use self::rustc_front::visit;
use self::syntax::ast;
use self::syntax::attr::AttrMetaMethods;
use self::syntax::codemap::Span;

pub fn dump_crate(tcx: &ty::ctxt) {
    let mut dump = OuterDump { tcx: tcx };
    visit::walk_crate(&mut dump, tcx.map.krate());
}

///////////////////////////////////////////////////////////////////////////
// OuterDump -- walks a crate, looking for fn items and methods to build MIR from

struct OuterDump<'a,'tcx:'a> {
    tcx: &'a ty::ctxt<'tcx>,
}

impl<'a, 'tcx> OuterDump<'a, 'tcx> {
    fn visit_mir<OP>(&self, attributes: &'tcx [ast::Attribute], mut walk_op: OP)
        where OP: FnMut(&mut InnerDump<'a,'tcx>)
    {
        let mut built_mir = false;

        for attr in attributes {
            if attr.check_name("rustc_mir") {
                let mut closure_dump = InnerDump { tcx: self.tcx, attr: Some(attr) };
                walk_op(&mut closure_dump);
                built_mir = true;
            }
        }

        let always_build_mir = self.tcx.sess.opts.always_build_mir;
        if !built_mir && always_build_mir {
            let mut closure_dump = InnerDump { tcx: self.tcx, attr: None };
            walk_op(&mut closure_dump);
        }
    }
}

impl<'a, 'tcx> visit::Visitor<'tcx> for OuterDump<'a, 'tcx> {
    fn visit_item(&mut self, item: &'tcx hir::Item) {
        self.visit_mir(&item.attrs, |c| visit::walk_item(c, item));
        visit::walk_item(self, item);
    }

    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
        match trait_item.node {
            hir::MethodTraitItem(_, Some(_)) => {
                self.visit_mir(&trait_item.attrs, |c| visit::walk_trait_item(c, trait_item));
            }
            _ => { }
        }
        visit::walk_trait_item(self, trait_item);
    }
}

///////////////////////////////////////////////////////////////////////////
// InnerDump -- dumps MIR for a single fn and its contained closures

struct InnerDump<'a,'tcx:'a> {
    tcx: &'a ty::ctxt<'tcx>,
    attr: Option<&'a ast::Attribute>,
}

impl<'a, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'tcx> {
    fn visit_item(&mut self, _: &'tcx hir::Item) {
        // ignore nested items; they need their own graphviz annotation
    }

    fn visit_fn(&mut self,
                fk: visit::FnKind<'tcx>,
                decl: &'tcx hir::FnDecl,
                body: &'tcx hir::Block,
                span: Span,
                id: ast::NodeId) {
        let (prefix, implicit_arg_tys) = match fk {
            visit::FnKind::Closure =>
                (format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]),
            _ =>
                (format!(""), vec![]),
        };

        let param_env =
            ty::ParameterEnvironment::for_item(self.tcx, id);

        let infcx =
            infer::new_infer_ctxt(self.tcx,
                                  &self.tcx.tables,
                                  Some(param_env),
                                  true);

        match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
            Ok(mir) => {
                let meta_item_list =
                    self.attr.iter()
                             .flat_map(|a| a.meta_item_list())
                             .flat_map(|l| l.iter());
                for item in meta_item_list {
                    if item.check_name("graphviz") {
                        match item.value_str() {
                            Some(s) => {
                                match
                                    File::create(format!("{}{}", prefix, s))
                                    .and_then(|ref mut output| dot::render(&mir, output))
                                {
                                    Ok(()) => { }
                                    Err(e) => {
                                        self.tcx.sess.span_fatal(
                                            item.span,
                                            &format!("Error writing graphviz \
                                                      results to `{}`: {}",
                                                     s, e));
                                    }
                                }
                            }
                            None => {
                                self.tcx.sess.span_err(
                                    item.span,
                                    &format!("graphviz attribute requires a path"));
                            }
                        }
                    }
                }
            }
            Err(ErrorReported) => { }
        }

        visit::walk_fn(self, fk, decl, body, span);
    }
}

fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
                         implicit_arg_tys: Vec<Ty<'tcx>>,
                         fn_id: ast::NodeId,
                         span: Span,
                         decl: &'tcx hir::FnDecl,
                         body: &'tcx hir::Block)
                         -> Result<Mir<Cx<'a,'tcx>>, ErrorReported> {
    let arguments =
        decl.inputs
            .iter()
            .map(|arg| {
                let ty = cx.tcx.node_id_to_type(arg.id);
                (ty, PatNode::irrefutable(&arg.pat))
            })
            .collect();

    let parameter_scope =
        cx.tcx.region_maps.lookup_code_extent(
            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
    Ok(build::construct(cx,
                        span,
                        implicit_arg_tys,
                        arguments,
                        parameter_scope,
                        body))
}

fn closure_self_ty<'a,'tcx>(tcx: &ty::ctxt<'tcx>,
                            closure_expr_id: ast::NodeId,
                            body_id: ast::NodeId)
                            -> Ty<'tcx>
{
    let closure_ty = tcx.node_id_to_type(closure_expr_id);

    // We're just hard-coding the idea that the signature will be
    // &self or &mut self and hence will have a bound region with
    // number 0, hokey.
    let region =
        ty::Region::ReFree(
            ty::FreeRegion {
                scope: tcx.region_maps.item_extent(body_id),
                bound_region: ty::BoundRegion::BrAnon(0)
            });
    let region =
        tcx.mk_region(region);

    match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
        ty::ClosureKind::FnClosureKind =>
            tcx.mk_ref(region,
                       ty::TypeAndMut { ty: closure_ty,
                                        mutbl: hir::MutImmutable }),
        ty::ClosureKind::FnMutClosureKind =>
            tcx.mk_ref(region,
                       ty::TypeAndMut { ty: closure_ty,
                                        mutbl: hir::MutMutable }),
        ty::ClosureKind::FnOnceClosureKind =>
            closure_ty
    }
}
<commit_msg>always build MIR<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An experimental pass that scources for `#[rustc_mir]` attributes,
//! builds the resulting MIR, and dumps it out into a file for inspection.
//!
//! The attribute formats that are currently accepted are:
//!
//! - `#[rustc_mir(graphviz="file.gv")]`
//! - `#[rustc_mir(pretty="file.mir")]`

extern crate syntax;
extern crate rustc;
extern crate rustc_front;

use build;
use dot;
use repr::Mir;
use std::fs::File;
use tcx::{PatNode, Cx};

use self::rustc::middle::infer;
use self::rustc::middle::region::CodeExtentData;
use self::rustc::middle::ty::{self, Ty};
use self::rustc::util::common::ErrorReported;
use self::rustc_front::hir;
use self::rustc_front::visit;
use self::syntax::ast;
use self::syntax::attr::AttrMetaMethods;
use self::syntax::codemap::Span;

pub fn dump_crate(tcx: &ty::ctxt) {
    let mut dump = OuterDump { tcx: tcx };
    visit::walk_crate(&mut dump, tcx.map.krate());
}

///////////////////////////////////////////////////////////////////////////
// OuterDump -- walks a crate, looking for fn items and methods to build MIR from

struct OuterDump<'a,'tcx:'a> {
    tcx: &'a ty::ctxt<'tcx>,
}

impl<'a, 'tcx> OuterDump<'a, 'tcx> {
    fn visit_mir<OP>(&self, attributes: &'tcx [ast::Attribute], mut walk_op: OP)
        where OP: FnMut(&mut InnerDump<'a,'tcx>)
    {
        let mut built_mir = false;

        for attr in attributes {
            if attr.check_name("rustc_mir") {
                let mut closure_dump = InnerDump { tcx: self.tcx, attr: Some(attr) };
                walk_op(&mut closure_dump);
                built_mir = true;
            }
        }

        let always_build_mir = true;
        if !built_mir && always_build_mir {
            let mut closure_dump = InnerDump { tcx: self.tcx, attr: None };
            walk_op(&mut closure_dump);
        }
    }
}

impl<'a, 'tcx> visit::Visitor<'tcx> for OuterDump<'a, 'tcx> {
    fn visit_item(&mut self, item: &'tcx hir::Item) {
        self.visit_mir(&item.attrs, |c| visit::walk_item(c, item));
        visit::walk_item(self, item);
    }

    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
        match trait_item.node {
            hir::MethodTraitItem(_, Some(_)) => {
                self.visit_mir(&trait_item.attrs, |c| visit::walk_trait_item(c, trait_item));
            }
            _ => { }
        }
        visit::walk_trait_item(self, trait_item);
    }
}

///////////////////////////////////////////////////////////////////////////
// InnerDump -- dumps MIR for a single fn and its contained closures

struct InnerDump<'a,'tcx:'a> {
    tcx: &'a ty::ctxt<'tcx>,
    attr: Option<&'a ast::Attribute>,
}

impl<'a, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'tcx> {
    fn visit_item(&mut self, _: &'tcx hir::Item) {
        // ignore nested items; they need their own graphviz annotation
    }

    fn visit_fn(&mut self,
                fk: visit::FnKind<'tcx>,
                decl: &'tcx hir::FnDecl,
                body: &'tcx hir::Block,
                span: Span,
                id: ast::NodeId) {
        let (prefix, implicit_arg_tys) = match fk {
            visit::FnKind::Closure =>
                (format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]),
            _ =>
                (format!(""), vec![]),
        };

        let param_env =
            ty::ParameterEnvironment::for_item(self.tcx, id);

        let infcx =
            infer::new_infer_ctxt(self.tcx,
                                  &self.tcx.tables,
                                  Some(param_env),
                                  true);

        match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
            Ok(mir) => {
                let meta_item_list =
                    self.attr.iter()
                             .flat_map(|a| a.meta_item_list())
                             .flat_map(|l| l.iter());
                for item in meta_item_list {
                    if item.check_name("graphviz") {
                        match item.value_str() {
                            Some(s) => {
                                match
                                    File::create(format!("{}{}", prefix, s))
                                    .and_then(|ref mut output| dot::render(&mir, output))
                                {
                                    Ok(()) => { }
                                    Err(e) => {
                                        self.tcx.sess.span_fatal(
                                            item.span,
                                            &format!("Error writing graphviz \
                                                      results to `{}`: {}",
                                                     s, e));
                                    }
                                }
                            }
                            None => {
                                self.tcx.sess.span_err(
                                    item.span,
                                    &format!("graphviz attribute requires a path"));
                            }
                        }
                    }
                }
            }
            Err(ErrorReported) => { }
        }

        visit::walk_fn(self, fk, decl, body, span);
    }
}

fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
                         implicit_arg_tys: Vec<Ty<'tcx>>,
                         fn_id: ast::NodeId,
                         span: Span,
                         decl: &'tcx hir::FnDecl,
                         body: &'tcx hir::Block)
                         -> Result<Mir<Cx<'a,'tcx>>, ErrorReported> {
    let arguments =
        decl.inputs
            .iter()
            .map(|arg| {
                let ty = cx.tcx.node_id_to_type(arg.id);
                (ty, PatNode::irrefutable(&arg.pat))
            })
            .collect();

    let parameter_scope =
        cx.tcx.region_maps.lookup_code_extent(
            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
    Ok(build::construct(cx,
                        span,
                        implicit_arg_tys,
                        arguments,
                        parameter_scope,
                        body))
}

fn closure_self_ty<'a,'tcx>(tcx: &ty::ctxt<'tcx>,
                            closure_expr_id: ast::NodeId,
                            body_id: ast::NodeId)
                            -> Ty<'tcx>
{
    let closure_ty = tcx.node_id_to_type(closure_expr_id);

    // We're just hard-coding the idea that the signature will be
    // &self or &mut self and hence will have a bound region with
    // number 0, hokey.
    let region =
        ty::Region::ReFree(
            ty::FreeRegion {
                scope: tcx.region_maps.item_extent(body_id),
                bound_region: ty::BoundRegion::BrAnon(0)
            });
    let region =
        tcx.mk_region(region);

    match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
        ty::ClosureKind::FnClosureKind =>
            tcx.mk_ref(region,
                       ty::TypeAndMut { ty: closure_ty,
                                        mutbl: hir::MutImmutable }),
        ty::ClosureKind::FnMutClosureKind =>
            tcx.mk_ref(region,
                       ty::TypeAndMut { ty: closure_ty,
                                        mutbl: hir::MutMutable }),
        ty::ClosureKind::FnOnceClosureKind =>
            closure_ty
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate rand;

pub const DEFAULT_ENGLISH_DICTIONARY_PATH: &'static str = "/usr/share/dict/words";

#[derive(Debug)]
pub struct EnglishPasswordOptions {
    pub num_words: u8,
    pub dictionary_path: String,
}

#[derive(Debug)]
pub struct KanaPasswordOptions {
    pub syllable_counts: Vec<u8>,
}

pub enum PasswordOptions {
    English(EnglishPasswordOptions),
    Japanese(KanaPasswordOptions),
}

mod args {
    use clap::{value_t, values_t};

    // Aborts this process on error.
    pub fn parse_args() -> crate::PasswordOptions {
        let matches = clap::App::new("xkpw")
            .version("0.1.0")
            .author("j39m")
            .about("Generates passwords")
            .subcommand(
                clap::SubCommand::with_name("en")
                    .about("generates dictionary passwords in English")
                    .arg(clap::Arg::with_name("num-words").required(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("jp")
                    .about("generates random strings of Japanese syllables")
                    .arg(
                        clap::Arg::with_name("syllable-counts")
                            .required(true)
                            .multiple(true),
                    ),
            )
            .get_matches();

        match matches.subcommand() {
            ("en", Some(en_matches)) => {
                return crate::PasswordOptions::English(crate::EnglishPasswordOptions {
                    num_words: clap::value_t!(en_matches, "num-words", u8)
                        .unwrap_or_else(|e| e.exit()),
                    dictionary_path: crate::DEFAULT_ENGLISH_DICTIONARY_PATH.to_owned(),
                })
            }
            ("jp", Some(jp_matches)) => {
                return crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
                    syllable_counts: clap::values_t!(jp_matches, "syllable-counts", u8)
                        .unwrap_or_else(|e| e.exit()),
                })
            }
            _ => (),
        }
        crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
            syllable_counts: vec![4, 3, 3, 3],
        })
    }
} // mod args

mod kana {
    pub const BASE: &'static [&str] = &[
        "a", "i", "u", "e", "o", "ka", "ki", "ku", "ke", "ko", "sa", "shi", "su", "se", "so", "ta",
        "chi", "tsu", "te", "to", "na", "ni", "nu", "ne", "no", "ha", "hi", "hu", "he", "ho", "ma",
        "mi", "mu", "me", "mo", "ya", "yu", "yo", "ra", "ri", "ru", "re", "ro", "wa", "wo",
    ];

    pub const DIGRAPHS: &'static [&str] = &[
        "kya", "kyu", "kyo", "sha", "shu", "sho", "cha", "chu", "cho", "nya", "nyu", "nyo", "hya",
        "hyu", "hyo", "mya", "myu", "myo", "rya", "ryu", "ryo",
    ];

    pub const DIACRITICS: &'static [&str] = &[
        "ga", "gi", "gu", "ge", "go", "za", "ji", "zu", "ze", "zo", "da", "de", "do", "ba", "bi",
        "bu", "be", "bo", "pa", "pi", "pu", "pe", "po",
    ];

    pub const DIGRAPHS_WITH_DIACRITICS: &'static [&str] = &[
        "gya", "gyu", "gyo", "ja", "ju", "jo", "bya", "byu", "byo", "pya", "pyu", "pyo",
    ];

    fn all() -> Vec<&'static str> {
        let mut all_kana: Vec<&'static str> = Vec::new();
        all_kana.extend(BASE);
        all_kana.extend(DIGRAPHS);
        all_kana.extend(DIACRITICS);
        all_kana.extend(DIGRAPHS_WITH_DIACRITICS);
        all_kana
    }

    fn simple() -> Vec<&'static str> {
        let mut simple_kana: Vec<&'static str> = Vec::new();
        simple_kana.extend(BASE);
        simple_kana.extend(DIACRITICS);
        simple_kana
    }

    pub fn get(use_simple: bool) -> Vec<&'static str> {
        match use_simple {
            true => simple(),
            false => all(),
        }
    }
} // mod kana

mod helpers {
    use rand::seq::SliceRandom;
    use std::convert::TryInto;
    use std::io::Read;

    // Reads the dictionary at |path| and returns a linewise vector of
    // its contents.
    fn ingest_english_dictionary(path: &std::path::Path) -> std::io::Result<Vec<String>> {
        let mut file = std::fs::File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(contents
            .lines()
            .map(|word| word.trim().to_lowercase())
            .collect())
    }

    // Assumes ownership of a Vector of owned |words| and prints them
    // separated by spaces.
    fn print_words(words: Vec<String>) {
        let mut iter = words.into_iter();
        if let Some(word) = iter.next() {
            print!("{}", word);
            for word in iter {
                print!(" {}", word);
            }
            print!("\n");
        }
    }

    // Returns 1 if we fail to read the word dictionary.
    fn print_english_password(options: crate::EnglishPasswordOptions) -> i32 {
        let all_words =
            match ingest_english_dictionary(std::path::Path::new(&options.dictionary_path)) {
                Ok(result) => result,
                Err(error) => {
                    eprintln!("Error reading dictionary: {}", error);
                    return 1;
                }
            };
        let mut rng = &mut rand::thread_rng();
        let selection: Vec<String> = all_words
            .choose_multiple(&mut rng, options.num_words.try_into().unwrap())
            .map(|borrowed| borrowed.to_owned())
            .collect();

        print_words(selection);
        0
    }

    // Builds a single random pseudo-Japanese word from |kana_set|.
    fn build_kana_word(kana_set: &Vec<&'static str>, syllable_count: &u8) -> String {
        let mut collected_kana: Vec<&'static str> = Vec::new();
        let mut rng = &mut rand::thread_rng();
        for _ in 0..*syllable_count {
            collected_kana.push(kana_set.choose(&mut rng).unwrap());
        }
        collected_kana.join("")
    }

    // Builds random pseudo-Japanese words from |kana_set|, observing
    // the word lengths specified by |options|.
    fn build_kana_words(
        kana_set: Vec<&'static str>,
        options: crate::KanaPasswordOptions,
    ) -> Vec<String> {
        options
            .syllable_counts
            .iter()
            .map(|count| build_kana_word(&kana_set, count))
            .collect()
    }

    // Builds a vector of owned kana words, maps these to a vector of
    // borrowed kana words, and then prints the same.
    fn print_kana_password(options: crate::KanaPasswordOptions) {
        print_words(build_kana_words(crate::kana::get(true), options));
    }

    pub fn main() -> i32 {
        let options = crate::args::parse_args();
        match options {
            crate::PasswordOptions::English(options) => return print_english_password(options),
            crate::PasswordOptions::Japanese(options) => print_kana_password(options),
        }
        0
    }
} // mod helpers

fn main() {
    std::process::exit(crate::helpers::main());
}
<commit_msg>xkpw: unpublish kana arrays<commit_after>extern crate clap;
extern crate rand;

pub const DEFAULT_ENGLISH_DICTIONARY_PATH: &'static str = "/usr/share/dict/words";

#[derive(Debug)]
pub struct EnglishPasswordOptions {
    pub num_words: u8,
    pub dictionary_path: String,
}

#[derive(Debug)]
pub struct KanaPasswordOptions {
    pub syllable_counts: Vec<u8>,
}

pub enum PasswordOptions {
    English(EnglishPasswordOptions),
    Japanese(KanaPasswordOptions),
}

mod args {
    use clap::{value_t, values_t};

    // Aborts this process on error.
    pub fn parse_args() -> crate::PasswordOptions {
        let matches = clap::App::new("xkpw")
            .version("0.1.0")
            .author("j39m")
            .about("Generates passwords")
            .subcommand(
                clap::SubCommand::with_name("en")
                    .about("generates dictionary passwords in English")
                    .arg(clap::Arg::with_name("num-words").required(true)),
            )
            .subcommand(
                clap::SubCommand::with_name("jp")
                    .about("generates random strings of Japanese syllables")
                    .arg(
                        clap::Arg::with_name("syllable-counts")
                            .required(true)
                            .multiple(true),
                    ),
            )
            .get_matches();

        match matches.subcommand() {
            ("en", Some(en_matches)) => {
                return crate::PasswordOptions::English(crate::EnglishPasswordOptions {
                    num_words: clap::value_t!(en_matches, "num-words", u8)
                        .unwrap_or_else(|e| e.exit()),
                    dictionary_path: crate::DEFAULT_ENGLISH_DICTIONARY_PATH.to_owned(),
                })
            }
            ("jp", Some(jp_matches)) => {
                return crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
                    syllable_counts: clap::values_t!(jp_matches, "syllable-counts", u8)
                        .unwrap_or_else(|e| e.exit()),
                })
            }
            _ => (),
        }
        crate::PasswordOptions::Japanese(crate::KanaPasswordOptions {
            syllable_counts: vec![4, 3, 3, 3],
        })
    }
} // mod args

mod kana {
    const BASE: &'static [&str] = &[
        "a", "i", "u", "e", "o", "ka", "ki", "ku", "ke", "ko", "sa", "shi", "su", "se", "so", "ta",
        "chi", "tsu", "te", "to", "na", "ni", "nu", "ne", "no", "ha", "hi", "hu", "he", "ho", "ma",
        "mi", "mu", "me", "mo", "ya", "yu", "yo", "ra", "ri", "ru", "re", "ro", "wa", "wo",
    ];

    const DIGRAPHS: &'static [&str] = &[
        "kya", "kyu", "kyo", "sha", "shu", "sho", "cha", "chu", "cho", "nya", "nyu", "nyo", "hya",
        "hyu", "hyo", "mya", "myu", "myo", "rya", "ryu", "ryo",
    ];

    const DIACRITICS: &'static [&str] = &[
        "ga", "gi", "gu", "ge", "go", "za", "ji", "zu", "ze", "zo", "da", "de", "do", "ba", "bi",
        "bu", "be", "bo", "pa", "pi", "pu", "pe", "po",
    ];

    const DIGRAPHS_WITH_DIACRITICS: &'static [&str] = &[
        "gya", "gyu", "gyo", "ja", "ju", "jo", "bya", "byu", "byo", "pya", "pyu", "pyo",
    ];

    fn all() -> Vec<&'static str> {
        let mut all_kana: Vec<&'static str> = Vec::new();
        all_kana.extend(BASE);
        all_kana.extend(DIGRAPHS);
        all_kana.extend(DIACRITICS);
        all_kana.extend(DIGRAPHS_WITH_DIACRITICS);
        all_kana
    }

    fn simple() -> Vec<&'static str> {
        let mut simple_kana: Vec<&'static str> = Vec::new();
        simple_kana.extend(BASE);
        simple_kana.extend(DIACRITICS);
        simple_kana
    }

    pub fn get(use_simple: bool) -> Vec<&'static str> {
        match use_simple {
            true => simple(),
            false => all(),
        }
    }
} // mod kana

mod helpers {
    use rand::seq::SliceRandom;
    use std::convert::TryInto;
    use std::io::Read;

    // Reads the dictionary at |path| and returns a linewise vector of
    // its contents.
    fn ingest_english_dictionary(path: &std::path::Path) -> std::io::Result<Vec<String>> {
        let mut file = std::fs::File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(contents
            .lines()
            .map(|word| word.trim().to_lowercase())
            .collect())
    }

    // Assumes ownership of a Vector of owned |words| and prints them
    // separated by spaces.
    fn print_words(words: Vec<String>) {
        let mut iter = words.into_iter();
        if let Some(word) = iter.next() {
            print!("{}", word);
            for word in iter {
                print!(" {}", word);
            }
            print!("\n");
        }
    }

    // Returns 1 if we fail to read the word dictionary.
    fn print_english_password(options: crate::EnglishPasswordOptions) -> i32 {
        let all_words =
            match ingest_english_dictionary(std::path::Path::new(&options.dictionary_path)) {
                Ok(result) => result,
                Err(error) => {
                    eprintln!("Error reading dictionary: {}", error);
                    return 1;
                }
            };
        let mut rng = &mut rand::thread_rng();
        let selection: Vec<String> = all_words
            .choose_multiple(&mut rng, options.num_words.try_into().unwrap())
            .map(|borrowed| borrowed.to_owned())
            .collect();

        print_words(selection);
        0
    }

    // Builds a single random pseudo-Japanese word from |kana_set|.
    fn build_kana_word(kana_set: &Vec<&'static str>, syllable_count: &u8) -> String {
        let mut collected_kana: Vec<&'static str> = Vec::new();
        let mut rng = &mut rand::thread_rng();
        for _ in 0..*syllable_count {
            collected_kana.push(kana_set.choose(&mut rng).unwrap());
        }
        collected_kana.join("")
    }

    // Builds random pseudo-Japanese words from |kana_set|, observing
    // the word lengths specified by |options|.
    fn build_kana_words(
        kana_set: Vec<&'static str>,
        options: crate::KanaPasswordOptions,
    ) -> Vec<String> {
        options
            .syllable_counts
            .iter()
            .map(|count| build_kana_word(&kana_set, count))
            .collect()
    }

    // Builds a vector of owned kana words, maps these to a vector of
    // borrowed kana words, and then prints the same.
    fn print_kana_password(options: crate::KanaPasswordOptions) {
        print_words(build_kana_words(crate::kana::get(true), options));
    }

    pub fn main() -> i32 {
        let options = crate::args::parse_args();
        match options {
            crate::PasswordOptions::English(options) => return print_english_password(options),
            crate::PasswordOptions::Japanese(options) => print_kana_password(options),
        }
        0
    }
} // mod helpers

fn main() {
    std::process::exit(crate::helpers::main());
}
<|endoftext|>


<commit_before>pub mod anoncreds;
pub mod crypto;
pub mod sovrin;
pub mod wallet;

use commands::sovrin::{SovrinCommand, SovrinCommandExecutor};
use commands::wallet::{WalletCommand, WalletCommandExecutor};
use services::sovrin::SovrinService;
use services::wallet::WalletService;

use std::error;
use std::sync::mpsc::{Sender, channel};
use std::rc::Rc;
use std::thread;

pub enum Command {
    Exit,
    Sovrin(SovrinCommand),
    Wallet(WalletCommand)
}

pub struct CommandExecutor {
    worker: Option<thread::JoinHandle<()>>,
    sender: Sender<Command>
}

impl CommandExecutor {
    pub fn new() -> CommandExecutor {
        let (sender, receiver) = channel();

        CommandExecutor {
            sender: sender,
            worker: Some(thread::spawn(move || {
                loop {
                    info!(target: "command_executor", "Worker thread started");

                    let sovrin_service = Rc::new(SovrinService::new());
                    let wallet_service = Rc::new(WalletService::new());
                    let sovrin_command_executor = SovrinCommandExecutor::new(sovrin_service.clone());
                    let wallet_command_executor = WalletCommandExecutor::new(wallet_service.clone());

                    match receiver.recv() {
                        Ok(Command::Sovrin(cmd)) => {
                            info!(target: "command_executor", "SovrinCommand command received");
                            sovrin_command_executor.execute(cmd);
                        },
                        Ok(Command::Wallet(cmd)) => {
                            info!(target: "command_executor", "WalletCommand command received");
                            wallet_command_executor.execute(cmd);
                        },
                        Ok(Command::Exit) => {
                            info!(target: "command_executor", "Exit command received");
                            break
                        },
                        Err(err) => {
                            error!(target: "command_executor", "Failed to get command!");
                            panic!("Failed to get command! {:?}", err)
                        }
                    }
                }
            }))
        }
    }

    pub fn send(&self, cmd: Command) {
        self.sender.send(cmd);
    }
}

impl Drop for CommandExecutor {
    fn drop(&mut self) {
        info!(target: "command_executor", "Drop started");
        self.send(Command::Exit);
        // Option worker type and this kludge is workaround for rust
        self.worker.take().unwrap().join();
        info!(target: "command_executor", "Drop finished");
    }
}

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

    #[test]
    fn command_executor_can_be_created() {
        let command_executor = CommandExecutor::new();
        assert!(true, "No crashes on CommandExecutor::new");
    }

    #[test]
    fn command_executor_can_be_dropped() {
        fn drop_test() {
            let command_executor = CommandExecutor::new();
        }

        drop_test();
        assert!(true, "No crashes on CommandExecutor::drop");
    }

    #[test]
    fn set_did_command_can_be_sent() {
        let (sender, receiver) = channel();

        let cb = Box::new(move |result| {
            match result {
                Ok(val) => sender.send("OK"),
                Err(err) => sender.send("ERR")
            };
        });

        let cmd_executor = CommandExecutor::new();
        cmd_executor.send(
            Command::Sovrin
                (SovrinCommand::SendNymTx(
                    "{did: \"DID0\", sign_key: \"KEY0\"}".to_string(),
                    "DID0".to_string(),
                    None,
                    None,
                    None,
                    None,
                    cb)));

        match receiver.recv() {
            Ok(result) => {
                assert_eq!("OK", result);
            }
            Err(err) => {
                panic!("Error on result recv: {:?}", err);
            }
        }
    }

    #[test]
    fn wallet_set_value_command_can_be_sent() {
        let (sender, receiver) = channel();

        let cb = Box::new(move |result| {
            match result {
                Ok(val) => sender.send("OK"),
                Err(err) => sender.send("ERR")
            };
        });

        let cmd_executor = CommandExecutor::new();
        cmd_executor.send(Command::Wallet(WalletCommand::Set(vec!["key".to_string(), "subkey".to_string()], "value".to_string(), cb)));

        match receiver.recv() {
            Ok(result) => {
                assert_eq!("OK", result);
            }
            Err(err) => {
                panic!("Error on result recv: {:?}", err);
            }
        }
    }

    #[test]
    fn wallet_get_value_command_can_be_sent() {

        let cmd_executor = CommandExecutor::new();

        let (set_sender, set_receiver) = channel();

        let cb_set = Box::new(move |result| {
            match result {
                Ok(val) => set_sender.send("OK"),
                Err(err) => set_sender.send("ERR")
            };
        });

        cmd_executor.send(Command::Wallet(WalletCommand::Set(vec!["key".to_string(), "subkey".to_string()], "value".to_string(), cb_set)));

        match set_receiver.recv() {
            Ok(result) => {
                assert_eq!("OK", result);
            }
            Err(err) => {
                panic!("Error on result recv: {:?}", err);
            }
        }

        let (get_sender, get_receiver) = channel();

        let cb = Box::new(move |result| {
            match result {
                Ok(val) => get_sender.send(val),
                Err(err) => get_sender.send(None)
            };
        });

        cmd_executor.send(Command::Wallet(WalletCommand::Get(vec!["key".to_string(), "subkey".to_string()], cb)));

        match get_receiver.recv() {
            Ok(result) => {
                assert_eq!(Some("value".to_string()), result);
            }
            Err(err) => {
                panic!("Error on result recv: {:?}", err);
            }
        }
    }
}<commit_msg>* Stupid bug was fixed<commit_after>pub mod anoncreds;
pub mod crypto;
pub mod sovrin;
pub mod wallet;

use commands::sovrin::{SovrinCommand, SovrinCommandExecutor};
use commands::wallet::{WalletCommand, WalletCommandExecutor};
use services::sovrin::SovrinService;
use services::wallet::WalletService;

use std::error;
use std::sync::mpsc::{Sender, channel};
use std::rc::Rc;
use std::thread;

pub enum Command {
    Exit,
    Sovrin(SovrinCommand),
    Wallet(WalletCommand)
}

pub struct CommandExecutor {
    worker: Option<thread::JoinHandle<()>>,
    sender: Sender<Command>
}

impl CommandExecutor {
    pub fn new() -> CommandExecutor {
        let (sender, receiver) = channel();

        CommandExecutor {
            sender: sender,
            worker: Some(thread::spawn(move || {
                info!(target: "command_executor", "Worker thread started");

                let sovrin_service = Rc::new(SovrinService::new());
                let wallet_service = Rc::new(WalletService::new());
                let sovrin_command_executor = SovrinCommandExecutor::new(sovrin_service.clone());
                let wallet_command_executor = WalletCommandExecutor::new(wallet_service.clone());

                loop {
                    match receiver.recv() {
                        Ok(Command::Sovrin(cmd)) => {
                            info!(target: "command_executor", "SovrinCommand command received");
                            sovrin_command_executor.execute(cmd);
                        },
                        Ok(Command::Wallet(cmd)) => {
                            info!(target: "command_executor", "WalletCommand command received");
                            wallet_command_executor.execute(cmd);
                        },
                        Ok(Command::Exit) => {
                            info!(target: "command_executor", "Exit command received");
                            break
                        },
                        Err(err) => {
                            error!(target: "command_executor", "Failed to get command!");
                            panic!("Failed to get command! {:?}", err)
                        }
                    }
                }
            }))
        }
    }

    pub fn send(&self, cmd: Command) {
        self.sender.send(cmd);
    }
}

impl Drop for CommandExecutor {
    fn drop(&mut self) {
        info!(target: "command_executor", "Drop started");
        self.send(Command::Exit);
        // Option worker type and this kludge is workaround for rust
        self.worker.take().unwrap().join();
        info!(target: "command_executor", "Drop finished");
    }
}

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

    #[test]
    fn command_executor_can_be_created() {
        let command_executor = CommandExecutor::new();
        assert!(true, "No crashes on CommandExecutor::new");
    }

    #[test]
    fn command_executor_can_be_dropped() {
        fn drop_test() {
            let command_executor = CommandExecutor::new();
        }

        drop_test();
        assert!(true, "No crashes on CommandExecutor::drop");
    }

    #[test]
    fn set_did_command_can_be_sent() {
        let (sender, receiver) = channel();

        let cb = Box::new(move |result| {
            match result {
                Ok(val) => sender.send("OK"),
                Err(err) => sender.send("ERR")
            };
        });

        let cmd_executor = CommandExecutor::new();
        cmd_executor.send(
            Command::Sovrin
                (SovrinCommand::SendNymTx(
                    "{did: \"DID0\", sign_key: \"KEY0\"}".to_string(),
                    "DID0".to_string(),
                    None,
                    None,
                    None,
                    None,
                    cb)));

        match receiver.recv() {
            Ok(result) => {
                assert_eq!("OK", result);
            }
            Err(err) => {
                panic!("Error on result recv: {:?}", err);
            }
        }
    }

    #[test]
    fn wallet_set_value_command_can_be_sent() {
        let (sender, receiver) = channel();

        let cb = Box::new(move |result| {
            match result {
                Ok(val) => sender.send("OK"),
                Err(err) => sender.send("ERR")
            };
        });

        let cmd_executor = CommandExecutor::new();
        cmd_executor.send(Command::Wallet(WalletCommand::Set(vec!["key".to_string(), "subkey".to_string()], "value".to_string(), cb)));

        match receiver.recv() {
            Ok(result) => {
                assert_eq!("OK", result);
            }
            Err(err) => {
                panic!("Error on result recv: {:?}", err);
            }
        }
    }

    #[test]
    fn wallet_get_value_command_can_be_sent() {
        let cmd_executor = CommandExecutor::new();

        let (set_sender, set_receiver) = channel();

        let cb_set = Box::new(move |result| {
            match result {
                Ok(val) => set_sender.send("OK"),
                Err(err) => set_sender.send("ERR")
            };
        });

        cmd_executor.send(Command::Wallet(WalletCommand::Set(vec!["key".to_string(), "subkey".to_string()], "value".to_string(), cb_set)));

        match set_receiver.recv() {
            Ok(result) => {
                assert_eq!("OK", result);
            }
            Err(err) => {
                panic!("Error on result recv: {:?}", err);
            }
        }

        let (get_sender, get_receiver) = channel();

        let cb = Box::new(move |result| {
            match result {
                Ok(val) => get_sender.send(val),
                Err(err) => get_sender.send(None)
            };
        });

        cmd_executor.send(Command::Wallet(WalletCommand::Get(vec!["key".to_string(), "subkey".to_string()], cb)));

        match get_receiver.recv() {
            Ok(result) => {
                assert_eq!(Some("value".to_string()), result);
            }
            Err(err) => {
                panic!("Error on result recv: {:?}", err);
            }
        }
    }
}<|endoftext|>


<commit_before>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

/// A trait for a non-seekable object.
pub trait WriteOwned: Write + ToOwned {}
/// A trait for a seekable object.
pub trait WriteSeek: Write + Seek + ToOwned {}

impl<T: Write + ToOwned> WriteOwned for T {}
impl<T: Write + Seek + ToOwned> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<WO: WriteOwned, WS: WriteSeek> {
    NonSeekable(WO, u64),
    Seekable(WS),
}

impl<WO: WriteOwned, WS: WriteSeek> Writer<WO, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: WO) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns whether the [`Writer`] can seek within the source.
    pub fn can_seek(&self) -> bool {
        matches!(self, Self::Seekable(_))
    }

    /// Returns the non-seekable object whether is present.
    pub fn non_seekable_object(&self) -> Option<(<WO as ToOwned>::Owned, u64)> {
        if let Self::NonSeekable(inner, index) = self {
            Some((inner.to_owned(), *index))
        } else {
            None
        }
    }

    /// Returns the seekable object whether is present.
    pub fn seekable_object(&self) -> Option<<WS as ToOwned>::Owned> {
        if let Self::Seekable(inner) = self {
            Some(inner.to_owned())
        } else {
            None
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Write for Writer<WO, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Seek for Writer<WO, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> {
    muxer: M,
    writer: Writer<WO, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> Context<M, WO, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<WO, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }

    /// Returns the underlying writer.
    pub fn writer(&self) -> &Writer<WO, WS> {
        &self.writer
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    struct DummyDes {
        d: Descr,
    }

    struct DummyMuxer {}

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

    impl Muxer for DummyMuxer {
        fn configure(&mut self) -> Result<()> {
            Ok(())
        }

        fn write_header<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy header";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn write_packet<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
            pkt: Arc<Packet>,
        ) -> Result<()> {
            out.write_all(&pkt.data).unwrap();
            Ok(())
        }

        fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy trailer";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn set_global_info(&mut self, _info: GlobalInfo) -> Result<()> {
            Ok(())
        }

        fn set_option<'a>(&mut self, _key: &str, _val: Value<'a>) -> Result<()> {
            Ok(())
        }
    }

    impl Descriptor for DummyDes {
        type OutputMuxer = DummyMuxer;

        fn create(&self) -> Self::OutputMuxer {
            DummyMuxer {}
        }
        fn describe(&self) -> &Descr {
            &self.d
        }
    }

    const DUMMY_DES: &dyn Descriptor<OutputMuxer = DummyMuxer> = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy mux",
            extensions: &["mx", "mux"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn lookup() {
        let muxers: &[&dyn Descriptor<OutputMuxer = DummyMuxer>] = &[DUMMY_DES];

        muxers.by_name("dummy").unwrap();
    }

    #[test]
    fn write_header() {
        let mux = DummyMuxer::new();
        let writer: Writer<Cursor<Vec<u8>>, Cursor<Vec<u8>>> =
            Writer::from_seekable(Cursor::new(Vec::new()));

        let mut muxer = Context::new(mux, writer);
        muxer.configure().unwrap();
        muxer.write_header().unwrap();
    }
}
<commit_msg>format: Use default values for Writer traits<commit_after>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{Cursor, ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

/// A trait for a non-seekable object.
pub trait WriteOwned: Write + ToOwned {}
/// A trait for a seekable object.
pub trait WriteSeek: Write + Seek + ToOwned {}

impl<T: Write + ToOwned> WriteOwned for T {}
impl<T: Write + Seek + ToOwned> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<WO = Cursor<Vec<u8>>, WS = Cursor<Vec<u8>>> {
    NonSeekable(WO, u64),
    Seekable(WS),
}

impl<WO: WriteOwned> Writer<WO, Cursor<Vec<u8>>> {
    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: WO) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns the non-seekable object whether is present.
    pub fn non_seekable_object(&self) -> Option<(<WO as ToOwned>::Owned, u64)> {
        if let Self::NonSeekable(inner, index) = self {
            Some((inner.to_owned(), *index))
        } else {
            None
        }
    }
}

impl<WS: WriteSeek> Writer<Cursor<Vec<u8>>, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Returns the seekable object whether is present.
    pub fn seekable_object(&self) -> Option<<WS as ToOwned>::Owned> {
        if let Self::Seekable(inner) = self {
            Some(inner.to_owned())
        } else {
            None
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Write for Writer<WO, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Seek for Writer<WO, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> {
    muxer: M,
    writer: Writer<WO, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> Context<M, WO, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<WO, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }

    /// Returns the underlying writer.
    pub fn writer(&self) -> &Writer<WO, WS> {
        &self.writer
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    struct DummyDes {
        d: Descr,
    }

    struct DummyMuxer {}

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

    impl Muxer for DummyMuxer {
        fn configure(&mut self) -> Result<()> {
            Ok(())
        }

        fn write_header<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy header";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn write_packet<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
            pkt: Arc<Packet>,
        ) -> Result<()> {
            out.write_all(&pkt.data).unwrap();
            Ok(())
        }

        fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy trailer";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn set_global_info(&mut self, _info: GlobalInfo) -> Result<()> {
            Ok(())
        }

        fn set_option<'a>(&mut self, _key: &str, _val: Value<'a>) -> Result<()> {
            Ok(())
        }
    }

    impl Descriptor for DummyDes {
        type OutputMuxer = DummyMuxer;

        fn create(&self) -> Self::OutputMuxer {
            DummyMuxer {}
        }
        fn describe(&self) -> &Descr {
            &self.d
        }
    }

    const DUMMY_DES: &dyn Descriptor<OutputMuxer = DummyMuxer> = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy mux",
            extensions: &["mx", "mux"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn lookup() {
        let muxers: &[&dyn Descriptor<OutputMuxer = DummyMuxer>] = &[DUMMY_DES];

        muxers.by_name("dummy").unwrap();
    }

    #[test]
    fn write_header() {
        let mux = DummyMuxer::new();
        let writer = Writer::from_seekable(Cursor::new(Vec::new()));

        let mut muxer = Context::new(mux, writer);
        muxer.configure().unwrap();
        muxer.write_header().unwrap();
    }
}
<|endoftext|>


<commit_before>// Std
use std::{collections::HashMap, ffi::OsString, mem, ops::Deref};

// Internal
use crate::{
    build::{Arg, ArgPredicate, Command},
    parse::{ArgMatches, MatchedArg, SubCommand, ValueSource},
    util::Id,
};

// Third party
use indexmap::map::Entry;

#[derive(Debug, Default)]
pub(crate) struct ArgMatcher(ArgMatches);

impl ArgMatcher {
    pub(crate) fn new(_cmd: &Command) -> Self {
        ArgMatcher(ArgMatches {
            #[cfg(debug_assertions)]
            valid_args: {
                let args = _cmd.get_arguments().map(|a| a.id.clone());
                let groups = _cmd.get_groups().map(|g| g.id.clone());
                args.chain(groups).collect()
            },
            #[cfg(debug_assertions)]
            valid_subcommands: _cmd.get_subcommands().map(|sc| sc.get_id()).collect(),
            // HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
            // since users can't detect it and avoid the asserts.
            //
            // See clap-rs/clap#3263
            #[cfg(debug_assertions)]
            disable_asserts: _cmd.is_allow_external_subcommands_set(),
            ..Default::default()
        })
    }

    pub(crate) fn into_inner(self) -> ArgMatches {
        self.0
    }

    pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
        debug!(
            "ArgMatcher::get_global_values: global_arg_vec={:?}",
            global_arg_vec
        );
        let mut vals_map = HashMap::new();
        self.fill_in_global_values(global_arg_vec, &mut vals_map);
    }

    fn fill_in_global_values(
        &mut self,
        global_arg_vec: &[Id],
        vals_map: &mut HashMap<Id, MatchedArg>,
    ) {
        for global_arg in global_arg_vec {
            if let Some(ma) = self.get(global_arg) {
                // We have to check if the parent's global arg wasn't used but still exists
                // such as from a default value.
                //
                // For example, `myprog subcommand --global-arg=value` where --global-arg defines
                // a default value of `other` myprog would have an existing MatchedArg for
                // --global-arg where the value is `other`, however the occurs will be 0.
                let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
                    if parent_ma.get_occurrences() > 0 && ma.get_occurrences() == 0 {
                        parent_ma
                    } else {
                        ma
                    }
                } else {
                    ma
                }
                .clone();
                vals_map.insert(global_arg.clone(), to_update);
            }
        }
        if let Some(ref mut sc) = self.0.subcommand {
            let mut am = ArgMatcher(mem::take(&mut sc.matches));
            am.fill_in_global_values(global_arg_vec, vals_map);
            mem::swap(&mut am.0, &mut sc.matches);
        }

        for (name, matched_arg) in vals_map.iter_mut() {
            self.0.args.insert(name.clone(), matched_arg.clone());
        }
    }

    #[cfg(not(feature = "unstable-v4"))]
    pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
        self.0.args.get_mut(arg)
    }

    pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
        self.0.args.get(arg)
    }

    pub(crate) fn remove(&mut self, arg: &Id) {
        self.0.args.swap_remove(arg);
    }

    pub(crate) fn contains(&self, arg: &Id) -> bool {
        self.0.args.contains_key(arg)
    }

    pub(crate) fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> {
        self.0.args.keys()
    }

    pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
        self.0.args.entry(arg.clone())
    }

    pub(crate) fn subcommand(&mut self, sc: SubCommand) {
        self.0.subcommand = Some(Box::new(sc));
    }

    pub(crate) fn subcommand_name(&self) -> Option<&str> {
        self.0.subcommand_name()
    }

    pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
        self.0.args.iter()
    }

    pub(crate) fn check_explicit<'a>(&self, arg: &Id, predicate: ArgPredicate<'a>) -> bool {
        self.get(arg).map_or(false, |a| a.check_explicit(predicate))
    }

    pub(crate) fn inc_occurrence_of_arg(&mut self, arg: &Arg) {
        let id = &arg.id;
        debug!("ArgMatcher::inc_occurrence_of_arg: id={:?}", id);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.update_ty(ValueSource::CommandLine);
        ma.set_ignore_case(arg.is_ignore_case_set());
        ma.invalid_utf8_allowed(arg.is_allow_invalid_utf8_set());
        ma.inc_occurrences();
    }

    pub(crate) fn inc_occurrence_of_group(&mut self, id: &Id) {
        debug!("ArgMatcher::inc_occurrence_of_group: id={:?}", id);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.update_ty(ValueSource::CommandLine);
        ma.inc_occurrences();
    }

    #[cfg(feature = "unstable-v4")]
    pub(crate) fn inc_occurrence_of_external(&mut self, allow_invalid_utf8: bool) {
        let id = &Id::empty_hash();
        debug!(
            "ArgMatcher::inc_occurrence_of_external: id={:?}, allow_invalid_utf8={}",
            id, allow_invalid_utf8
        );
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.update_ty(ValueSource::CommandLine);
        ma.invalid_utf8_allowed(allow_invalid_utf8);
        ma.inc_occurrences();
    }

    pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource, append: bool) {
        if append {
            self.append_val_to(arg, val, ty);
        } else {
            self.push_val_to(arg, val, ty);
        }
    }

    fn push_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource) {
        // We will manually inc occurrences later(for flexibility under
        // specific circumstances, like only add one occurrence for flag
        // when we met: `--flag=one,two`).
        let ma = self.entry(arg).or_default();
        ma.update_ty(ty);
        ma.push_val(val);
    }

    fn append_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource) {
        let ma = self.entry(arg).or_default();
        ma.update_ty(ty);
        ma.append_val(val);
    }

    pub(crate) fn new_val_group(&mut self, arg: &Id) {
        let ma = self.entry(arg).or_default();
        ma.new_val_group();
    }

    pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueSource) {
        let ma = self.entry(arg).or_default();
        ma.update_ty(ty);
        ma.push_index(idx);
    }

    pub(crate) fn has_val_groups(&mut self, arg: &Id) -> bool {
        match self.entry(arg) {
            Entry::Occupied(e) => e.get().has_val_groups(),
            Entry::Vacant(_) => false,
        }
    }

    pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
        debug!("ArgMatcher::needs_more_vals: o={}", o.name);
        if let Some(ma) = self.get(&o.id) {
            let current_num = ma.num_vals();
            if let Some(num) = o.num_vals {
                debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
                return if o.is_multiple_occurrences_set() {
                    (current_num % num) != 0
                } else {
                    num != current_num
                };
            } else if let Some(num) = o.max_vals {
                debug!("ArgMatcher::needs_more_vals: max_vals...{}", num);
                return current_num < num;
            } else if o.min_vals.is_some() {
                debug!("ArgMatcher::needs_more_vals: min_vals...true");
                return true;
            }
            return o.is_multiple_values_set();
        }
        true
    }
}

impl Deref for ArgMatcher {
    type Target = ArgMatches;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<commit_msg>fix(parser): Assert on unknown args when using external subcommands (unstable)<commit_after>// Std
use std::{collections::HashMap, ffi::OsString, mem, ops::Deref};

// Internal
use crate::{
    build::{Arg, ArgPredicate, Command},
    parse::{ArgMatches, MatchedArg, SubCommand, ValueSource},
    util::Id,
};

// Third party
use indexmap::map::Entry;

#[derive(Debug, Default)]
pub(crate) struct ArgMatcher(ArgMatches);

impl ArgMatcher {
    pub(crate) fn new(_cmd: &Command) -> Self {
        ArgMatcher(ArgMatches {
            #[cfg(debug_assertions)]
            valid_args: {
                let args = _cmd.get_arguments().map(|a| a.id.clone());
                let groups = _cmd.get_groups().map(|g| g.id.clone());
                args.chain(groups).collect()
            },
            #[cfg(debug_assertions)]
            valid_subcommands: _cmd.get_subcommands().map(|sc| sc.get_id()).collect(),
            // HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
            // since users can't detect it and avoid the asserts.
            //
            // See clap-rs/clap#3263
            #[cfg(debug_assertions)]
            #[cfg(not(feature = "unstable-v4"))]
            disable_asserts: _cmd.is_allow_external_subcommands_set(),
            #[cfg(debug_assertions)]
            #[cfg(feature = "unstable-v4")]
            disable_asserts: false,
            ..Default::default()
        })
    }

    pub(crate) fn into_inner(self) -> ArgMatches {
        self.0
    }

    pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
        debug!(
            "ArgMatcher::get_global_values: global_arg_vec={:?}",
            global_arg_vec
        );
        let mut vals_map = HashMap::new();
        self.fill_in_global_values(global_arg_vec, &mut vals_map);
    }

    fn fill_in_global_values(
        &mut self,
        global_arg_vec: &[Id],
        vals_map: &mut HashMap<Id, MatchedArg>,
    ) {
        for global_arg in global_arg_vec {
            if let Some(ma) = self.get(global_arg) {
                // We have to check if the parent's global arg wasn't used but still exists
                // such as from a default value.
                //
                // For example, `myprog subcommand --global-arg=value` where --global-arg defines
                // a default value of `other` myprog would have an existing MatchedArg for
                // --global-arg where the value is `other`, however the occurs will be 0.
                let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
                    if parent_ma.get_occurrences() > 0 && ma.get_occurrences() == 0 {
                        parent_ma
                    } else {
                        ma
                    }
                } else {
                    ma
                }
                .clone();
                vals_map.insert(global_arg.clone(), to_update);
            }
        }
        if let Some(ref mut sc) = self.0.subcommand {
            let mut am = ArgMatcher(mem::take(&mut sc.matches));
            am.fill_in_global_values(global_arg_vec, vals_map);
            mem::swap(&mut am.0, &mut sc.matches);
        }

        for (name, matched_arg) in vals_map.iter_mut() {
            self.0.args.insert(name.clone(), matched_arg.clone());
        }
    }

    #[cfg(not(feature = "unstable-v4"))]
    pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
        self.0.args.get_mut(arg)
    }

    pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
        self.0.args.get(arg)
    }

    pub(crate) fn remove(&mut self, arg: &Id) {
        self.0.args.swap_remove(arg);
    }

    pub(crate) fn contains(&self, arg: &Id) -> bool {
        self.0.args.contains_key(arg)
    }

    pub(crate) fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> {
        self.0.args.keys()
    }

    pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
        self.0.args.entry(arg.clone())
    }

    pub(crate) fn subcommand(&mut self, sc: SubCommand) {
        self.0.subcommand = Some(Box::new(sc));
    }

    pub(crate) fn subcommand_name(&self) -> Option<&str> {
        self.0.subcommand_name()
    }

    pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
        self.0.args.iter()
    }

    pub(crate) fn check_explicit<'a>(&self, arg: &Id, predicate: ArgPredicate<'a>) -> bool {
        self.get(arg).map_or(false, |a| a.check_explicit(predicate))
    }

    pub(crate) fn inc_occurrence_of_arg(&mut self, arg: &Arg) {
        let id = &arg.id;
        debug!("ArgMatcher::inc_occurrence_of_arg: id={:?}", id);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.update_ty(ValueSource::CommandLine);
        ma.set_ignore_case(arg.is_ignore_case_set());
        ma.invalid_utf8_allowed(arg.is_allow_invalid_utf8_set());
        ma.inc_occurrences();
    }

    pub(crate) fn inc_occurrence_of_group(&mut self, id: &Id) {
        debug!("ArgMatcher::inc_occurrence_of_group: id={:?}", id);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.update_ty(ValueSource::CommandLine);
        ma.inc_occurrences();
    }

    #[cfg(feature = "unstable-v4")]
    pub(crate) fn inc_occurrence_of_external(&mut self, allow_invalid_utf8: bool) {
        let id = &Id::empty_hash();
        debug!(
            "ArgMatcher::inc_occurrence_of_external: id={:?}, allow_invalid_utf8={}",
            id, allow_invalid_utf8
        );
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.update_ty(ValueSource::CommandLine);
        ma.invalid_utf8_allowed(allow_invalid_utf8);
        ma.inc_occurrences();
    }

    pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource, append: bool) {
        if append {
            self.append_val_to(arg, val, ty);
        } else {
            self.push_val_to(arg, val, ty);
        }
    }

    fn push_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource) {
        // We will manually inc occurrences later(for flexibility under
        // specific circumstances, like only add one occurrence for flag
        // when we met: `--flag=one,two`).
        let ma = self.entry(arg).or_default();
        ma.update_ty(ty);
        ma.push_val(val);
    }

    fn append_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource) {
        let ma = self.entry(arg).or_default();
        ma.update_ty(ty);
        ma.append_val(val);
    }

    pub(crate) fn new_val_group(&mut self, arg: &Id) {
        let ma = self.entry(arg).or_default();
        ma.new_val_group();
    }

    pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueSource) {
        let ma = self.entry(arg).or_default();
        ma.update_ty(ty);
        ma.push_index(idx);
    }

    pub(crate) fn has_val_groups(&mut self, arg: &Id) -> bool {
        match self.entry(arg) {
            Entry::Occupied(e) => e.get().has_val_groups(),
            Entry::Vacant(_) => false,
        }
    }

    pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
        debug!("ArgMatcher::needs_more_vals: o={}", o.name);
        if let Some(ma) = self.get(&o.id) {
            let current_num = ma.num_vals();
            if let Some(num) = o.num_vals {
                debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
                return if o.is_multiple_occurrences_set() {
                    (current_num % num) != 0
                } else {
                    num != current_num
                };
            } else if let Some(num) = o.max_vals {
                debug!("ArgMatcher::needs_more_vals: max_vals...{}", num);
                return current_num < num;
            } else if o.min_vals.is_some() {
                debug!("ArgMatcher::needs_more_vals: min_vals...true");
                return true;
            }
            return o.is_multiple_values_set();
        }
        true
    }
}

impl Deref for ArgMatcher {
    type Target = ArgMatches;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<|endoftext|>


<commit_before>use geometry::Point;
use geometry::Rect;
use geometry::Size;

/**
 Elements that may be contained by a quadtree node.
 Either child nodes, a single rect, or nothing.
 */
enum Elements {
    /// Children are top left, top right, bottom right, and bottom left, respectively.
    Children(~QuadTree, ~QuadTree, ~QuadTree, ~QuadTree),
    /// A single rectangle.
    Member(Rect),
    /// Nothing.
    None
}

/**
 A quadtree node that can contain either one rectangle,
 or exactly four child nodes.
 */
pub struct QuadTree {
    rect: Rect,
    elements: Elements,
}

impl QuadTree {
    /**
     Create a quadtree with a square root node with the same origin and size
     as the passed in rect.
     */
    fn newAutosized(rect: Rect) -> QuadTree {
        QuadTree { rect: rect, elements: Member(rect), }
    }

    /**
     Create a quadtree with a root node with the given origin, size, and member rectangle.
     If `insertRect` is not entirely contained within the rectangle defined by `origin` and `size`,
     higher level nodes will be created to form a quadtree with a child of the rect specified
     and other children such that the rect is in the tree.
     */
    fn new(origin: Point, size: Size, insertRect: Rect) -> QuadTree {
        let nodeRect = Rect { origin: origin, size: size };
        let node = QuadTree { rect: nodeRect, elements: None };

        node.insertRect(insertRect)
    }

    fn insertRect(self, toInsert: Rect) -> QuadTree {
        fail!("insertRect not implemented!");

        self
    }
}<commit_msg>Add method to find rects in nodes intersected by a rect.<commit_after>use geometry::Point;
use geometry::Rect;
use geometry::Size;

/**
 Elements that may be contained by a quadtree node.
 Either child nodes, a single rect, or nothing.
 */
enum Elements {
    /// Children are top left, top right, bottom right, and bottom left, respectively.
    Children(~QuadTree, ~QuadTree, ~QuadTree, ~QuadTree),
    /// A single rectangle.
    Member(Rect),
    /// Nothing.
    NoElements,
}

/**
 A quadtree node that can contain either one rectangle,
 or exactly four child nodes.
 */
pub struct QuadTree {
    rect: Rect,
    elements: Elements,
}

impl QuadTree {
    /**
     Create an empty quadtree with a zero-sized root node.
     */
    pub fn new() -> QuadTree {
        let origin = Point { x: 0 as f32, y: 0 as f32 };
        let size = Size { width: 0 as f32, height: 0 as f32 };
        let nodeRect = Rect { origin: origin, size: size };
        let node = QuadTree { rect: nodeRect, elements: NoElements };

        node
    }

    /**
     Create a quadtree with a root node with the same origin and a square
     size with side length matching the longer dimension of `rect`.
     */
    pub fn newAutosized(rect: Rect) -> QuadTree {
        let largerDimen = if rect.size.width > rect.size.height {
            rect.size.width
        } else {
            rect.size.height
        };

        let square = Rect { origin: rect.origin, size: Size { width: largerDimen, height: largerDimen } };

        QuadTree { rect: square, elements: Member(rect), }
    }

    /**
     Create a quadtree with a root node with the given origin, size, and member rectangle.
     If `insertRect` is not entirely contained within the rectangle defined by `origin` and `size`,
     higher level nodes will be created to form a quadtree with a child of the rect specified
     and other children such that the rect is in the tree.
     */
    pub fn newWithSize(origin: Point, size: Size, insertRect: Rect) -> QuadTree {
        let nodeRect = Rect { origin: origin, size: size };
        let node = QuadTree { rect: nodeRect, elements: NoElements };

        let (success, tree) = node.insertRect(insertRect);

        assert!(success, "Failed inserting a node into an empty quadtree.");

        tree
    }

    /**
     Insert a rectangle into the quadtree. If `toInsert` overlaps another rectangle
     already in the tree, the return value will be (false, self).
     If the root node is zero-sized, the resulting tree will have a square root node
     large enough to hold `toInsert`.
     */
    pub fn insertRect(self, toInsert: Rect) -> (bool, QuadTree) {
        if self.rect.size.width == 0.0 {
            return (true, QuadTree::newAutosized(toInsert))
        }

        fail!("insertRect not implemented for non-zero sized trees!");

        (false, self)
    }

    /**
     Find all of the rects in `self`, or its children, that are in nodes
     intersected by the given rect.
     */
    pub fn rectsInChildNodesIntersectedByRect(&self, testRect: &Rect) -> ~[Rect] {
        // If the test rect doesn't intersect us, then it can't intersect
        // any rects that we have.
        match self.rect.intersect(testRect) {
            Some(intersection) => {
                let mut rects = ~[];
                let mut nodesToCheck = ~[self];

                while nodesToCheck.len() > 0 {
                    let mut newNodesToCheck = ~[];

                    for node in nodesToCheck.iter() {
                        match node.elements {
                            Children(~ref tl, ~ref tr, ~ref br, ~ref bl) => {
                                let mut check = ~[];
                                let intersection = &intersection;
                                if tl.rect.intersects(intersection) {
                                    check.push(tl);
                                }
                                if tr.rect.intersects(intersection) {
                                    check.push(tr);
                                }
                                if br.rect.intersects(intersection) {
                                    check.push(br);
                                }
                                if bl.rect.intersects(intersection) {
                                    check.push(bl);
                                }
                                newNodesToCheck.push_all(check);
                            }
                            Member(memberRect) => rects.push(memberRect),
                            NoElements => ()
                        };
                    }

                    nodesToCheck = newNodesToCheck;
                }

                rects
            },
            None => ~[],
        }
    }
}<|endoftext|>


<commit_before>use std::io::Read;
use error::{Result, Error, ErrorKind};
use reader::FbxEvent;

#[derive(Clone, Copy, PartialEq, Eq)]
enum ParserMode {
    /// Reading magic binary (i.e. the first line)
    Magic,
    /// Reading binary FBX
    Binary,
    /// Reading ASCII FBX
    Ascii,
}

pub struct Parser {
    pos: u64,
    mode: ParserMode,
}

impl Parser {
    pub fn new() -> Self {
        Parser {
            pos: 0,
            mode: ParserMode::Magic,
        }
    }
    pub fn next<R: Read>(&mut self, reader: &mut R) -> Result<FbxEvent> {
        match self.mode {
            ParserMode::Magic => self.magic_next(reader),
            ParserMode::Binary => self.binary_next(reader),
            ParserMode::Ascii => self.ascii_next(reader),
        }
    }
    pub fn magic_next<R: Read>(&mut self, _reader: &mut R) -> Result<FbxEvent> {
        Err(Error::new(self.pos, ErrorKind::Unimplemented("Parser for magic binary is not implemented yet".to_string())))
    }
    pub fn binary_next<R: Read>(&mut self, _reader: &mut R) -> Result<FbxEvent> {
        Err(Error::new(self.pos, ErrorKind::Unimplemented("Parser for Binary FBX format is not implemented yet".to_string())))
    }
    pub fn ascii_next<R: Read>(&mut self, _reader: &mut R) -> Result<FbxEvent> {
        Err(Error::new(self.pos, ErrorKind::Unimplemented("Parser for ASCII FBX format is not implemented yet".to_string())))
    }
}
<commit_msg>Add some macros for `reader::parser`<commit_after>extern crate byteorder;

use std::io::Read;
use error::{Result, Error, ErrorKind};
use reader::FbxEvent;

#[macro_use]
mod macros {
    macro_rules! try_with_pos {
        ($pos:expr, $expr:expr) => (match $expr {
            ::std::result::Result::Ok(val) => val,
            ::std::result::Result::Err(err) => {
                return ::std::result::Result::Err($crate::error::Error::new($pos, err));
            },
        })
    }

    macro_rules! try_read_le_u32 {
        ($pos: expr, $reader:expr) => ({
            use self::byteorder::ReadBytesExt;
            let val = try_with_pos!($pos, $reader.by_ref().read_u32::<byteorder::LittleEndian>());
            $pos += 4;
            val
        })
    }

    macro_rules! try_read_exact {
        ($pos:expr, $reader:expr, $len:expr) => ({
            let mut buffer = Vec::<u8>::with_capacity($len as usize);
            let len = try_with_pos!($pos, $reader.by_ref().take($len as u64).read_to_end(&mut buffer)) as u64;
            if len != ($len as u64) {
                return Err(Error::new($pos, ErrorKind::UnexpectedEof));
            }
            $pos += len;
            buffer
        })
    }
}

#[derive(Clone, Copy, PartialEq, Eq)]
enum ParserMode {
    /// Reading magic binary (i.e. the first line)
    Magic,
    /// Reading binary FBX
    Binary,
    /// Reading ASCII FBX
    Ascii,
}

pub struct Parser {
    pos: u64,
    mode: ParserMode,
}

impl Parser {
    pub fn new() -> Self {
        Parser {
            pos: 0,
            mode: ParserMode::Magic,
        }
    }
    pub fn next<R: Read>(&mut self, reader: &mut R) -> Result<FbxEvent> {
        match self.mode {
            ParserMode::Magic => self.magic_next(reader),
            ParserMode::Binary => self.binary_next(reader),
            ParserMode::Ascii => self.ascii_next(reader),
        }
    }
    pub fn magic_next<R: Read>(&mut self, _reader: &mut R) -> Result<FbxEvent> {
        Err(Error::new(self.pos, ErrorKind::Unimplemented("Parser for magic binary is not implemented yet".to_string())))
    }
    pub fn binary_next<R: Read>(&mut self, _reader: &mut R) -> Result<FbxEvent> {
        Err(Error::new(self.pos, ErrorKind::Unimplemented("Parser for Binary FBX format is not implemented yet".to_string())))
    }
    pub fn ascii_next<R: Read>(&mut self, _reader: &mut R) -> Result<FbxEvent> {
        Err(Error::new(self.pos, ErrorKind::Unimplemented("Parser for ASCII FBX format is not implemented yet".to_string())))
    }
}
<|endoftext|>