<commit_before>use crate::cli;
use crate::command_prelude::*;
use anyhow::{bail, format_err};
use cargo::core::dependency::DepKind;
use cargo::ops::tree::{self, EdgeKind};
use cargo::ops::Packages;
use cargo::util::CargoResult;
use std::collections::HashSet;
use std::str::FromStr;

pub fn cli() -> App {
    subcommand("tree")
        .about("Display a tree visualization of a dependency graph")
        .arg(opt("quiet", "Suppress status messages").short("q"))
        .arg_manifest_path()
        .arg_package_spec_no_all(
            "Package to be used as the root of the tree",
            "Display the tree for all packages in the workspace",
            "Exclude specific workspace members",
        )
        .arg(Arg::with_name("all").long("all").short("a").hidden(true))
        .arg(
            Arg::with_name("all-targets")
                .long("all-targets")
                .hidden(true),
        )
        .arg_features()
        .arg_target_triple(
            "Filter dependencies matching the given target-triple (default host platform)",
        )
        .arg(
            Arg::with_name("no-dev-dependencies")
                .long("no-dev-dependencies")
                .hidden(true),
        )
        .arg(
            multi_opt(
                "edges",
                "KINDS",
                "The kinds of dependencies to display \
                 (features, normal, build, dev, all, no-dev, no-build, no-normal)",
            )
            .short("e"),
        )
        .arg(
            optional_multi_opt(
                "invert",
                "SPEC",
                "Invert the tree direction and focus on the given package",
            )
            .short("i"),
        )
        .arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
        .arg(
            Arg::with_name("prefix-depth")
                .long("prefix-depth")
                .hidden(true),
        )
        .arg(
            opt(
                "prefix",
                "Change the prefix (indentation) of how each entry is displayed",
            )
            .value_name("PREFIX")
            .possible_values(&["depth", "indent", "none"])
            .default_value("indent"),
        )
        .arg(opt(
            "no-dedupe",
            "Do not de-duplicate (repeats all shared dependencies)",
        ))
        .arg(
            opt(
                "duplicates",
                "Show only dependencies which come in multiple versions (implies -i)",
            )
            .short("d")
            .alias("duplicate"),
        )
        .arg(
            opt("charset", "Character set to use in output: utf8, ascii")
                .value_name("CHARSET")
                .possible_values(&["utf8", "ascii"])
                .default_value("utf8"),
        )
        .arg(
            opt("format", "Format string used for printing dependencies")
                .value_name("FORMAT")
                .short("f")
                .default_value("{p}"),
        )
        .arg(
            // Backwards compatibility with old cargo-tree.
            Arg::with_name("version")
                .long("version")
                .short("V")
                .hidden(true),
        )
        .after_help("Run `cargo help tree` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    if args.is_present("version") {
        let verbose = args.occurrences_of("verbose") > 0;
        let version = cli::get_version_string(verbose);
        cargo::drop_print!(config, "{}", version);
        return Ok(());
    }
    let prefix = if args.is_present("no-indent") {
        config
            .shell()
            .warn("the --no-indent flag has been changed to --prefix=none")?;
        "none"
    } else if args.is_present("prefix-depth") {
        config
            .shell()
            .warn("the --prefix-depth flag has been changed to --prefix=depth")?;
        "depth"
    } else {
        args.value_of("prefix").unwrap()
    };
    let prefix = tree::Prefix::from_str(prefix).map_err(|e| anyhow::anyhow!("{}", e))?;

    let no_dedupe = args.is_present("no-dedupe") || args.is_present("all");
    if args.is_present("all") {
        config.shell().warn(
            "The `cargo tree` --all flag has been changed to --no-dedupe, \
             and may be removed in a future version.\n\
             If you are looking to display all workspace members, use the --workspace flag.",
        )?;
    }

    let targets = if args.is_present("all-targets") {
        config
            .shell()
            .warn("the --all-targets flag has been changed to --target=all")?;
        vec!["all".to_string()]
    } else {
        args._values_of("target")
    };
    let target = tree::Target::from_cli(targets);

    let edge_kinds = parse_edge_kinds(config, args)?;
    let graph_features = edge_kinds.contains(&EdgeKind::Feature);

    let packages = args.packages_from_flags()?;
    let mut invert = args
        .values_of("invert")
        .map_or_else(|| Vec::new(), |is| is.map(|s| s.to_string()).collect());
    if args.is_present_with_zero_values("invert") {
        match &packages {
            Packages::Packages(ps) => {
                // Backwards compatibility with old syntax of `cargo tree -i -p foo`.
                invert.extend(ps.clone());
            }
            _ => {
                return Err(format_err!(
                    "The `-i` flag requires a package name.\n\
\n\
The `-i` flag is used to inspect the reverse dependencies of a specific\n\
package. It will invert the tree and display the packages that depend on the\n\
given package.\n\
\n\
Note that in a workspace, by default it will only display the package's\n\
reverse dependencies inside the tree of the workspace member in the current\n\
directory. The --workspace flag can be used to extend it so that it will show\n\
the package's reverse dependencies across the entire workspace. The -p flag\n\
can be used to display the package's reverse dependencies only with the\n\
subtree of the package given to -p.\n\
"
                )
                .into());
            }
        }
    }

    let ws = args.workspace(config)?;
    let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let opts = tree::TreeOptions {
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        packages,
        target,
        edge_kinds,
        invert,
        prefix,
        no_dedupe,
        duplicates: args.is_present("duplicates"),
        charset,
        format: args.value_of("format").unwrap().to_string(),
        graph_features,
    };

    tree::build_and_print(&ws, &opts)?;
    Ok(())
}

fn parse_edge_kinds(config: &Config, args: &ArgMatches<'_>) -> CargoResult<HashSet<EdgeKind>> {
    let mut kinds: Vec<&str> = args
        .values_of("edges")
        .map_or_else(|| Vec::new(), |es| es.flat_map(|e| e.split(',')).collect());
    if args.is_present("no-dev-dependencies") {
        config
            .shell()
            .warn("the --no-dev-dependencies flag has changed to -e=no-dev")?;
        kinds.push("no-dev");
    }
    if kinds.is_empty() {
        kinds.extend(&["normal", "build", "dev"]);
    }

    let mut result = HashSet::new();
    let insert_defaults = |result: &mut HashSet<EdgeKind>| {
        result.insert(EdgeKind::Dep(DepKind::Normal));
        result.insert(EdgeKind::Dep(DepKind::Build));
        result.insert(EdgeKind::Dep(DepKind::Development));
    };
    let unknown = |k| {
        bail!(
            "unknown edge kind `{}`, valid values are \
                \"normal\", \"build\", \"dev\", \
                \"no-normal\", \"no-build\", \"no-dev\", \
                \"features\", or \"all\"",
            k
        )
    };
    if kinds.iter().any(|k| k.starts_with("no-")) {
        insert_defaults(&mut result);
        for kind in &kinds {
            match *kind {
                "no-normal" => result.remove(&EdgeKind::Dep(DepKind::Normal)),
                "no-build" => result.remove(&EdgeKind::Dep(DepKind::Build)),
                "no-dev" => result.remove(&EdgeKind::Dep(DepKind::Development)),
                "features" => result.insert(EdgeKind::Feature),
                "normal" | "build" | "dev" | "all" => {
                    bail!("`no-` dependency kinds cannot be mixed with other dependency kinds")
                }
                k => return unknown(k),
            };
        }
        return Ok(result);
    }
    for kind in &kinds {
        match *kind {
            "all" => {
                insert_defaults(&mut result);
                result.insert(EdgeKind::Feature);
            }
            "features" => {
                result.insert(EdgeKind::Feature);
            }
            "normal" => {
                result.insert(EdgeKind::Dep(DepKind::Normal));
            }
            "build" => {
                result.insert(EdgeKind::Dep(DepKind::Build));
            }
            "dev" => {
                result.insert(EdgeKind::Dep(DepKind::Development));
            }
            k => return unknown(k),
        }
    }
    if kinds.len() == 1 && kinds[0] == "features" {
        insert_defaults(&mut result);
    }
    Ok(result)
}
<commit_msg>Auto merge of #8766 - weihanglo:cmd/tree-all-targets, r=ehuss<commit_after>use crate::cli;
use crate::command_prelude::*;
use anyhow::{bail, format_err};
use cargo::core::dependency::DepKind;
use cargo::ops::tree::{self, EdgeKind};
use cargo::ops::Packages;
use cargo::util::CargoResult;
use std::collections::HashSet;
use std::str::FromStr;

pub fn cli() -> App {
    subcommand("tree")
        .about("Display a tree visualization of a dependency graph")
        .arg(opt("quiet", "Suppress status messages").short("q"))
        .arg_manifest_path()
        .arg_package_spec_no_all(
            "Package to be used as the root of the tree",
            "Display the tree for all packages in the workspace",
            "Exclude specific workspace members",
        )
        .arg(Arg::with_name("all").long("all").short("a").hidden(true))
        .arg(
            Arg::with_name("all-targets")
                .long("all-targets")
                .hidden(true),
        )
        .arg_features()
        .arg_target_triple(
            "Filter dependencies matching the given target-triple (default host platform). \
            Pass `all` to include all targets.",
        )
        .arg(
            Arg::with_name("no-dev-dependencies")
                .long("no-dev-dependencies")
                .hidden(true),
        )
        .arg(
            multi_opt(
                "edges",
                "KINDS",
                "The kinds of dependencies to display \
                 (features, normal, build, dev, all, no-dev, no-build, no-normal)",
            )
            .short("e"),
        )
        .arg(
            optional_multi_opt(
                "invert",
                "SPEC",
                "Invert the tree direction and focus on the given package",
            )
            .short("i"),
        )
        .arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
        .arg(
            Arg::with_name("prefix-depth")
                .long("prefix-depth")
                .hidden(true),
        )
        .arg(
            opt(
                "prefix",
                "Change the prefix (indentation) of how each entry is displayed",
            )
            .value_name("PREFIX")
            .possible_values(&["depth", "indent", "none"])
            .default_value("indent"),
        )
        .arg(opt(
            "no-dedupe",
            "Do not de-duplicate (repeats all shared dependencies)",
        ))
        .arg(
            opt(
                "duplicates",
                "Show only dependencies which come in multiple versions (implies -i)",
            )
            .short("d")
            .alias("duplicate"),
        )
        .arg(
            opt("charset", "Character set to use in output: utf8, ascii")
                .value_name("CHARSET")
                .possible_values(&["utf8", "ascii"])
                .default_value("utf8"),
        )
        .arg(
            opt("format", "Format string used for printing dependencies")
                .value_name("FORMAT")
                .short("f")
                .default_value("{p}"),
        )
        .arg(
            // Backwards compatibility with old cargo-tree.
            Arg::with_name("version")
                .long("version")
                .short("V")
                .hidden(true),
        )
        .after_help("Run `cargo help tree` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    if args.is_present("version") {
        let verbose = args.occurrences_of("verbose") > 0;
        let version = cli::get_version_string(verbose);
        cargo::drop_print!(config, "{}", version);
        return Ok(());
    }
    let prefix = if args.is_present("no-indent") {
        config
            .shell()
            .warn("the --no-indent flag has been changed to --prefix=none")?;
        "none"
    } else if args.is_present("prefix-depth") {
        config
            .shell()
            .warn("the --prefix-depth flag has been changed to --prefix=depth")?;
        "depth"
    } else {
        args.value_of("prefix").unwrap()
    };
    let prefix = tree::Prefix::from_str(prefix).map_err(|e| anyhow::anyhow!("{}", e))?;

    let no_dedupe = args.is_present("no-dedupe") || args.is_present("all");
    if args.is_present("all") {
        config.shell().warn(
            "The `cargo tree` --all flag has been changed to --no-dedupe, \
             and may be removed in a future version.\n\
             If you are looking to display all workspace members, use the --workspace flag.",
        )?;
    }

    let targets = if args.is_present("all-targets") {
        config
            .shell()
            .warn("the --all-targets flag has been changed to --target=all")?;
        vec!["all".to_string()]
    } else {
        args._values_of("target")
    };
    let target = tree::Target::from_cli(targets);

    let edge_kinds = parse_edge_kinds(config, args)?;
    let graph_features = edge_kinds.contains(&EdgeKind::Feature);

    let packages = args.packages_from_flags()?;
    let mut invert = args
        .values_of("invert")
        .map_or_else(|| Vec::new(), |is| is.map(|s| s.to_string()).collect());
    if args.is_present_with_zero_values("invert") {
        match &packages {
            Packages::Packages(ps) => {
                // Backwards compatibility with old syntax of `cargo tree -i -p foo`.
                invert.extend(ps.clone());
            }
            _ => {
                return Err(format_err!(
                    "The `-i` flag requires a package name.\n\
\n\
The `-i` flag is used to inspect the reverse dependencies of a specific\n\
package. It will invert the tree and display the packages that depend on the\n\
given package.\n\
\n\
Note that in a workspace, by default it will only display the package's\n\
reverse dependencies inside the tree of the workspace member in the current\n\
directory. The --workspace flag can be used to extend it so that it will show\n\
the package's reverse dependencies across the entire workspace. The -p flag\n\
can be used to display the package's reverse dependencies only with the\n\
subtree of the package given to -p.\n\
"
                )
                .into());
            }
        }
    }

    let ws = args.workspace(config)?;
    let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let opts = tree::TreeOptions {
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        packages,
        target,
        edge_kinds,
        invert,
        prefix,
        no_dedupe,
        duplicates: args.is_present("duplicates"),
        charset,
        format: args.value_of("format").unwrap().to_string(),
        graph_features,
    };

    tree::build_and_print(&ws, &opts)?;
    Ok(())
}

fn parse_edge_kinds(config: &Config, args: &ArgMatches<'_>) -> CargoResult<HashSet<EdgeKind>> {
    let mut kinds: Vec<&str> = args
        .values_of("edges")
        .map_or_else(|| Vec::new(), |es| es.flat_map(|e| e.split(',')).collect());
    if args.is_present("no-dev-dependencies") {
        config
            .shell()
            .warn("the --no-dev-dependencies flag has changed to -e=no-dev")?;
        kinds.push("no-dev");
    }
    if kinds.is_empty() {
        kinds.extend(&["normal", "build", "dev"]);
    }

    let mut result = HashSet::new();
    let insert_defaults = |result: &mut HashSet<EdgeKind>| {
        result.insert(EdgeKind::Dep(DepKind::Normal));
        result.insert(EdgeKind::Dep(DepKind::Build));
        result.insert(EdgeKind::Dep(DepKind::Development));
    };
    let unknown = |k| {
        bail!(
            "unknown edge kind `{}`, valid values are \
                \"normal\", \"build\", \"dev\", \
                \"no-normal\", \"no-build\", \"no-dev\", \
                \"features\", or \"all\"",
            k
        )
    };
    if kinds.iter().any(|k| k.starts_with("no-")) {
        insert_defaults(&mut result);
        for kind in &kinds {
            match *kind {
                "no-normal" => result.remove(&EdgeKind::Dep(DepKind::Normal)),
                "no-build" => result.remove(&EdgeKind::Dep(DepKind::Build)),
                "no-dev" => result.remove(&EdgeKind::Dep(DepKind::Development)),
                "features" => result.insert(EdgeKind::Feature),
                "normal" | "build" | "dev" | "all" => {
                    bail!("`no-` dependency kinds cannot be mixed with other dependency kinds")
                }
                k => return unknown(k),
            };
        }
        return Ok(result);
    }
    for kind in &kinds {
        match *kind {
            "all" => {
                insert_defaults(&mut result);
                result.insert(EdgeKind::Feature);
            }
            "features" => {
                result.insert(EdgeKind::Feature);
            }
            "normal" => {
                result.insert(EdgeKind::Dep(DepKind::Normal));
            }
            "build" => {
                result.insert(EdgeKind::Dep(DepKind::Build));
            }
            "dev" => {
                result.insert(EdgeKind::Dep(DepKind::Development));
            }
            k => return unknown(k),
        }
    }
    if kinds.len() == 1 && kinds[0] == "features" {
        insert_defaults(&mut result);
    }
    Ok(result)
}
<|endoftext|>


<commit_before>// a thunk is a function that immediately unconditionally jumps to another
// function. often seen with thunks to imports.

use std::collections::BTreeSet;

use crate::{
    analysis::cfg::{flow::Flow, CFG},
    VA,
};

pub fn find_thunks<'a, T>(cfg: &CFG, functions: T) -> BTreeSet<VA>
where
    T: Iterator<Item = &'a VA>,
{
    let mut thunks: BTreeSet<VA> = Default::default();

    for &function in functions {
        println!("is thunk: {:#x}", function);

        if let Some(succs) = cfg.flows.flows_by_src.get(&function) {
            if succs.len() != 1 {
                println!("succs: {}", succs.len());
                continue;
            }

            println!("succ: {:x?}", succs[0]);

            if let Flow::UnconditionalJump(_) = succs[0] {
                thunks.insert(function);
            }
        }
    }

    return thunks;
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        analysis::cfg::{InstructionIndex, CFG},
        rsrc::*,
    };
    use anyhow::Result;

    #[test]
    fn nop() -> Result<()> {
        let buf = get_buf(Rsrc::NOP);
        let pe = crate::loader::pe::PE::from_bytes(&buf)?;

        let mut insns: InstructionIndex = Default::default();

        for &ep in crate::analysis::pe::entrypoints::find_pe_entrypoint(&pe)?.iter() {
            insns.build_index(&pe.module, ep)?;
        }

        for &exp in crate::analysis::pe::exports::find_pe_exports(&pe)?.iter() {
            insns.build_index(&pe.module, exp)?;
        }

        // int __cdecl _except_handler3(int, PVOID TargetFrame, int)
        // eventually flows to RtlUnwind
        insns.build_index(&pe.module, 0x4027F4)?;

        let cfg = CFG::from_instructions(&pe.module, insns)?;

        let thunks = find_thunks(&cfg, [0x405F42, 0x401000].iter());

        // ```
        //     .text:00405F42  ; void __stdcall RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue)
        //     .text:00405F42  RtlUnwind       proc near               ; CODE XREF: __global_unwind2+13↑p
        //     .text:00405F42
        //     .text:00405F42  TargetFrame     = dword ptr  4
        //     .text:00405F42  TargetIp        = dword ptr  8
        //     .text:00405F42  ExceptionRecord = dword ptr  0Ch
        //     .text:00405F42  ReturnValue     = dword ptr  10h
        //     .text:00405F42
        //     .text:00405F42 000 FF 25 7C 60 40 00  jmp     ds:__imp_RtlUnwind
        //     .text:00405F42  RtlUnwind       endp
        // ```
        assert!(thunks.contains(&0x405F42));

        Ok(())
    }
}
<commit_msg>thunk: remove old print statements<commit_after>// a thunk is a function that immediately unconditionally jumps to another
// function. often seen with thunks to imports.

use std::collections::BTreeSet;

use crate::{
    analysis::cfg::{flow::Flow, CFG},
    VA,
};

pub fn find_thunks<'a, T>(cfg: &CFG, functions: T) -> BTreeSet<VA>
where
    T: Iterator<Item = &'a VA>,
{
    let mut thunks: BTreeSet<VA> = Default::default();

    for &function in functions {
        if let Some(succs) = cfg.flows.flows_by_src.get(&function) {
            if succs.len() != 1 {
                continue;
            }

            if let Flow::UnconditionalJump(_) = succs[0] {
                thunks.insert(function);
            }
        }
    }

    return thunks;
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        analysis::cfg::{InstructionIndex, CFG},
        rsrc::*,
    };
    use anyhow::Result;

    #[test]
    fn nop() -> Result<()> {
        let buf = get_buf(Rsrc::NOP);
        let pe = crate::loader::pe::PE::from_bytes(&buf)?;

        let mut insns: InstructionIndex = Default::default();

        for &ep in crate::analysis::pe::entrypoints::find_pe_entrypoint(&pe)?.iter() {
            insns.build_index(&pe.module, ep)?;
        }

        for &exp in crate::analysis::pe::exports::find_pe_exports(&pe)?.iter() {
            insns.build_index(&pe.module, exp)?;
        }

        // int __cdecl _except_handler3(int, PVOID TargetFrame, int)
        // eventually flows to RtlUnwind
        insns.build_index(&pe.module, 0x4027F4)?;

        let cfg = CFG::from_instructions(&pe.module, insns)?;

        let thunks = find_thunks(&cfg, [0x405F42, 0x401000].iter());

        // ```
        //     .text:00405F42  ; void __stdcall RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue)
        //     .text:00405F42  RtlUnwind       proc near               ; CODE XREF: __global_unwind2+13↑p
        //     .text:00405F42
        //     .text:00405F42  TargetFrame     = dword ptr  4
        //     .text:00405F42  TargetIp        = dword ptr  8
        //     .text:00405F42  ExceptionRecord = dword ptr  0Ch
        //     .text:00405F42  ReturnValue     = dword ptr  10h
        //     .text:00405F42
        //     .text:00405F42 000 FF 25 7C 60 40 00  jmp     ds:__imp_RtlUnwind
        //     .text:00405F42  RtlUnwind       endp
        // ```
        assert!(thunks.contains(&0x405F42));

        Ok(())
    }
}
<|endoftext|>


<commit_before>use dispatcher::Module;
use dispatcher::MsgSender;

use rand::distributions::Normal;
use rand::prelude::*;

use std::collections::HashMap;

#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
enum MeasurementType {
    Temperature,
    Humidity,
    Pressure,
    LightLevel,
}

#[derive(Debug)]
pub struct MeteoModule {
    last_values: HashMap<MeasurementType, HashMap<u32, f64>>,
    rng: SmallRng,
}

impl MeteoModule {
    pub fn new() -> MeteoModule {
        let mut last_values = HashMap::new();
        last_values.insert(MeasurementType::Temperature, HashMap::new());
        last_values.insert(MeasurementType::Humidity, HashMap::new());
        last_values.insert(MeasurementType::Pressure, HashMap::new());
        last_values.insert(MeasurementType::LightLevel, HashMap::new());

        let rng = SmallRng::from_entropy();

        MeteoModule { last_values, rng }
    }
    fn generate_new_value(&mut self, meas_type: MeasurementType, ch_num: u32) -> f32 {
        let dist = {
            let last_value = self.last_values[&meas_type].get(&ch_num);

            match meas_type {
                MeasurementType::Temperature => Normal::new(*last_value.unwrap_or(&25.0), 1.0),
                MeasurementType::Humidity => Normal::new(*last_value.unwrap_or(&65.0), 0.3),
                MeasurementType::Pressure => Normal::new(*last_value.unwrap_or(&101_325.0), 100.0),
                MeasurementType::LightLevel => Normal::new(*last_value.unwrap_or(&1000.0), 10.0),
            }
        };

        let val = self.rng.sample(dist);

        self.last_values
            .get_mut(&meas_type)
            .unwrap()
            .insert(ch_num, val);

        val as f32
    }
}

impl Module for MeteoModule {
    fn handle_incoming_msg(
        &mut self,
        msg_writer: &mut MsgSender,
        transaction_id: u32,
        msg_str: &str,
    ) -> Result<(), ()> {
        trace!("Handling message: {} {}", transaction_id, msg_str);

        let mut values = msg_str.split(',');

        let msg_type = values.next().ok_or(())?;
        let ch_num = values.next().ok_or(())?.parse::<u32>().map_err(|_| ())?;

        let response_payload_str = match msg_type {
            "GET_TEMPERATURE" => format!(
                "TEMPERATURE_REPLY,{},{}",
                ch_num,
                self.generate_new_value(MeasurementType::Temperature, ch_num)
            ),
            "GET_HUMIDITY" => format!(
                "HUMIDITY_REPLY,{},{}",
                ch_num,
                self.generate_new_value(MeasurementType::Humidity, ch_num)
            ),
            "GET_PRESSURE" => format!(
                "PRESSURE_REPLY,{},{}",
                ch_num,
                self.generate_new_value(MeasurementType::Pressure, ch_num)
            ),
            "GET_LIGHT_LEVEL" => format!(
                "LIGHT_LEVEL_REPLY,{},{}",
                ch_num,
                self.generate_new_value(MeasurementType::LightLevel, ch_num)
            ),
            unknown_msg_type_str => {
                warn!("Unknown message type: {}", unknown_msg_type_str);
                return Err(());
            }
        };

        msg_writer.write_msg(transaction_id, "METEO", &response_payload_str)
    }
}
<commit_msg>Added traces to node stub Meteo module<commit_after>use dispatcher::Module;
use dispatcher::MsgSender;

use rand::distributions::Normal;
use rand::prelude::*;

use std::collections::HashMap;

#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
enum MeasurementType {
    Temperature,
    Humidity,
    Pressure,
    LightLevel,
}

#[derive(Debug)]
pub struct MeteoModule {
    last_values: HashMap<MeasurementType, HashMap<u32, f64>>,
    rng: SmallRng,
}

impl MeteoModule {
    pub fn new() -> MeteoModule {
        let mut last_values = HashMap::new();
        last_values.insert(MeasurementType::Temperature, HashMap::new());
        last_values.insert(MeasurementType::Humidity, HashMap::new());
        last_values.insert(MeasurementType::Pressure, HashMap::new());
        last_values.insert(MeasurementType::LightLevel, HashMap::new());

        let rng = SmallRng::from_entropy();

        MeteoModule { last_values, rng }
    }
    fn generate_new_value(&mut self, meas_type: MeasurementType, ch_num: u32) -> f32 {
        let dist = {
            let last_value = self.last_values[&meas_type].get(&ch_num);

            match meas_type {
                MeasurementType::Temperature => Normal::new(*last_value.unwrap_or(&25.0), 1.0),
                MeasurementType::Humidity => Normal::new(*last_value.unwrap_or(&65.0), 0.3),
                MeasurementType::Pressure => Normal::new(*last_value.unwrap_or(&101_325.0), 100.0),
                MeasurementType::LightLevel => Normal::new(*last_value.unwrap_or(&1000.0), 10.0),
            }
        };

        trace!("Using distribution: {:?}", dist);

        let val = self.rng.sample(dist);

        self.last_values
            .get_mut(&meas_type)
            .unwrap()
            .insert(ch_num, val);

        val as f32
    }
}

impl Module for MeteoModule {
    fn handle_incoming_msg(
        &mut self,
        msg_writer: &mut MsgSender,
        transaction_id: u32,
        msg_str: &str,
    ) -> Result<(), ()> {
        debug!("Handling message: {} {}", transaction_id, msg_str);

        let mut values = msg_str.split(',');

        let msg_type = values.next().ok_or(())?;
        let ch_num = values.next().ok_or(())?.parse::<u32>().map_err(|_| ())?;

        let response_payload_str = match msg_type {
            "GET_TEMPERATURE" => format!(
                "TEMPERATURE_REPLY,{},{}",
                ch_num,
                self.generate_new_value(MeasurementType::Temperature, ch_num)
            ),
            "GET_HUMIDITY" => format!(
                "HUMIDITY_REPLY,{},{}",
                ch_num,
                self.generate_new_value(MeasurementType::Humidity, ch_num)
            ),
            "GET_PRESSURE" => format!(
                "PRESSURE_REPLY,{},{}",
                ch_num,
                self.generate_new_value(MeasurementType::Pressure, ch_num)
            ),
            "GET_LIGHT_LEVEL" => format!(
                "LIGHT_LEVEL_REPLY,{},{}",
                ch_num,
                self.generate_new_value(MeasurementType::LightLevel, ch_num)
            ),
            unknown_msg_type_str => {
                warn!("Unknown message type: {}", unknown_msg_type_str);
                return Err(());
            }
        };

        msg_writer.write_msg(transaction_id, "METEO", &response_payload_str)
    }
}
<|endoftext|>


<commit_before>//! Eager expansion related utils
//!
//! Here is a dump of a discussion from Vadim Petrochenkov about Eager Expansion and
//! Its name resolution :
//!
//! > Eagerly expanded macros (and also macros eagerly expanded by eagerly expanded macros,
//! > which actually happens in practice too!) are resolved at the location of the "root" macro
//! > that performs the eager expansion on its arguments.
//! > If some name cannot be resolved at the eager expansion time it's considered unresolved,
//! > even if becomes available later (e.g. from a glob import or other macro).
//!
//! > Eagerly expanded macros don't add anything to the module structure of the crate and
//! > don't build any speculative module structures, i.e. they are expanded in a "flat"
//! > way even if tokens in them look like modules.
//!
//! > In other words, it kinda works for simple cases for which it was originally intended,
//! > and we need to live with it because it's available on stable and widely relied upon.
//!
//!
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
use std::sync::Arc;

use base_db::CrateId;
use mbe::ExpandResult;
use syntax::{ted, SyntaxNode};

use crate::{
    ast::{self, AstNode},
    db::AstDatabase,
    EagerCallInfo, ExpandTo, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
    MacroDefKind,
};

#[derive(Debug)]
pub struct ErrorEmitted {
    _private: (),
}

pub trait ErrorSink {
    fn emit(&mut self, err: mbe::ExpandError);

    fn option<T>(
        &mut self,
        opt: Option<T>,
        error: impl FnOnce() -> mbe::ExpandError,
    ) -> Result<T, ErrorEmitted> {
        match opt {
            Some(it) => Ok(it),
            None => {
                self.emit(error());
                Err(ErrorEmitted { _private: () })
            }
        }
    }

    fn option_with<T>(
        &mut self,
        opt: impl FnOnce() -> Option<T>,
        error: impl FnOnce() -> mbe::ExpandError,
    ) -> Result<T, ErrorEmitted> {
        self.option(opt(), error)
    }

    fn result<T>(&mut self, res: Result<T, mbe::ExpandError>) -> Result<T, ErrorEmitted> {
        match res {
            Ok(it) => Ok(it),
            Err(e) => {
                self.emit(e);
                Err(ErrorEmitted { _private: () })
            }
        }
    }

    fn expand_result_option<T>(&mut self, res: ExpandResult<Option<T>>) -> Result<T, ErrorEmitted> {
        match (res.value, res.err) {
            (None, Some(err)) => {
                self.emit(err);
                Err(ErrorEmitted { _private: () })
            }
            (Some(value), opt_err) => {
                if let Some(err) = opt_err {
                    self.emit(err);
                }
                Ok(value)
            }
            (None, None) => unreachable!("`ExpandResult` without value or error"),
        }
    }
}

impl ErrorSink for &'_ mut dyn FnMut(mbe::ExpandError) {
    fn emit(&mut self, err: mbe::ExpandError) {
        self(err);
    }
}

fn err(msg: impl Into<String>) -> mbe::ExpandError {
    mbe::ExpandError::Other(msg.into())
}

pub fn expand_eager_macro(
    db: &dyn AstDatabase,
    krate: CrateId,
    macro_call: InFile<ast::MacroCall>,
    def: MacroDefId,
    resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
    mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
) -> Result<MacroCallId, ErrorEmitted> {
    let parsed_args = diagnostic_sink.option_with(
        || Some(mbe::syntax_node_to_token_tree(macro_call.value.token_tree()?.syntax()).0),
        || err("malformed macro invocation"),
    )?;

    let ast_map = db.ast_id_map(macro_call.file_id);
    let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(&macro_call.value));
    let expand_to = ExpandTo::from_call_site(&macro_call.value);

    // Note:
    // When `lazy_expand` is called, its *parent* file must be already exists.
    // Here we store an eager macro id for the argument expanded subtree here
    // for that purpose.
    let arg_id = db.intern_macro(MacroCallLoc {
        def,
        krate,
        eager: Some(EagerCallInfo {
            arg_or_expansion: Arc::new(parsed_args.clone()),
            included_file: None,
        }),
        kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr },
    });
    let arg_file_id = arg_id;

    let parsed_args = diagnostic_sink
        .result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::ParserEntryPoint::Expr))?
        .0;
    let result = eager_macro_recur(
        db,
        InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
        krate,
        resolver,
        diagnostic_sink,
    )?;
    let subtree =
        diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?;

    if let MacroDefKind::BuiltInEager(eager, _) = def.kind {
        let res = eager.expand(db, arg_id, &subtree);

        let expanded = diagnostic_sink.expand_result_option(res)?;
        let loc = MacroCallLoc {
            def,
            krate,
            eager: Some(EagerCallInfo {
                arg_or_expansion: Arc::new(expanded.subtree),
                included_file: expanded.included_file,
            }),
            kind: MacroCallKind::FnLike { ast_id: call_id, expand_to },
        };

        Ok(db.intern_macro(loc))
    } else {
        panic!("called `expand_eager_macro` on non-eager macro def {:?}", def);
    }
}

fn to_subtree(node: &SyntaxNode) -> Option<tt::Subtree> {
    let mut subtree = mbe::syntax_node_to_token_tree(node).0;
    subtree.delimiter = None;
    Some(subtree)
}

fn lazy_expand(
    db: &dyn AstDatabase,
    def: &MacroDefId,
    macro_call: InFile<ast::MacroCall>,
    krate: CrateId,
) -> ExpandResult<Option<InFile<SyntaxNode>>> {
    let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);

    let expand_to = ExpandTo::from_call_site(&macro_call.value);
    let id = def.as_lazy_macro(
        db,
        krate,
        MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to },
    );

    let err = db.macro_expand_error(id);
    let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));

    ExpandResult { value, err }
}

fn eager_macro_recur(
    db: &dyn AstDatabase,
    curr: InFile<SyntaxNode>,
    krate: CrateId,
    macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
    mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
) -> Result<SyntaxNode, ErrorEmitted> {
    let original = curr.value.clone_for_update();

    let children = original.descendants().filter_map(ast::MacroCall::cast);
    let mut replacements = Vec::new();

    // Collect replacement
    for child in children {
        let def = diagnostic_sink
            .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?;
        let insert = match def.kind {
            MacroDefKind::BuiltInEager(..) => {
                let id = expand_eager_macro(
                    db,
                    krate,
                    curr.with_value(child.clone()),
                    def,
                    macro_resolver,
                    diagnostic_sink,
                )?;
                db.parse_or_expand(id.as_file())
                    .expect("successful macro expansion should be parseable")
                    .clone_for_update()
            }
            MacroDefKind::Declarative(_)
            | MacroDefKind::BuiltIn(..)
            | MacroDefKind::BuiltInAttr(..)
            | MacroDefKind::BuiltInDerive(..)
            | MacroDefKind::ProcMacro(..) => {
                let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
                let val = diagnostic_sink.expand_result_option(res)?;

                // replace macro inside
                eager_macro_recur(db, val, krate, macro_resolver, diagnostic_sink)?
            }
        };

        // check if the whole original syntax is replaced
        if child.syntax() == &original {
            return Ok(insert);
        }

        replacements.push((child, insert));
    }

    replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
    Ok(original)
}
<commit_msg>Include macro path in eager macro resolve error<commit_after>//! Eager expansion related utils
//!
//! Here is a dump of a discussion from Vadim Petrochenkov about Eager Expansion and
//! Its name resolution :
//!
//! > Eagerly expanded macros (and also macros eagerly expanded by eagerly expanded macros,
//! > which actually happens in practice too!) are resolved at the location of the "root" macro
//! > that performs the eager expansion on its arguments.
//! > If some name cannot be resolved at the eager expansion time it's considered unresolved,
//! > even if becomes available later (e.g. from a glob import or other macro).
//!
//! > Eagerly expanded macros don't add anything to the module structure of the crate and
//! > don't build any speculative module structures, i.e. they are expanded in a "flat"
//! > way even if tokens in them look like modules.
//!
//! > In other words, it kinda works for simple cases for which it was originally intended,
//! > and we need to live with it because it's available on stable and widely relied upon.
//!
//!
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
use std::sync::Arc;

use base_db::CrateId;
use mbe::ExpandResult;
use syntax::{ted, SyntaxNode};

use crate::{
    ast::{self, AstNode},
    db::AstDatabase,
    EagerCallInfo, ExpandTo, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
    MacroDefKind,
};

#[derive(Debug)]
pub struct ErrorEmitted {
    _private: (),
}

pub trait ErrorSink {
    fn emit(&mut self, err: mbe::ExpandError);

    fn option<T>(
        &mut self,
        opt: Option<T>,
        error: impl FnOnce() -> mbe::ExpandError,
    ) -> Result<T, ErrorEmitted> {
        match opt {
            Some(it) => Ok(it),
            None => {
                self.emit(error());
                Err(ErrorEmitted { _private: () })
            }
        }
    }

    fn option_with<T>(
        &mut self,
        opt: impl FnOnce() -> Option<T>,
        error: impl FnOnce() -> mbe::ExpandError,
    ) -> Result<T, ErrorEmitted> {
        self.option(opt(), error)
    }

    fn result<T>(&mut self, res: Result<T, mbe::ExpandError>) -> Result<T, ErrorEmitted> {
        match res {
            Ok(it) => Ok(it),
            Err(e) => {
                self.emit(e);
                Err(ErrorEmitted { _private: () })
            }
        }
    }

    fn expand_result_option<T>(&mut self, res: ExpandResult<Option<T>>) -> Result<T, ErrorEmitted> {
        match (res.value, res.err) {
            (None, Some(err)) => {
                self.emit(err);
                Err(ErrorEmitted { _private: () })
            }
            (Some(value), opt_err) => {
                if let Some(err) = opt_err {
                    self.emit(err);
                }
                Ok(value)
            }
            (None, None) => unreachable!("`ExpandResult` without value or error"),
        }
    }
}

impl ErrorSink for &'_ mut dyn FnMut(mbe::ExpandError) {
    fn emit(&mut self, err: mbe::ExpandError) {
        self(err);
    }
}

fn err(msg: impl Into<String>) -> mbe::ExpandError {
    mbe::ExpandError::Other(msg.into())
}

pub fn expand_eager_macro(
    db: &dyn AstDatabase,
    krate: CrateId,
    macro_call: InFile<ast::MacroCall>,
    def: MacroDefId,
    resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
    mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
) -> Result<MacroCallId, ErrorEmitted> {
    let parsed_args = diagnostic_sink.option_with(
        || Some(mbe::syntax_node_to_token_tree(macro_call.value.token_tree()?.syntax()).0),
        || err("malformed macro invocation"),
    )?;

    let ast_map = db.ast_id_map(macro_call.file_id);
    let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(&macro_call.value));
    let expand_to = ExpandTo::from_call_site(&macro_call.value);

    // Note:
    // When `lazy_expand` is called, its *parent* file must be already exists.
    // Here we store an eager macro id for the argument expanded subtree here
    // for that purpose.
    let arg_id = db.intern_macro(MacroCallLoc {
        def,
        krate,
        eager: Some(EagerCallInfo {
            arg_or_expansion: Arc::new(parsed_args.clone()),
            included_file: None,
        }),
        kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr },
    });
    let arg_file_id = arg_id;

    let parsed_args = diagnostic_sink
        .result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::ParserEntryPoint::Expr))?
        .0;
    let result = eager_macro_recur(
        db,
        InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
        krate,
        resolver,
        diagnostic_sink,
    )?;
    let subtree =
        diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?;

    if let MacroDefKind::BuiltInEager(eager, _) = def.kind {
        let res = eager.expand(db, arg_id, &subtree);

        let expanded = diagnostic_sink.expand_result_option(res)?;
        let loc = MacroCallLoc {
            def,
            krate,
            eager: Some(EagerCallInfo {
                arg_or_expansion: Arc::new(expanded.subtree),
                included_file: expanded.included_file,
            }),
            kind: MacroCallKind::FnLike { ast_id: call_id, expand_to },
        };

        Ok(db.intern_macro(loc))
    } else {
        panic!("called `expand_eager_macro` on non-eager macro def {:?}", def);
    }
}

fn to_subtree(node: &SyntaxNode) -> Option<tt::Subtree> {
    let mut subtree = mbe::syntax_node_to_token_tree(node).0;
    subtree.delimiter = None;
    Some(subtree)
}

fn lazy_expand(
    db: &dyn AstDatabase,
    def: &MacroDefId,
    macro_call: InFile<ast::MacroCall>,
    krate: CrateId,
) -> ExpandResult<Option<InFile<SyntaxNode>>> {
    let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);

    let expand_to = ExpandTo::from_call_site(&macro_call.value);
    let id = def.as_lazy_macro(
        db,
        krate,
        MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to },
    );

    let err = db.macro_expand_error(id);
    let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));

    ExpandResult { value, err }
}

fn eager_macro_recur(
    db: &dyn AstDatabase,
    curr: InFile<SyntaxNode>,
    krate: CrateId,
    macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
    mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
) -> Result<SyntaxNode, ErrorEmitted> {
    let original = curr.value.clone_for_update();

    let children = original.descendants().filter_map(ast::MacroCall::cast);
    let mut replacements = Vec::new();

    // Collect replacement
    for child in children {
        let def = diagnostic_sink.option_with(
            || macro_resolver(child.path()?),
            || {
                let path = child.path().map(|path| format!(" `{}!`", path)).unwrap_or_default();
                err(format!("failed to resolve macro{}", path))
            },
        )?;
        let insert = match def.kind {
            MacroDefKind::BuiltInEager(..) => {
                let id = expand_eager_macro(
                    db,
                    krate,
                    curr.with_value(child.clone()),
                    def,
                    macro_resolver,
                    diagnostic_sink,
                )?;
                db.parse_or_expand(id.as_file())
                    .expect("successful macro expansion should be parseable")
                    .clone_for_update()
            }
            MacroDefKind::Declarative(_)
            | MacroDefKind::BuiltIn(..)
            | MacroDefKind::BuiltInAttr(..)
            | MacroDefKind::BuiltInDerive(..)
            | MacroDefKind::ProcMacro(..) => {
                let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
                let val = diagnostic_sink.expand_result_option(res)?;

                // replace macro inside
                eager_macro_recur(db, val, krate, macro_resolver, diagnostic_sink)?
            }
        };

        // check if the whole original syntax is replaced
        if child.syntax() == &original {
            return Ok(insert);
        }

        replacements.push((child, insert));
    }

    replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
    Ok(original)
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use argh::FromArgs;
use devices::virtio::block::block::DiskOption;
use devices::virtio::vhost::user::device;
use devices::virtio::vhost::user::VhostUserParams;
use devices::SerialParameters;

use crate::crosvm::config::from_key_values;
use crate::crosvm::config::validate_serial_parameters;
use crate::crosvm::config::JailConfig;

#[derive(FromArgs)]
#[argh(subcommand)]
/// Unix Devices
pub enum DeviceSubcommand {
    Console(device::ConsoleOptions),
    #[cfg(feature = "audio")]
    Snd(device::SndOptions),
    Fs(device::FsOptions),
    #[cfg(feature = "gpu")]
    Gpu(device::GpuOptions),
    Vsock(device::VsockOptions),
    Wl(device::WlOptions),
}

fn parse_vu_serial_options(s: &str) -> Result<VhostUserParams<SerialParameters>, String> {
    let params: VhostUserParams<SerialParameters> = from_key_values(s)?;

    validate_serial_parameters(&params.device_params)?;

    Ok(params)
}

#[argh_helpers::pad_description_for_argh]
#[derive(FromArgs)]
#[argh(subcommand, name = "devices")]
/// Start one or several jailed device processes.
pub struct DevicesCommand {
    #[argh(switch)]
    /// disable sandboxing. Will nullify the --jail option if it was present.
    pub disable_sandbox: bool,

    #[argh(
        option,
        arg_name = "jail configuration",
        default = "Default::default()"
    )]
    /// set up the jail configuration.
    /// Possible key values:
    ///     pivot-root=/path - Path to empty directory to use for
    ///         sandbox pivot root.
    ///     seccomp-policy-dir=/path - Path to seccomp .policy files
    ///     seccomp-log-failures=(true|false) - Log seccomp filter
    ///         failures instead of them being fatal.
    pub jail: JailConfig,

    #[argh(
        option,
        arg_name = "serial options",
        from_str_fn(parse_vu_serial_options)
    )]
    /// start a serial device (see help from run command for options)
    pub serial: Vec<VhostUserParams<SerialParameters>>,

    #[argh(option, arg_name = "block options")]
    /// start a block device (see help from run command for options)
    pub block: Vec<VhostUserParams<DiskOption>>,
}

#[derive(FromArgs)]
#[argh(subcommand)]
/// Unix Commands
pub enum Commands {
    #[cfg(unix)]
    Devices(DevicesCommand),
}
<commit_msg>crosvm: devices: document serial option properly<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use argh::FromArgs;
use devices::virtio::block::block::DiskOption;
use devices::virtio::vhost::user::device;
use devices::virtio::vhost::user::VhostUserParams;
use devices::SerialParameters;

use crate::crosvm::config::from_key_values;
use crate::crosvm::config::validate_serial_parameters;
use crate::crosvm::config::JailConfig;

#[derive(FromArgs)]
#[argh(subcommand)]
/// Unix Devices
pub enum DeviceSubcommand {
    Console(device::ConsoleOptions),
    #[cfg(feature = "audio")]
    Snd(device::SndOptions),
    Fs(device::FsOptions),
    #[cfg(feature = "gpu")]
    Gpu(device::GpuOptions),
    Vsock(device::VsockOptions),
    Wl(device::WlOptions),
}

fn parse_vu_serial_options(s: &str) -> Result<VhostUserParams<SerialParameters>, String> {
    let params: VhostUserParams<SerialParameters> = from_key_values(s)?;

    validate_serial_parameters(&params.device_params)?;

    Ok(params)
}

#[argh_helpers::pad_description_for_argh]
#[derive(FromArgs)]
#[argh(subcommand, name = "devices")]
/// Start one or several jailed device processes.
pub struct DevicesCommand {
    #[argh(switch)]
    /// disable sandboxing. Will nullify the --jail option if it was present.
    pub disable_sandbox: bool,

    #[argh(
        option,
        arg_name = "jail configuration",
        default = "Default::default()"
    )]
    /// set up the jail configuration.
    /// Possible key values:
    ///     pivot-root=/path - Path to empty directory to use for
    ///         sandbox pivot root.
    ///     seccomp-policy-dir=/path - Path to seccomp .policy files
    ///     seccomp-log-failures=(true|false) - Log seccomp filter
    ///         failures instead of them being fatal.
    pub jail: JailConfig,

    #[argh(
        option,
        arg_name = "vhost=PATH,type=TYPE,[hardware=HW,num=NUM,path=PATH,input=PATH,console,earlycon,stdin]",
        from_str_fn(parse_vu_serial_options)
    )]
    /// comma separated key=value pairs for setting up serial
    /// devices. Can be given more than once.
    /// Possible key values:
    ///     vhost=PATH - Path to a vhost-user endpoint to listen to.
    ///     type=(stdout,syslog,sink,file) - Where to route the
    ///        serial device
    ///     hardware=(serial,virtio-console) - Which type of serial
    ///        hardware to emulate. Defaults to 8250 UART (serial).
    ///     num=(1,2,3,4) - Serial Device Number. If not provided,
    ///        num will default to 1.
    ///     path=PATH - The path to the file to write to when
    ///        type=file
    ///     input=PATH - The path to the file to read from when not
    ///        stdin
    ///     console - Use this serial device as the guest console.
    ///        Can only be given once. Will default to first
    ///        serial port if not provided.
    ///     earlycon - Use this serial device as the early console.
    ///        Can only be given once.
    ///     stdin - Direct standard input to this serial device.
    ///        Can only be given once. Will default to first serial
    ///        port if not provided.
    pub serial: Vec<VhostUserParams<SerialParameters>>,

    #[argh(option, arg_name = "block options")]
    /// start a block device (see help from run command for options)
    pub block: Vec<VhostUserParams<DiskOption>>,
}

#[derive(FromArgs)]
#[argh(subcommand)]
/// Unix Commands
pub enum Commands {
    #[cfg(unix)]
    Devices(DevicesCommand),
}
<|endoftext|>


<commit_before>use std::{
    collections::HashSet,
    iter::FromIterator,
};

use serde::{
    Deserialize,
    Serialize,
};

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct RawAccession {
    pub id: usize,
    pub urs_taxid: String,
    accession: String,
    common_name: Option<String>,
    database: String,
    external_id: String,
    function: Option<String>,
    gene_synonyms: Option<String>,
    gene: Option<String>,
    locus_tag: Option<String>,
    non_coding_id: Option<String>,
    notes: Option<String>,
    optional_id: Option<String>,
    organelle: Option<String>,
    parent_accession: Option<String>,
    product: Option<String>,
    species: Option<String>,
    standard_name: Option<String>,
    tax_string: Option<String>,
    authors: Option<String>,
    journal: Option<String>,
    pub_title: Option<String>,
    pub_id: Option<u64>,
    pubmed_id: Option<String>,
    doi: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct CrossReference {
    name: String,
    external_id: String,
    optional_id: Option<String>,
    accession: String,
    non_coding_id: Option<String>,
    parent_accession: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AccessionVec {
    species: HashSet<String>,
    organelles: HashSet<String>,
    tax_strings: HashSet<String>,
    functions: HashSet<String>,
    genes: HashSet<String>,
    gene_synonyms: HashSet<String>,
    common_name: HashSet<String>,
    notes: HashSet<String>,
    locus_tags: HashSet<String>,
    standard_names: HashSet<String>,
    products: HashSet<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ReferenceVec {
    authors: HashSet<String>,
    journals: HashSet<String>,
    pub_titles: HashSet<String>,
    pub_ids: HashSet<u64>,
    pubmed_ids: HashSet<String>,
    dois: HashSet<String>,
}

impl Default for ReferenceVec {
    fn default() -> Self {
        Self {
            authors: HashSet::new(),
            journals: HashSet::new(),
            pub_titles: HashSet::new(),
            pub_ids: HashSet::new(),
            pubmed_ids: HashSet::new(),
            dois: HashSet::new(),
        }
    }
}

impl Default for AccessionVec {
    fn default() -> Self {
        Self {
            species: HashSet::new(),
            organelles: HashSet::new(),
            tax_strings: HashSet::new(),
            functions: HashSet::new(),
            genes: HashSet::new(),
            gene_synonyms: HashSet::new(),
            common_name: HashSet::new(),
            notes: HashSet::new(),
            locus_tags: HashSet::new(),
            standard_names: HashSet::new(),
            products: HashSet::new(),
        }
    }
}

impl From<RawAccession> for CrossReference {
    fn from(raw: RawAccession) -> Self {
        Self {
            name: raw.database,
            external_id: raw.external_id,
            optional_id: raw.optional_id,
            accession: raw.accession,
            non_coding_id: raw.non_coding_id,
            parent_accession: raw.parent_accession,
        }
    }
}

fn insert(current: &mut HashSet<String>, raw: Option<String>) {
    match raw {
        None => (),
        Some(s) => match s.is_empty() {
            false => {
                current.insert(s);
            },
            true => (),
        },
    }
}

impl FromIterator<RawAccession> for AccessionVec {
    fn from_iter<I: IntoIterator<Item = RawAccession>>(iter: I) -> Self {
        let mut a = AccessionVec::default();

        for i in iter {
            insert(&mut a.species, i.species);
            insert(&mut a.tax_strings, i.tax_string);
            insert(&mut a.functions, i.function);
            insert(&mut a.organelles, i.organelle.map(|s| s.to_lowercase()));
            insert(&mut a.genes, i.gene);
            insert(&mut a.common_name, i.common_name.map(|s| s.to_lowercase()));
            insert(&mut a.notes, i.notes);
            insert(&mut a.locus_tags, i.locus_tag);
            insert(&mut a.standard_names, i.standard_name);
            insert(&mut a.products, i.product);

            for synonyms in i.gene_synonyms.into_iter() {
                if synonyms.contains(";") {
                    a.gene_synonyms
                        .extend(synonyms.split(";").map(|p| p.trim()).map(str::to_string))
                } else if synonyms.contains(",") {
                    a.gene_synonyms
                        .extend(synonyms.split(",").map(|p| p.trim()).map(str::to_string))
                } else {
                    a.gene_synonyms.insert(synonyms);
                }
            }
        }

        a
    }
}

impl FromIterator<RawAccession> for ReferenceVec {
    fn from_iter<I: IntoIterator<Item = RawAccession>>(iter: I) -> Self {
        let mut value = ReferenceVec::default();

        for i in iter {
            match i.authors {
                None => (),
                Some(authors) => {
                    let authors =
                        authors.split(", ").filter(|a| !a.is_empty()).map(|s| s.to_string());
                    value.authors.extend(authors);
                },
            }

            insert(&mut value.journals, i.journal);
            insert(&mut value.pub_titles, i.pub_title);
            insert(&mut value.pubmed_ids, i.pubmed_id);
            insert(&mut value.dois, i.doi);
            value.pub_ids.extend(i.pub_id.into_iter());
        }

        value
    }
}

impl CrossReference {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn external_id(&self) -> &str {
        &self.external_id
    }
}
<commit_msg>Remove bad publication title<commit_after>use std::{
    collections::HashSet,
    iter::FromIterator,
};

use serde::{
    Deserialize,
    Serialize,
};

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct RawAccession {
    pub id: usize,
    pub urs_taxid: String,
    accession: String,
    common_name: Option<String>,
    database: String,
    external_id: String,
    function: Option<String>,
    gene_synonyms: Option<String>,
    gene: Option<String>,
    locus_tag: Option<String>,
    non_coding_id: Option<String>,
    notes: Option<String>,
    optional_id: Option<String>,
    organelle: Option<String>,
    parent_accession: Option<String>,
    product: Option<String>,
    species: Option<String>,
    standard_name: Option<String>,
    tax_string: Option<String>,
    authors: Option<String>,
    journal: Option<String>,
    pub_title: Option<String>,
    pub_id: Option<u64>,
    pubmed_id: Option<String>,
    doi: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct CrossReference {
    name: String,
    external_id: String,
    optional_id: Option<String>,
    accession: String,
    non_coding_id: Option<String>,
    parent_accession: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AccessionVec {
    species: HashSet<String>,
    organelles: HashSet<String>,
    tax_strings: HashSet<String>,
    functions: HashSet<String>,
    genes: HashSet<String>,
    gene_synonyms: HashSet<String>,
    common_name: HashSet<String>,
    notes: HashSet<String>,
    locus_tags: HashSet<String>,
    standard_names: HashSet<String>,
    products: HashSet<String>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ReferenceVec {
    authors: HashSet<String>,
    journals: HashSet<String>,
    pub_titles: HashSet<String>,
    pub_ids: HashSet<u64>,
    pubmed_ids: HashSet<String>,
    dois: HashSet<String>,
}

impl Default for ReferenceVec {
    fn default() -> Self {
        Self {
            authors: HashSet::new(),
            journals: HashSet::new(),
            pub_titles: HashSet::new(),
            pub_ids: HashSet::new(),
            pubmed_ids: HashSet::new(),
            dois: HashSet::new(),
        }
    }
}

impl Default for AccessionVec {
    fn default() -> Self {
        Self {
            species: HashSet::new(),
            organelles: HashSet::new(),
            tax_strings: HashSet::new(),
            functions: HashSet::new(),
            genes: HashSet::new(),
            gene_synonyms: HashSet::new(),
            common_name: HashSet::new(),
            notes: HashSet::new(),
            locus_tags: HashSet::new(),
            standard_names: HashSet::new(),
            products: HashSet::new(),
        }
    }
}

impl From<RawAccession> for CrossReference {
    fn from(raw: RawAccession) -> Self {
        Self {
            name: raw.database,
            external_id: raw.external_id,
            optional_id: raw.optional_id,
            accession: raw.accession,
            non_coding_id: raw.non_coding_id,
            parent_accession: raw.parent_accession,
        }
    }
}

fn insert(current: &mut HashSet<String>, raw: Option<String>) {
    match raw {
        None => (),
        Some(s) => match s.is_empty() {
            false => {
                current.insert(s);
            },
            true => (),
        },
    }
}

impl FromIterator<RawAccession> for AccessionVec {
    fn from_iter<I: IntoIterator<Item = RawAccession>>(iter: I) -> Self {
        let mut a = AccessionVec::default();

        for i in iter {
            insert(&mut a.species, i.species);
            insert(&mut a.tax_strings, i.tax_string);
            insert(&mut a.functions, i.function);
            insert(&mut a.organelles, i.organelle.map(|s| s.to_lowercase()));
            insert(&mut a.genes, i.gene);
            insert(&mut a.common_name, i.common_name.map(|s| s.to_lowercase()));
            insert(&mut a.notes, i.notes);
            insert(&mut a.locus_tags, i.locus_tag);
            insert(&mut a.standard_names, i.standard_name);
            insert(&mut a.products, i.product);

            for synonyms in i.gene_synonyms.into_iter() {
                if synonyms.contains(";") {
                    a.gene_synonyms
                        .extend(synonyms.split(";").map(|p| p.trim()).map(str::to_string))
                } else if synonyms.contains(",") {
                    a.gene_synonyms
                        .extend(synonyms.split(",").map(|p| p.trim()).map(str::to_string))
                } else {
                    a.gene_synonyms.insert(synonyms);
                }
            }
        }

        a
    }
}

impl FromIterator<RawAccession> for ReferenceVec {
    fn from_iter<I: IntoIterator<Item = RawAccession>>(iter: I) -> Self {
        let mut value = ReferenceVec::default();

        for i in iter {
            match i.authors {
                None => (),
                Some(authors) => {
                    let authors =
                        authors.split(", ").filter(|a| !a.is_empty()).map(|s| s.to_string());
                    value.authors.extend(authors);
                },
            }

            insert(&mut value.journals, i.journal);
            insert(&mut value.pub_titles, i.pub_title);
            insert(&mut value.pubmed_ids, i.pubmed_id);
            insert(&mut value.dois, i.doi);
            value.pub_ids.extend(i.pub_id.into_iter());

            value.pub_titles.remove("None");
        }

        value
    }
}

impl CrossReference {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn external_id(&self) -> &str {
        &self.external_id
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod get_repos_should {
    use super::*;

    #[test]
    fn return_repos_with_app_name_hello_world_library_and_language_rust_and_program_type_lib_and_user_intrepion(
    ) {
        let expected = vec![GitHubRepository {
            app_name: "hello-world-library".to_string(),
            language: ProgrammingLanguage::Rust,
            program_type: ProgramType::Library,
        }];
    }
}

enum ProgrammingLanguage {
    Rust,
}

struct GitHubRepository {
    app_name: String,
    language: ProgrammingLanguage,
}
<commit_msg>green<commit_after>#[cfg(test)]
mod get_repos_should {
    use super::*;

    #[test]
    fn return_repos_with_app_name_hello_world_library_and_language_rust_and_program_type_lib_and_user_intrepion(
    ) {
        let expected = vec![GitHubRepository {
            app_name: "hello-world-library".to_string(),
            language: ProgrammingLanguage::Rust,
            program_type: ProgramType::Library,
        }];
    }
}

enum ProgrammingLanguage {
    Rust,
}

enum ProgramType {
    Library,
}

struct GitHubRepository {
    app_name: String,
    language: ProgrammingLanguage,
    program_type: ProgramType,
}
<|endoftext|>


<commit_before>//! Utilities to do with connections between a Minecraft or Forge client and Netherrack

extern crate chrono;
use self::chrono::duration::Duration;

use super::packet::PacketHeader;

use std::collections::VecDeque;

use std::net::{Shutdown, TcpStream};

use std::io::Read;

use super::deque_buffer::DequeBuffer;

/// An enum describing the current connection's state
pub enum ConnectionState {

    /// Connection is in handshake mode
    HANDSHAKE,

    /// Connection is in login mode
    LOGIN,

    /// Connection is in status mode
    STATUS,

    /// Connection is in play mode
    PLAY

}

/// A struct defining a game connection
pub struct GameConnection {

    /// The TCP stream bound to this GameConnection
    pub stream: TcpStream,

    /// The state of this GameConnection
    pub state: ConnectionState

}

impl GameConnection {

    /// Creates a new GameConnection
    pub fn new(stream: TcpStream) -> GameConnection {
        GameConnection {
            stream: stream,
            state: ConnectionState::HANDSHAKE
        }
    }

    /// Starts listening on the connection
    pub fn start_listening(&mut self) {

        info!("Got a new client from {}! Oh my!", self.stream.peer_addr().unwrap());

        let mut timeout_duration = Duration::zero();

        loop {

            if timeout_duration.num_seconds() >= 10 {
                info!("Client timed out; Shutdown was {:?}", self.stream.shutdown(Shutdown::Both));
                break;
            }

            let mut raw_buffer = vec![0u8; 512];

            match self.stream.read(&mut raw_buffer) {

                Err(error) => {
                    // Connection dropped out or something broke
                    // In the future, we use the customized NetherrackStream to see if we're in GAME mode, and if so, get the attached player and start saving their information and get rid of them
                    // For now, we just exit the loop
                    error!("Got an error! {}", error);

                    let _ = self.stream.shutdown(Shutdown::Both);
                    break; //Close the connection
                }
                Ok(count) => {
                    if count == 0 {
                        //Nothing in stream, let's sleep for a few milliseconds and try again
                        timeout_duration = timeout_duration + Duration::milliseconds(2);
                        ::std::thread::sleep_ms(2);
                    } else {

                        timeout_duration = Duration::zero();

                        // Now truncate the raw buffer - Don't worry, it will reallocate to 512 on the next networking loop
                        raw_buffer.truncate(count);

                        let mut backing: VecDeque<u8> = VecDeque::<u8>::with_capacity(count);

                        for b in raw_buffer {

                            backing.push_back(b);
                        }

                        let mut buffer = DequeBuffer::from(backing);

                        //drop(raw_buffer);

                        let length_result = buffer.read_unsigned_varint_32();
                        let id_result = buffer.read_unsigned_varint_32();

                        if length_result.is_err() || id_result.is_err() {
                            error!("Error while reading packet ID or length! Oh no, dropping connection");

                            debug!("Shutdown result: {:?}", self.stream.shutdown(Shutdown::Both));
                            break;
                        }

                        let packet_header = PacketHeader { length: length_result.unwrap(), id: id_result.unwrap() };

                        info!("Read {} bytes, length is {}, id is {}", count, packet_header.length, packet_header.id);

                        info!("Remaining buffer size is {}", buffer.remaining());

                        //TODO: Move to a MinecraftClientConnection, determine if the client is Forge or Vanilla, and set the GameState to HANDSHAKE

                        if packet_header.id == 0 {
                            if packet_header.length == 1 {

                                //This is a request packet
                                debug!("Received a Server Status Request packet");

                            } else {

                                //This is a handshake packet
                                debug!("Received a Handshake packet");

                                let protocol_result = buffer.read_unsigned_varint_32();

                                if protocol_result.is_err() {
                                    error!("Error reading protocol version");
                                    debug!("Shutdown result: {:?}", self.stream.shutdown(Shutdown::Both));
                                    break;
                                }

                                debug!("Protocol version {}", protocol_result.unwrap());

                            }
                        }

                        // This is a memory leak. We need to get the time of last packet and check to see if it's more than 20 seconds ago
                    }
                }

            }

        }

        info!("Connection closed");

    }

}<commit_msg>Add GameConnection.disconnect()<commit_after>//! Utilities to do with connections between a Minecraft or Forge client and Netherrack

extern crate chrono;
use self::chrono::duration::Duration;

use super::packet::PacketHeader;

use std::collections::VecDeque;

use std::net::{Shutdown, TcpStream};

use std::io::Read;

use super::deque_buffer::DequeBuffer;

/// An enum describing the current connection's state
pub enum ConnectionState {

    /// Connection is in handshake mode
    HANDSHAKE,

    /// Connection is in login mode
    LOGIN,

    /// Connection is in status mode
    STATUS,

    /// Connection is in play mode
    PLAY

}

/// A struct defining a game connection
pub struct GameConnection {

    /// The TCP stream bound to this GameConnection
    pub stream: TcpStream,

    /// The state of this GameConnection
    pub state: ConnectionState

}

impl GameConnection {

    /// Creates a new GameConnection
    pub fn new(stream: TcpStream) -> GameConnection {
        GameConnection {
            stream: stream,
            state: ConnectionState::HANDSHAKE
        }
    }

    pub fn disconnect(&mut self) {
        //TODO: Check to see if in ConnectionState::PLAY, otherwise
        let result = self.stream.shutdown(Shutdown::Both);

        if result.is_ok() == false {
            error!("Error disconnecting: {:?}", result);
        }

    }

    /// Starts listening on the connection
    pub fn start_listening(&mut self) {

        info!("Got a new client from {}! Oh my!", self.stream.peer_addr().unwrap());

        let mut timeout_duration = Duration::zero();

        loop {

            if timeout_duration.num_seconds() >= 10 {
                info!("Client timed out");
                self.disconnect();
                break;
            }

            let mut raw_buffer = vec![0u8; 512];

            match self.stream.read(&mut raw_buffer) {

                Err(error) => {
                    // Connection dropped out or something broke
                    // In the future, we use the customized NetherrackStream to see if we're in GAME mode, and if so, get the attached player and start saving their information and get rid of them
                    // For now, we just exit the loop
                    error!("Got an error! {}", error);

                    self.disconnect();
                    break;
                }
                Ok(count) => {
                    if count == 0 {
                        //Nothing in stream, let's sleep for a few milliseconds and try again
                        timeout_duration = timeout_duration + Duration::milliseconds(2);
                        ::std::thread::sleep_ms(2);
                    } else {

                        timeout_duration = Duration::zero();

                        // Now truncate the raw buffer - Don't worry, it will reallocate to 512 on the next networking loop
                        raw_buffer.truncate(count);

                        let mut backing: VecDeque<u8> = VecDeque::<u8>::with_capacity(count);

                        for b in raw_buffer {

                            backing.push_back(b);
                        }

                        let mut buffer = DequeBuffer::from(backing);

                        //drop(raw_buffer);

                        let length_result = buffer.read_unsigned_varint_32();
                        let id_result = buffer.read_unsigned_varint_32();

                        if length_result.is_err() || id_result.is_err() {
                            error!("Error while reading packet ID or length! Oh no, dropping connection");

                            self.disconnect();
                            break;
                        }

                        let packet_header = PacketHeader { length: length_result.unwrap(), id: id_result.unwrap() };

                        info!("Read {} bytes, length is {}, id is {}", count, packet_header.length, packet_header.id);

                        info!("Remaining buffer size is {}", buffer.remaining());

                        //TODO: Move to a MinecraftClientConnection, determine if the client is Forge or Vanilla, and set the GameState to HANDSHAKE

                        if packet_header.id == 0 {
                            if packet_header.length == 1 {

                                //This is a request packet
                                debug!("Received a Server Status Request packet");

                            } else {

                                //This is a handshake packet
                                debug!("Received a Handshake packet");

                                let protocol_result = buffer.read_unsigned_varint_32();

                                if protocol_result.is_err() {
                                    error!("Error reading protocol version");
                                    self.disconnect();
                                    break;
                                }

                                debug!("Protocol version {}", protocol_result.unwrap());

                            }
                        }

                        // This is a memory leak. We need to get the time of last packet and check to see if it's more than 20 seconds ago
                    }
                }

            }

        }

        info!("Connection closed");

    }

}<|endoftext|>