<commit_before>use super::{
    child_properties, function, general,
    general::{cfg_deprecated_string, version_condition_no_doc, version_condition_string},
    properties, signal, trait_impls,
};
use crate::{
    analysis::{self, ref_mode::RefMode, rust_type::RustType, special_functions::Type},
    case::CaseExt,
    env::Env,
    library::{self, Nullable},
    nameutil,
    traits::IntoString,
};
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::object::Info,
    generate_display_trait: bool,
) -> Result<()> {
    general::start_comments(w, &env.config)?;
    general::uses(w, env, &analysis.imports, analysis.version)?;

    general::define_object_type(
        w,
        env,
        &analysis.name,
        &analysis.c_type,
        analysis.c_class_type.as_deref(),
        &analysis.get_type,
        analysis.is_interface,
        &analysis.supertypes,
    )?;

    if need_generate_inherent(analysis) {
        writeln!(w)?;
        write!(w, "impl {} {{", analysis.name)?;
        for func_analysis in &analysis.constructors() {
            function::generate(
                w,
                env,
                func_analysis,
                Some(&analysis.specials),
                analysis.version,
                false,
                false,
                1,
            )?;
        }

        if !analysis.builder_properties.is_empty() {
            // generate builder method that returns the corresponding builder
            let builder_name = format!("{}Builder", analysis.name);
            writeln!(
                w,
                "
            // rustdoc-stripper-ignore-next
            /// Creates a new builder-style object to construct a [`{name}`]
            /// This method returns an instance of [`{builder_name}`] which can be used to create a [`{name}`].
            pub fn builder() -> {builder_name} {{
                {builder_name}::default()
            }}
        ",
                name = analysis.name,
                builder_name = builder_name
            )?;
        }

        if !need_generate_trait(analysis) {
            for func_analysis in &analysis.methods() {
                function::generate(
                    w,
                    env,
                    func_analysis,
                    Some(&analysis.specials),
                    analysis.version,
                    false,
                    false,
                    1,
                )?;
            }

            for property in &analysis.properties {
                properties::generate(w, env, property, false, false, 1)?;
            }

            for child_property in &analysis.child_properties {
                child_properties::generate(w, env, child_property, false, false, 1)?;
            }
        }

        for func_analysis in &analysis.functions() {
            function::generate(
                w,
                env,
                func_analysis,
                Some(&analysis.specials),
                analysis.version,
                false,
                false,
                1,
            )?;
        }

        if !need_generate_trait(analysis) {
            for signal_analysis in analysis
                .signals
                .iter()
                .chain(analysis.notify_signals.iter())
            {
                signal::generate(w, env, signal_analysis, false, false, 1)?;
            }
        }

        writeln!(w, "}}")?;

        general::declare_default_from_new(w, env, &analysis.name, &analysis.functions)?;
    }

    trait_impls::generate(
        w,
        env,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        if need_generate_trait(analysis) {
            Some(&analysis.trait_name)
        } else {
            None
        },
        analysis.version,
    )?;

    if !analysis.builder_properties.is_empty() {
        writeln!(w)?;
        generate_builder(w, env, analysis)?;
    }

    if analysis.concurrency != library::Concurrency::None {
        writeln!(w)?;
    }

    match analysis.concurrency {
        library::Concurrency::Send | library::Concurrency::SendSync => {
            writeln!(w, "unsafe impl Send for {} {{}}", analysis.name)?;
        }
        library::Concurrency::SendUnique => {
            if env.namespaces.is_glib_crate {
                writeln!(w, "unsafe impl ::SendUnique for {} {{", analysis.name)?;
            } else {
                writeln!(w, "unsafe impl glib::SendUnique for {} {{", analysis.name)?;
            }

            writeln!(w, "    fn is_unique(&self) -> bool {{")?;
            writeln!(w, "        self.ref_count() == 1")?;
            writeln!(w, "    }}")?;

            writeln!(w, "}}")?;
        }
        _ => (),
    }

    if let library::Concurrency::SendSync = analysis.concurrency {
        writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name)?;
    }

    if !analysis.final_type {
        writeln!(w)?;
        writeln!(
            w,
            "pub const NONE_{}: Option<&{}> = None;",
            analysis.name.to_snake().to_uppercase(),
            analysis.name
        )?;
    }

    if need_generate_trait(analysis) {
        writeln!(w)?;
        generate_trait(w, env, analysis)?;
    }

    if generate_display_trait && !analysis.specials.has_trait(Type::Display) {
        writeln!(w, "\nimpl fmt::Display for {} {{", analysis.name,)?;
        // Generate Display trait implementation.
        writeln!(
            w,
            "\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
             \t\tf.write_str(\"{}\")\n\
             \t}}\n\
             }}",
            analysis.name
        )?;
    }

    Ok(())
}

// TODO: instead create a Vec<> inside the Builder instead of Options.
fn generate_builder(w: &mut dyn Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    let mut methods = vec![];
    let mut properties = vec![];
    writeln!(w, "#[derive(Clone, Default)]")?;
    writeln!(
        w,
        "// rustdoc-stripper-ignore-next
        /// A builder for generating a [`{}`].",
        analysis.name,
    )?;
    writeln!(w, "pub struct {}Builder {{", analysis.name)?;
    for property in &analysis.builder_properties {
        match RustType::try_new(env, property.typ) {
            Ok(type_string) => {
                let type_string = match type_string.as_str() {
                    s if nameutil::is_gstring(s) => "String",
                    "Vec<GString>" | "Vec<glib::GString>" | "Vec<crate::GString>" => "Vec<String>",
                    typ => typ,
                };
                let direction = if property.is_get {
                    library::ParameterDirection::In
                } else {
                    library::ParameterDirection::Out
                };
                let mut param_type = RustType::builder(env, property.typ)
                    .direction(direction)
                    .ref_mode(property.set_in_ref_mode)
                    .try_build()
                    .into_string();
                let (param_type_override, bounds, conversion) = match &param_type[..] {
                    "&str" => (None, String::new(), ".to_string()"),
                    "&[&str]" => (Some("Vec<String>".to_string()), String::new(), ""),
                    _ if !property.bounds.is_empty() => {
                        let (bounds, _) = function::bounds(&property.bounds, &[], false, false);
                        let alias =
                            property
                                .bounds
                                .get_parameter_bound(&property.name)
                                .map(|bound| {
                                    bound.full_type_parameter_reference(
                                        RefMode::ByRef,
                                        Nullable(false),
                                    )
                                });
                        (alias, bounds, ".clone().upcast()")
                    }
                    typ if typ.starts_with('&') => (None, String::new(), ".clone()"),
                    _ => (None, String::new(), ""),
                };
                if let Some(param_type_override) = param_type_override {
                    param_type = param_type_override.to_string();
                }
                let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
                let version_condition_string =
                    version_condition_string(env, property.version, false, 1);
                let deprecated_string =
                    cfg_deprecated_string(env, property.deprecated_version, false, 1);
                if let Some(ref version_condition_string) = version_condition_string {
                    writeln!(w, "{}", version_condition_string)?;
                }
                if let Some(ref deprecated_string) = deprecated_string {
                    writeln!(w, "{}", deprecated_string)?;
                }
                writeln!(w, "    {}: Option<{}>,", name, type_string)?;
                let version_prefix = version_condition_string
                    .map(|version| format!("{}\n", version))
                    .unwrap_or_default();

                let deprecation_prefix = deprecated_string
                    .map(|version| format!("{}\n", version))
                    .unwrap_or_default();

                methods.push(format!(
                    "\n{version_prefix}{deprecation_prefix}    pub fn {name}{bounds}(mut self, {name}: {param_type}) -> Self {{
        self.{name} = Some({name}{conversion});
        self
    }}",
                    version_prefix = version_prefix,
                    deprecation_prefix = deprecation_prefix,
                    param_type = param_type,
                    name = name,
                    conversion = conversion,
                    bounds = bounds
                ));
                properties.push(property);
            }
            Err(_) => writeln!(w, "    //{}: /*Unknown type*/,", property.name)?,
        }
    }
    writeln!(
        w,
        "}}

impl {name}Builder {{
    // rustdoc-stripper-ignore-next
    /// Create a new [`{name}Builder`].
    pub fn new() -> Self {{
        Self::default()
    }}
",
        name = analysis.name
    )?;

    writeln!(
        w,
        "
    // rustdoc-stripper-ignore-next
    /// Build the [`{name}`].
    pub fn build(self) -> {name} {{
        let mut properties: Vec<(&str, &dyn ToValue)> = vec![];",
        name = analysis.name
    )?;
    for property in &properties {
        let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
        version_condition_no_doc(w, env, property.version, false, 2)?;
        writeln!(
            w,
            "\
            if let Some(ref {field}) = self.{field} {{
                properties.push((\"{name}\", {field}));
            }}",
            name = property.name,
            field = name
        )?;
    }
    let glib_crate_name = if env.namespaces.is_glib_crate {
        "crate"
    } else {
        "glib"
    };

    // The split allows us to not have clippy::let_and_return lint disabled
    if let Some(code) = analysis.builder_postprocess.as_ref() {
        writeln!(
            w,
            r#"        let ret = {}::Object::new::<{}>(&properties)
                .expect("Failed to create an instance of {}");"#,
            glib_crate_name, analysis.name, analysis.name,
        )?;
        writeln!(w, "        {{\n            {}\n        }}", code)?;
        writeln!(w, "    ret\n    }}")?;
    } else {
        writeln!(
            w,
            r#"        {}::Object::new::<{}>(&properties)
                .expect("Failed to create an instance of {}")"#,
            glib_crate_name, analysis.name, analysis.name,
        )?;
        writeln!(w, "\n    }}")?;
    }

    for method in methods {
        writeln!(w, "{}", method)?;
    }
    writeln!(w, "}}")
}

fn generate_trait(w: &mut dyn Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    write!(w, "pub trait {}: 'static {{", analysis.trait_name)?;

    for func_analysis in &analysis.methods() {
        function::generate(
            w,
            env,
            func_analysis,
            Some(&analysis.specials),
            analysis.version,
            true,
            true,
            1,
        )?;
    }
    for property in &analysis.properties {
        properties::generate(w, env, property, true, true, 1)?;
    }
    for child_property in &analysis.child_properties {
        child_properties::generate(w, env, child_property, true, true, 1)?;
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        signal::generate(w, env, signal_analysis, true, true, 1)?;
    }
    writeln!(w, "}}")?;

    writeln!(w)?;
    write!(
        w,
        "impl<O: IsA<{}>> {} for O {{",
        analysis.name, analysis.trait_name,
    )?;

    for func_analysis in &analysis.methods() {
        function::generate(
            w,
            env,
            func_analysis,
            Some(&analysis.specials),
            analysis.version,
            true,
            false,
            1,
        )?;
    }
    for property in &analysis.properties {
        properties::generate(w, env, property, true, false, 1)?;
    }
    for child_property in &analysis.child_properties {
        child_properties::generate(w, env, child_property, true, false, 1)?;
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        signal::generate(w, env, signal_analysis, true, false, 1)?;
    }
    writeln!(w, "}}")?;

    Ok(())
}

fn need_generate_inherent(analysis: &analysis::object::Info) -> bool {
    analysis.has_constructors
        || analysis.has_functions
        || !need_generate_trait(analysis)
        || !analysis.builder_properties.is_empty()
}

fn need_generate_trait(analysis: &analysis::object::Info) -> bool {
    analysis.generate_trait
}

pub fn generate_reexports(
    env: &Env,
    analysis: &analysis::object::Info,
    module_name: &str,
    contents: &mut Vec<String>,
    traits: &mut Vec<String>,
) {
    let mut cfgs: Vec<String> = Vec::new();
    if let Some(cfg) = general::cfg_condition_string(&analysis.cfg_condition, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::version_condition_string(env, analysis.version, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::cfg_deprecated_string(env, analysis.deprecated_version, false, 0) {
        cfgs.push(cfg);
    }

    contents.push("".to_owned());
    contents.extend_from_slice(&cfgs);
    contents.push(format!("mod {};", module_name));
    contents.extend_from_slice(&cfgs);

    let none_type = if !analysis.final_type {
        format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
    } else {
        String::new()
    };

    contents.push(format!(
        "pub use self::{}::{{{}{}}};",
        module_name, analysis.name, none_type
    ));
    if need_generate_trait(analysis) {
        for cfg in &cfgs {
            traits.push(format!("\t{}", cfg));
        }
        traits.push(format!(
            "\tpub use super::{}::{};",
            module_name, analysis.trait_name
        ));
    }

    if !analysis.builder_properties.is_empty() {
        contents.extend_from_slice(&cfgs);
        contents.push(format!(
            "pub use self::{}::{}Builder;",
            module_name, analysis.name
        ));
    }
}
<commit_msg>codgen: make the builder method doc slightly better formatted<commit_after>use super::{
    child_properties, function, general,
    general::{cfg_deprecated_string, version_condition_no_doc, version_condition_string},
    properties, signal, trait_impls,
};
use crate::{
    analysis::{self, ref_mode::RefMode, rust_type::RustType, special_functions::Type},
    case::CaseExt,
    env::Env,
    library::{self, Nullable},
    nameutil,
    traits::IntoString,
};
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::object::Info,
    generate_display_trait: bool,
) -> Result<()> {
    general::start_comments(w, &env.config)?;
    general::uses(w, env, &analysis.imports, analysis.version)?;

    general::define_object_type(
        w,
        env,
        &analysis.name,
        &analysis.c_type,
        analysis.c_class_type.as_deref(),
        &analysis.get_type,
        analysis.is_interface,
        &analysis.supertypes,
    )?;

    if need_generate_inherent(analysis) {
        writeln!(w)?;
        write!(w, "impl {} {{", analysis.name)?;
        for func_analysis in &analysis.constructors() {
            function::generate(
                w,
                env,
                func_analysis,
                Some(&analysis.specials),
                analysis.version,
                false,
                false,
                1,
            )?;
        }

        if !analysis.builder_properties.is_empty() {
            // generate builder method that returns the corresponding builder
            let builder_name = format!("{}Builder", analysis.name);
            writeln!(
                w,
                "
            // rustdoc-stripper-ignore-next
            /// Creates a new builder-style object to construct a [`{name}`].
            ///
            /// This method returns an instance of [`{builder_name}`] which can be used to create a [`{name}`].
            pub fn builder() -> {builder_name} {{
                {builder_name}::default()
            }}
        ",
                name = analysis.name,
                builder_name = builder_name
            )?;
        }

        if !need_generate_trait(analysis) {
            for func_analysis in &analysis.methods() {
                function::generate(
                    w,
                    env,
                    func_analysis,
                    Some(&analysis.specials),
                    analysis.version,
                    false,
                    false,
                    1,
                )?;
            }

            for property in &analysis.properties {
                properties::generate(w, env, property, false, false, 1)?;
            }

            for child_property in &analysis.child_properties {
                child_properties::generate(w, env, child_property, false, false, 1)?;
            }
        }

        for func_analysis in &analysis.functions() {
            function::generate(
                w,
                env,
                func_analysis,
                Some(&analysis.specials),
                analysis.version,
                false,
                false,
                1,
            )?;
        }

        if !need_generate_trait(analysis) {
            for signal_analysis in analysis
                .signals
                .iter()
                .chain(analysis.notify_signals.iter())
            {
                signal::generate(w, env, signal_analysis, false, false, 1)?;
            }
        }

        writeln!(w, "}}")?;

        general::declare_default_from_new(w, env, &analysis.name, &analysis.functions)?;
    }

    trait_impls::generate(
        w,
        env,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        if need_generate_trait(analysis) {
            Some(&analysis.trait_name)
        } else {
            None
        },
        analysis.version,
    )?;

    if !analysis.builder_properties.is_empty() {
        writeln!(w)?;
        generate_builder(w, env, analysis)?;
    }

    if analysis.concurrency != library::Concurrency::None {
        writeln!(w)?;
    }

    match analysis.concurrency {
        library::Concurrency::Send | library::Concurrency::SendSync => {
            writeln!(w, "unsafe impl Send for {} {{}}", analysis.name)?;
        }
        library::Concurrency::SendUnique => {
            if env.namespaces.is_glib_crate {
                writeln!(w, "unsafe impl ::SendUnique for {} {{", analysis.name)?;
            } else {
                writeln!(w, "unsafe impl glib::SendUnique for {} {{", analysis.name)?;
            }

            writeln!(w, "    fn is_unique(&self) -> bool {{")?;
            writeln!(w, "        self.ref_count() == 1")?;
            writeln!(w, "    }}")?;

            writeln!(w, "}}")?;
        }
        _ => (),
    }

    if let library::Concurrency::SendSync = analysis.concurrency {
        writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name)?;
    }

    if !analysis.final_type {
        writeln!(w)?;
        writeln!(
            w,
            "pub const NONE_{}: Option<&{}> = None;",
            analysis.name.to_snake().to_uppercase(),
            analysis.name
        )?;
    }

    if need_generate_trait(analysis) {
        writeln!(w)?;
        generate_trait(w, env, analysis)?;
    }

    if generate_display_trait && !analysis.specials.has_trait(Type::Display) {
        writeln!(w, "\nimpl fmt::Display for {} {{", analysis.name,)?;
        // Generate Display trait implementation.
        writeln!(
            w,
            "\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
             \t\tf.write_str(\"{}\")\n\
             \t}}\n\
             }}",
            analysis.name
        )?;
    }

    Ok(())
}

// TODO: instead create a Vec<> inside the Builder instead of Options.
fn generate_builder(w: &mut dyn Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    let mut methods = vec![];
    let mut properties = vec![];
    writeln!(w, "#[derive(Clone, Default)]")?;
    writeln!(
        w,
        "// rustdoc-stripper-ignore-next
        /// A builder for generating a [`{}`].",
        analysis.name,
    )?;
    writeln!(w, "pub struct {}Builder {{", analysis.name)?;
    for property in &analysis.builder_properties {
        match RustType::try_new(env, property.typ) {
            Ok(type_string) => {
                let type_string = match type_string.as_str() {
                    s if nameutil::is_gstring(s) => "String",
                    "Vec<GString>" | "Vec<glib::GString>" | "Vec<crate::GString>" => "Vec<String>",
                    typ => typ,
                };
                let direction = if property.is_get {
                    library::ParameterDirection::In
                } else {
                    library::ParameterDirection::Out
                };
                let mut param_type = RustType::builder(env, property.typ)
                    .direction(direction)
                    .ref_mode(property.set_in_ref_mode)
                    .try_build()
                    .into_string();
                let (param_type_override, bounds, conversion) = match &param_type[..] {
                    "&str" => (None, String::new(), ".to_string()"),
                    "&[&str]" => (Some("Vec<String>".to_string()), String::new(), ""),
                    _ if !property.bounds.is_empty() => {
                        let (bounds, _) = function::bounds(&property.bounds, &[], false, false);
                        let alias =
                            property
                                .bounds
                                .get_parameter_bound(&property.name)
                                .map(|bound| {
                                    bound.full_type_parameter_reference(
                                        RefMode::ByRef,
                                        Nullable(false),
                                    )
                                });
                        (alias, bounds, ".clone().upcast()")
                    }
                    typ if typ.starts_with('&') => (None, String::new(), ".clone()"),
                    _ => (None, String::new(), ""),
                };
                if let Some(param_type_override) = param_type_override {
                    param_type = param_type_override.to_string();
                }
                let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
                let version_condition_string =
                    version_condition_string(env, property.version, false, 1);
                let deprecated_string =
                    cfg_deprecated_string(env, property.deprecated_version, false, 1);
                if let Some(ref version_condition_string) = version_condition_string {
                    writeln!(w, "{}", version_condition_string)?;
                }
                if let Some(ref deprecated_string) = deprecated_string {
                    writeln!(w, "{}", deprecated_string)?;
                }
                writeln!(w, "    {}: Option<{}>,", name, type_string)?;
                let version_prefix = version_condition_string
                    .map(|version| format!("{}\n", version))
                    .unwrap_or_default();

                let deprecation_prefix = deprecated_string
                    .map(|version| format!("{}\n", version))
                    .unwrap_or_default();

                methods.push(format!(
                    "\n{version_prefix}{deprecation_prefix}    pub fn {name}{bounds}(mut self, {name}: {param_type}) -> Self {{
        self.{name} = Some({name}{conversion});
        self
    }}",
                    version_prefix = version_prefix,
                    deprecation_prefix = deprecation_prefix,
                    param_type = param_type,
                    name = name,
                    conversion = conversion,
                    bounds = bounds
                ));
                properties.push(property);
            }
            Err(_) => writeln!(w, "    //{}: /*Unknown type*/,", property.name)?,
        }
    }
    writeln!(
        w,
        "}}

impl {name}Builder {{
    // rustdoc-stripper-ignore-next
    /// Create a new [`{name}Builder`].
    pub fn new() -> Self {{
        Self::default()
    }}
",
        name = analysis.name
    )?;

    writeln!(
        w,
        "
    // rustdoc-stripper-ignore-next
    /// Build the [`{name}`].
    pub fn build(self) -> {name} {{
        let mut properties: Vec<(&str, &dyn ToValue)> = vec![];",
        name = analysis.name
    )?;
    for property in &properties {
        let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
        version_condition_no_doc(w, env, property.version, false, 2)?;
        writeln!(
            w,
            "\
            if let Some(ref {field}) = self.{field} {{
                properties.push((\"{name}\", {field}));
            }}",
            name = property.name,
            field = name
        )?;
    }
    let glib_crate_name = if env.namespaces.is_glib_crate {
        "crate"
    } else {
        "glib"
    };

    // The split allows us to not have clippy::let_and_return lint disabled
    if let Some(code) = analysis.builder_postprocess.as_ref() {
        writeln!(
            w,
            r#"        let ret = {}::Object::new::<{}>(&properties)
                .expect("Failed to create an instance of {}");"#,
            glib_crate_name, analysis.name, analysis.name,
        )?;
        writeln!(w, "        {{\n            {}\n        }}", code)?;
        writeln!(w, "    ret\n    }}")?;
    } else {
        writeln!(
            w,
            r#"        {}::Object::new::<{}>(&properties)
                .expect("Failed to create an instance of {}")"#,
            glib_crate_name, analysis.name, analysis.name,
        )?;
        writeln!(w, "\n    }}")?;
    }

    for method in methods {
        writeln!(w, "{}", method)?;
    }
    writeln!(w, "}}")
}

fn generate_trait(w: &mut dyn Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    write!(w, "pub trait {}: 'static {{", analysis.trait_name)?;

    for func_analysis in &analysis.methods() {
        function::generate(
            w,
            env,
            func_analysis,
            Some(&analysis.specials),
            analysis.version,
            true,
            true,
            1,
        )?;
    }
    for property in &analysis.properties {
        properties::generate(w, env, property, true, true, 1)?;
    }
    for child_property in &analysis.child_properties {
        child_properties::generate(w, env, child_property, true, true, 1)?;
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        signal::generate(w, env, signal_analysis, true, true, 1)?;
    }
    writeln!(w, "}}")?;

    writeln!(w)?;
    write!(
        w,
        "impl<O: IsA<{}>> {} for O {{",
        analysis.name, analysis.trait_name,
    )?;

    for func_analysis in &analysis.methods() {
        function::generate(
            w,
            env,
            func_analysis,
            Some(&analysis.specials),
            analysis.version,
            true,
            false,
            1,
        )?;
    }
    for property in &analysis.properties {
        properties::generate(w, env, property, true, false, 1)?;
    }
    for child_property in &analysis.child_properties {
        child_properties::generate(w, env, child_property, true, false, 1)?;
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        signal::generate(w, env, signal_analysis, true, false, 1)?;
    }
    writeln!(w, "}}")?;

    Ok(())
}

fn need_generate_inherent(analysis: &analysis::object::Info) -> bool {
    analysis.has_constructors
        || analysis.has_functions
        || !need_generate_trait(analysis)
        || !analysis.builder_properties.is_empty()
}

fn need_generate_trait(analysis: &analysis::object::Info) -> bool {
    analysis.generate_trait
}

pub fn generate_reexports(
    env: &Env,
    analysis: &analysis::object::Info,
    module_name: &str,
    contents: &mut Vec<String>,
    traits: &mut Vec<String>,
) {
    let mut cfgs: Vec<String> = Vec::new();
    if let Some(cfg) = general::cfg_condition_string(&analysis.cfg_condition, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::version_condition_string(env, analysis.version, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::cfg_deprecated_string(env, analysis.deprecated_version, false, 0) {
        cfgs.push(cfg);
    }

    contents.push("".to_owned());
    contents.extend_from_slice(&cfgs);
    contents.push(format!("mod {};", module_name));
    contents.extend_from_slice(&cfgs);

    let none_type = if !analysis.final_type {
        format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
    } else {
        String::new()
    };

    contents.push(format!(
        "pub use self::{}::{{{}{}}};",
        module_name, analysis.name, none_type
    ));
    if need_generate_trait(analysis) {
        for cfg in &cfgs {
            traits.push(format!("\t{}", cfg));
        }
        traits.push(format!(
            "\tpub use super::{}::{};",
            module_name, analysis.trait_name
        ));
    }

    if !analysis.builder_properties.is_empty() {
        contents.extend_from_slice(&cfgs);
        contents.push(format!(
            "pub use self::{}::{}Builder;",
            module_name, analysis.name
        ));
    }
}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use bit_vec::BitVec;
use std::io::{self, Cursor, Read, Write};

use table::{Table, decode_table, encode_table};
use amqp_error::{AMQPError, AMQPResult};
use framing::{FrameType, Frame, MethodFrame};
use protocol;

#[derive(Debug)]
pub struct ArgumentsReader<'data> {
    cursor: Cursor<&'data [u8]>,
    bits: BitVec,
    byte: u8,
    current_bit: u8
}

impl <'data> ArgumentsReader<'data> {
    pub fn new(data: &'data [u8]) -> Self {
        Self { cursor: Cursor::new(data), bits: BitVec::from_bytes(&[0]), byte: 0, current_bit: 0 }
    }

    pub fn read_octet(&mut self) -> AMQPResult<u8>  {
        self.cursor.read_u8().map_err(From::from)
    }

    pub fn read_long(&mut self) -> AMQPResult<u32>  {
        self.cursor.read_u32::<BigEndian>().map_err(From::from)
    }

    pub fn read_longlong(&mut self) -> AMQPResult<u64>  {
        self.cursor.read_u64::<BigEndian>().map_err(From::from)
    }

    pub fn read_short(&mut self) -> AMQPResult<u16>  {
        self.cursor.read_u16::<BigEndian>().map_err(From::from)
    }

    pub fn read_shortstr(&mut self) -> AMQPResult<String> {
        let size = self.read_octet()? as usize;
        let mut buffer: Vec<u8> = vec![0u8; size];
        self.cursor.read(&mut buffer[..])?;
        Ok(String::from_utf8_lossy(&buffer[..]).to_string())
    }

    pub fn read_longstr(&mut self) -> AMQPResult<String> {
        let size = self.read_long()? as usize;
        debug!("Reading str of len {}", size);
        let mut buffer: Vec<u8> = vec![0u8; size];
        self.cursor.read(&mut buffer[..])?;
        Ok(String::from_utf8_lossy(&buffer[..]).to_string())
    }

    pub fn read_table(&mut self) -> AMQPResult<Table> {
        decode_table(&mut self.cursor).map(|(table, table_size)| table)
    }

    pub fn read_timestamp(&mut self) -> AMQPResult<u64>  {
        self.read_longlong()
    }

    // TODO: Reset current_bit on all subsequent other type of data reads
    pub fn read_bit(&mut self) -> AMQPResult<bool> {
        if self.current_bit == 0 {
            self.byte = self.read_octet()?;
            self.bits = BitVec::from_bytes(&[self.byte]);
        }
        self.current_bit += 1;
        self.bits.get(8 - (self.current_bit - 1) as usize).ok_or(AMQPError::Protocol("Bitmap is not correct".to_owned()))
    }
}

#[derive(Debug)]
pub struct ArgumentsWriter {
    data: Vec<u8>,
    bits: BitVec,
    current_bit: u8
}

impl ArgumentsWriter {
    pub fn new() -> Self {
        Self { data: vec![], bits: BitVec::from_bytes(&[0]), current_bit: 0 }
    }

    pub fn write_octet(&mut self, data: &u8) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.data.write_u8(*data).map_err(From::from)
    }

    pub fn write_long(&mut self, data: &u32) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.data.write_u32::<BigEndian>(*data).map_err(From::from)
    }

    pub fn write_longlong(&mut self, data: &u64) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.data.write_u64::<BigEndian>(*data).map_err(From::from)
    }

    pub fn write_short(&mut self, data: &u16) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.data.write_u16::<BigEndian>(*data).map_err(From::from)
    }

    pub fn write_shortstr(&mut self, data: &String) -> AMQPResult<()> {
        self.flush_bits()?;
        self.data.write_u8(data.len() as u8)?;
        self.data.write_all(data.as_bytes())?;
        Ok(())
    }

    pub fn write_longstr(&mut self, data: &String) -> AMQPResult<()> {
        self.flush_bits()?;
        self.data.write_u32::<BigEndian>(data.len() as u32)?;
        self.data.write_all(data.as_bytes())?;
        Ok(())
    }

    // Always a last method, since it writes to the end
    pub fn write_table(&mut self, data: &Table) -> AMQPResult<()> {
        self.flush_bits()?;
        encode_table(&mut self.data,&data)
    }

    pub fn write_timestamp(&mut self, data: &u64) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.write_longlong(data)
    }

    // TODO: Flush bytes on all subsequent other type of data writes
    pub fn write_bit(&mut self, data: &bool) -> AMQPResult<()> {
        println!("Setting bit: {} on a position {}", data, self.current_bit);
        self.current_bit += 1;
        self.bits.set(7 - (self.current_bit - 1) as usize, *data);
        if self.current_bit == 7 {
            self.flush_bits();
        }
        Ok(())
    }

    pub fn flush_bits(&mut self) -> AMQPResult<()> {
        if self.current_bit > 0 {
            let res = self.data.write_all(&self.bits.to_bytes()).map_err(From::from);
            self.bits = BitVec::from_bytes(&[0]);
            self.current_bit = 0;
            res
        } else {
            Ok(())
        }
    }

    pub fn as_bytes(mut self) -> Vec<u8> {
        self.flush_bits();
        self.data
    }
}

macro_rules! map_type {
    (octet) => (u8);
    (long) => (u32);
    (longlong) => (u64);
    (short) => (u16);
    (shortstr) => (String);
    (longstr) => (String);
    (table) => (Table);
    (timestamp) => (u64);
    (bit) => (bool);
}

macro_rules! read_type {
    ($reader:expr, octet) => ($reader.read_octet());
    ($reader:expr, long) => ($reader.read_long());
    ($reader:expr, longlong) => ($reader.read_longlong());
    ($reader:expr, short) => ($reader.read_short());
    ($reader:expr, shortstr) => ($reader.read_shortstr());
    ($reader:expr, longstr) => ($reader.read_longstr());
    ($reader:expr, table) => ($reader.read_table());
    ($reader:expr, timestamp) => ($reader.read_timestamp());
    ($reader:expr, bit) => ($reader.read_bit());
}

macro_rules! write_type {
    ($writer:expr, octet, $data:expr) => ($writer.write_octet($data));
    ($writer:expr, long, $data:expr) => ($writer.write_long($data));
    ($writer:expr, longlong, $data:expr) => ($writer.write_longlong($data));
    ($writer:expr, short, $data:expr) => ($writer.write_short($data));
    ($writer:expr, shortstr, $data:expr) => ($writer.write_shortstr($data));
    ($writer:expr, longstr, $data:expr) => ($writer.write_longstr($data));
    ($writer:expr, table, $data:expr) => ($writer.write_table($data));
    ($writer:expr, timestamp, $data:expr) => ($writer.write_timestamp($data));
    ($writer:expr, bit, $data:expr) => ($writer.write_bit($data));
}

macro_rules! method_struct {
    ($method_name:ident, $method_str:expr, $method_id:expr, $class_id:expr, ) => (
        #[derive(Debug)]
        pub struct $method_name;
        impl protocol::Method for $method_name {
            fn decode(method_frame: MethodFrame) -> AMQPResult<Self> where Self: Sized {
                Ok($method_name)
            }

            fn encode(&self) -> AMQPResult<Vec<u8>> {
                Ok(vec![])
            }

            fn name(&self) -> &'static str {
                $method_str
            }

            fn id(&self) -> u16 {
                $method_id
            }

            fn class_id(&self) -> u16 {
                $class_id
            }
        }
    );
    ($method_name:ident, $method_str:expr, $method_id:expr, $class_id:expr, $($arg_name:ident => $ty:ident),+) => (
        #[derive(Debug)]
        pub struct $method_name {
            $(pub $arg_name: map_type!($ty),)*
        }

        impl protocol::Method for $method_name {
            fn decode(method_frame: MethodFrame) -> AMQPResult<Self> where Self: Sized {
                let mut reader = ArgumentsReader::new(&method_frame.arguments);
                Ok($method_name {
                    $($arg_name: read_type!(reader, $ty)?,)*
                })
            }

            fn encode(&self) -> AMQPResult<Vec<u8>> {
                let mut writer = ArgumentsWriter::new();
                $(write_type!(writer, $ty, &self.$arg_name)?;)*
                Ok(writer.as_bytes())
            }

            fn name(&self) -> &'static str {
                $method_str
            }

            fn id(&self) -> u16 {
                $method_id
            }

            fn class_id(&self) -> u16 {
                $class_id
            }
        }
    )
}

#[cfg(test)]
mod test {
    use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
    use bit_vec::BitVec;
    use std::io::{self, Cursor, Read, Write};

    use table::{Table, decode_table, encode_table};
    use amqp_error::{AMQPError, AMQPResult};
    use framing::{FrameType, Frame, MethodFrame};
    use protocol;
    use super::*;

    method_struct!(Foo, "test.foo", 1, 2, a => octet, b => shortstr, c => longstr, d => bit, e => bit, f => long);
    method_struct!(FooNoFields, "test.foo_no_fields", 1, 2, );

    #[test]
    fn test_foo(){
        use protocol::Method;
        let f = Foo { a: 1, b: "test".to_string(), c: "bar".to_string(), d: false, e: true, f: 0xDEADBEEF };
        assert_eq!(f.encode().unwrap(), vec![
            1, // 1
            4, // "test".len()
            116, 101, 115, 116, // "test"
            0, 0, 0, 3, // "bar".len()
            98, 97, 114, // "bar"
            2, // false, true => 0b00000010
            0xDE, 0xAD, 0xBE, 0xEF, // 0xDEADBEEF
        ]);
    }
}
<commit_msg>Fix reading bit map.<commit_after>use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use bit_vec::BitVec;
use std::io::{self, Cursor, Read, Write};

use table::{Table, decode_table, encode_table};
use amqp_error::{AMQPError, AMQPResult};
use framing::{FrameType, Frame, MethodFrame};
use protocol;

#[derive(Debug)]
pub struct ArgumentsReader<'data> {
    cursor: Cursor<&'data [u8]>,
    bits: BitVec,
    byte: u8,
    current_bit: u8
}

impl <'data> ArgumentsReader<'data> {
    pub fn new(data: &'data [u8]) -> Self {
        Self { cursor: Cursor::new(data), bits: BitVec::from_bytes(&[0]), byte: 0, current_bit: 0 }
    }

    pub fn read_octet(&mut self) -> AMQPResult<u8>  {
        self.cursor.read_u8().map_err(From::from)
    }

    pub fn read_long(&mut self) -> AMQPResult<u32>  {
        self.cursor.read_u32::<BigEndian>().map_err(From::from)
    }

    pub fn read_longlong(&mut self) -> AMQPResult<u64>  {
        self.cursor.read_u64::<BigEndian>().map_err(From::from)
    }

    pub fn read_short(&mut self) -> AMQPResult<u16>  {
        self.cursor.read_u16::<BigEndian>().map_err(From::from)
    }

    pub fn read_shortstr(&mut self) -> AMQPResult<String> {
        let size = self.read_octet()? as usize;
        let mut buffer: Vec<u8> = vec![0u8; size];
        self.cursor.read(&mut buffer[..])?;
        Ok(String::from_utf8_lossy(&buffer[..]).to_string())
    }

    pub fn read_longstr(&mut self) -> AMQPResult<String> {
        let size = self.read_long()? as usize;
        let mut buffer: Vec<u8> = vec![0u8; size];
        self.cursor.read(&mut buffer[..])?;
        Ok(String::from_utf8_lossy(&buffer[..]).to_string())
    }

    pub fn read_table(&mut self) -> AMQPResult<Table> {
        decode_table(&mut self.cursor).map(|(table, table_size)| table)
    }

    pub fn read_timestamp(&mut self) -> AMQPResult<u64>  {
        self.read_longlong()
    }

    // TODO: Reset current_bit on all subsequent other type of data reads
    pub fn read_bit(&mut self) -> AMQPResult<bool> {
        if self.current_bit == 0 {
            self.byte = self.read_octet()?;
            self.bits = BitVec::from_bytes(&[self.byte]);
        }
        self.current_bit += 1;
        self.bits.get(7 - (self.current_bit - 1) as usize).ok_or(AMQPError::Protocol("Bitmap is not correct".to_owned()))
    }
}

#[derive(Debug)]
pub struct ArgumentsWriter {
    data: Vec<u8>,
    bits: BitVec,
    current_bit: u8
}

impl ArgumentsWriter {
    pub fn new() -> Self {
        Self { data: vec![], bits: BitVec::from_bytes(&[0]), current_bit: 0 }
    }

    pub fn write_octet(&mut self, data: &u8) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.data.write_u8(*data).map_err(From::from)
    }

    pub fn write_long(&mut self, data: &u32) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.data.write_u32::<BigEndian>(*data).map_err(From::from)
    }

    pub fn write_longlong(&mut self, data: &u64) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.data.write_u64::<BigEndian>(*data).map_err(From::from)
    }

    pub fn write_short(&mut self, data: &u16) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.data.write_u16::<BigEndian>(*data).map_err(From::from)
    }

    pub fn write_shortstr(&mut self, data: &String) -> AMQPResult<()> {
        self.flush_bits()?;
        self.data.write_u8(data.len() as u8)?;
        self.data.write_all(data.as_bytes())?;
        Ok(())
    }

    pub fn write_longstr(&mut self, data: &String) -> AMQPResult<()> {
        self.flush_bits()?;
        self.data.write_u32::<BigEndian>(data.len() as u32)?;
        self.data.write_all(data.as_bytes())?;
        Ok(())
    }

    // Always a last method, since it writes to the end
    pub fn write_table(&mut self, data: &Table) -> AMQPResult<()> {
        self.flush_bits()?;
        encode_table(&mut self.data,&data)
    }

    pub fn write_timestamp(&mut self, data: &u64) -> AMQPResult<()>  {
        self.flush_bits()?;
        self.write_longlong(data)
    }

    // TODO: Flush bytes on all subsequent other type of data writes
    pub fn write_bit(&mut self, data: &bool) -> AMQPResult<()> {
        println!("Setting bit: {} on a position {}", data, self.current_bit);
        self.current_bit += 1;
        self.bits.set(7 - (self.current_bit - 1) as usize, *data);
        if self.current_bit == 7 {
            self.flush_bits();
        }
        Ok(())
    }

    pub fn flush_bits(&mut self) -> AMQPResult<()> {
        if self.current_bit > 0 {
            let res = self.data.write_all(&self.bits.to_bytes()).map_err(From::from);
            self.bits = BitVec::from_bytes(&[0]);
            self.current_bit = 0;
            res
        } else {
            Ok(())
        }
    }

    pub fn as_bytes(mut self) -> Vec<u8> {
        self.flush_bits();
        self.data
    }
}

macro_rules! map_type {
    (octet) => (u8);
    (long) => (u32);
    (longlong) => (u64);
    (short) => (u16);
    (shortstr) => (String);
    (longstr) => (String);
    (table) => (Table);
    (timestamp) => (u64);
    (bit) => (bool);
}

macro_rules! read_type {
    ($reader:expr, octet) => ($reader.read_octet());
    ($reader:expr, long) => ($reader.read_long());
    ($reader:expr, longlong) => ($reader.read_longlong());
    ($reader:expr, short) => ($reader.read_short());
    ($reader:expr, shortstr) => ($reader.read_shortstr());
    ($reader:expr, longstr) => ($reader.read_longstr());
    ($reader:expr, table) => ($reader.read_table());
    ($reader:expr, timestamp) => ($reader.read_timestamp());
    ($reader:expr, bit) => ($reader.read_bit());
}

macro_rules! write_type {
    ($writer:expr, octet, $data:expr) => ($writer.write_octet($data));
    ($writer:expr, long, $data:expr) => ($writer.write_long($data));
    ($writer:expr, longlong, $data:expr) => ($writer.write_longlong($data));
    ($writer:expr, short, $data:expr) => ($writer.write_short($data));
    ($writer:expr, shortstr, $data:expr) => ($writer.write_shortstr($data));
    ($writer:expr, longstr, $data:expr) => ($writer.write_longstr($data));
    ($writer:expr, table, $data:expr) => ($writer.write_table($data));
    ($writer:expr, timestamp, $data:expr) => ($writer.write_timestamp($data));
    ($writer:expr, bit, $data:expr) => ($writer.write_bit($data));
}

macro_rules! method_struct {
    ($method_name:ident, $method_str:expr, $method_id:expr, $class_id:expr, ) => (
        #[derive(Debug)]
        pub struct $method_name;
        impl protocol::Method for $method_name {
            fn decode(method_frame: MethodFrame) -> AMQPResult<Self> where Self: Sized {
                Ok($method_name)
            }

            fn encode(&self) -> AMQPResult<Vec<u8>> {
                Ok(vec![])
            }

            fn name(&self) -> &'static str {
                $method_str
            }

            fn id(&self) -> u16 {
                $method_id
            }

            fn class_id(&self) -> u16 {
                $class_id
            }
        }
    );
    ($method_name:ident, $method_str:expr, $method_id:expr, $class_id:expr, $($arg_name:ident => $ty:ident),+) => (
        #[derive(Debug)]
        pub struct $method_name {
            $(pub $arg_name: map_type!($ty),)*
        }

        impl protocol::Method for $method_name {
            fn decode(method_frame: MethodFrame) -> AMQPResult<Self> where Self: Sized {
                let mut reader = ArgumentsReader::new(&method_frame.arguments);
                Ok($method_name {
                    $($arg_name: read_type!(reader, $ty)?,)*
                })
            }

            fn encode(&self) -> AMQPResult<Vec<u8>> {
                let mut writer = ArgumentsWriter::new();
                $(write_type!(writer, $ty, &self.$arg_name)?;)*
                Ok(writer.as_bytes())
            }

            fn name(&self) -> &'static str {
                $method_str
            }

            fn id(&self) -> u16 {
                $method_id
            }

            fn class_id(&self) -> u16 {
                $class_id
            }
        }
    )
}

#[cfg(test)]
mod test {
    use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
    use bit_vec::BitVec;
    use std::io::{self, Cursor, Read, Write};

    use table::{Table, decode_table, encode_table};
    use amqp_error::{AMQPError, AMQPResult};
    use framing::{FrameType, Frame, MethodFrame};
    use protocol;
    use super::*;

    method_struct!(Foo, "test.foo", 1, 2, a => octet, b => shortstr, c => longstr, d => bit, e => bit, f => long);
    method_struct!(FooNoFields, "test.foo_no_fields", 1, 2, );

    #[test]
    fn test_foo(){
        use protocol::Method;
        let f = Foo { a: 1, b: "test".to_string(), c: "bar".to_string(), d: false, e: true, f: 0xDEADBEEF };
        assert_eq!(f.encode().unwrap(), vec![
            1, // 1
            4, // "test".len()
            116, 101, 115, 116, // "test"
            0, 0, 0, 3, // "bar".len()
            98, 97, 114, // "bar"
            2, // false, true => 0b00000010
            0xDE, 0xAD, 0xBE, 0xEF, // 0xDEADBEEF
        ]);
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route-recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::{Any, AnyRefExt};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + Send + Share>>>
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler + Send + Share>>, String>
    {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler + Send + Share>);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box e as Box<Show>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a mut Request) -> &'a router::Params {
    req.extensions().find(&"router.params")
        .and_then(|a| a.as_ref::<router::Params>())
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a mut Request {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use super::*;

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "1, Get".to_str());
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "10, Post".to_str());
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"]);
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<commit_msg>Update travis config<commit_after>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route-recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::{Any, AnyRefExt};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + Send + Share>>>
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler + Send + Share>>, String>
    {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler + Send + Share>);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box e as Box<Show>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a mut Request) -> &'a router::Params {
    req.extensions().find(&"router.params")
        .and_then(|a| a.as_ref::<router::Params>())
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a mut Request {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use super::*;

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "1, Get".to_string());
    }

    #[test]
    fn basic_post() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_string().unwrap(), "10, Post".to_string());
    }

    #[test]
    fn nonexistent_route() {
        let router = test_router();
        let mut req = RequestSentinel::new(conduit::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"]);
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::DefaultHasher;
use std::hash::{BuildHasherDefault, Hash};

use utils::HashIter;

/// Abstract, but safe counter.
pub trait Counter: Copy + Ord + Sized {
    /// Add self to another counter.
    ///
    /// Returns `Some(Self)` when the addition was successfull (i.e. no overflow occured) and
    /// `None` in case of an error.
    fn checked_add(self, other: Self) -> Option<Self>;

    /// Return a counter representing zero.
    fn zero() -> Self;

    /// Return a counter representing one.
    fn one() -> Self;
}

macro_rules! impl_counter {
    ($t:ty) => {
        impl Counter for $t {
            #[inline]
            fn checked_add(self, other: Self) -> Option<Self> {
                self.checked_add(other)
            }

            #[inline]
            fn zero() -> Self {
                0
            }

            #[inline]
            fn one() -> Self {
                1
            }
        }
    }
}

impl_counter!(usize);
impl_counter!(u64);
impl_counter!(u32);
impl_counter!(u16);
impl_counter!(u8);

/// Simple implementation of a
/// [Count-min sketch](https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch)
///
/// The type parameter `C` sets the type of the counter in the internal table and can be used to
/// reduce memory consumption when low counts are expected.
pub struct CountMinSketch<C = usize>
where
    C: Counter,
{
    table: Vec<C>,
    w: usize,
    d: usize,
}

impl<C> CountMinSketch<C>
where
    C: Counter,
{
    /// Create new CountMinSketch based on table size.
    ///
    /// - `w` sets the number of columns
    /// - `d` sets the number of rows
    pub fn with_params(w: usize, d: usize) -> CountMinSketch<C> {
        let table = vec![C::zero(); w.checked_mul(d).unwrap()];
        CountMinSketch {
            table: table,
            w: w,
            d: d,
        }
    }

    /// Add one to the counter of the given element.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        self.add_n(&obj, C::one())
    }

    /// Add `n` to the counter of the given element.
    pub fn add_n<T>(&mut self, obj: &T, n: C)
    where
        T: Hash,
    {
        let bh = BuildHasherDefault::<DefaultHasher>::default();
        for (i, pos) in HashIter::new(self.w, self.d, obj, bh).enumerate() {
            let x = i * self.w + pos;
            self.table[x] = self.table[x].checked_add(n).unwrap();
        }
    }

    /// Runs a point query, i.e. a query for the count of a single object.
    pub fn query_point<T>(&self, obj: &T) -> C
    where
        T: Hash,
    {
        let bh = BuildHasherDefault::<DefaultHasher>::default();
        HashIter::new(self.w, self.d, obj, bh)
            .enumerate()
            .map(|(i, pos)| i * self.w + pos)
            .map(|x| self.table[x])
            .min()
            .unwrap()
    }
}

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

    #[test]
    fn empty() {
        let cms = CountMinSketch::<usize>::with_params(10, 10);
        assert_eq!(cms.query_point(&1), 0);
    }

    #[test]
    fn add_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        assert_eq!(cms.query_point(&1), 1);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&2);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 1);
        assert_eq!(cms.query_point(&3), 0);
    }
}
<commit_msg>countminsketch: impl getter<commit_after>use std::collections::hash_map::DefaultHasher;
use std::hash::{BuildHasherDefault, Hash};

use utils::HashIter;

/// Abstract, but safe counter.
pub trait Counter: Copy + Ord + Sized {
    /// Add self to another counter.
    ///
    /// Returns `Some(Self)` when the addition was successfull (i.e. no overflow occured) and
    /// `None` in case of an error.
    fn checked_add(self, other: Self) -> Option<Self>;

    /// Return a counter representing zero.
    fn zero() -> Self;

    /// Return a counter representing one.
    fn one() -> Self;
}

macro_rules! impl_counter {
    ($t:ty) => {
        impl Counter for $t {
            #[inline]
            fn checked_add(self, other: Self) -> Option<Self> {
                self.checked_add(other)
            }

            #[inline]
            fn zero() -> Self {
                0
            }

            #[inline]
            fn one() -> Self {
                1
            }
        }
    }
}

impl_counter!(usize);
impl_counter!(u64);
impl_counter!(u32);
impl_counter!(u16);
impl_counter!(u8);

/// Simple implementation of a
/// [Count-min sketch](https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch)
///
/// The type parameter `C` sets the type of the counter in the internal table and can be used to
/// reduce memory consumption when low counts are expected.
pub struct CountMinSketch<C = usize>
where
    C: Counter,
{
    table: Vec<C>,
    w: usize,
    d: usize,
}

impl<C> CountMinSketch<C>
where
    C: Counter,
{
    /// Create new CountMinSketch based on table size.
    ///
    /// - `w` sets the number of columns
    /// - `d` sets the number of rows
    pub fn with_params(w: usize, d: usize) -> CountMinSketch<C> {
        let table = vec![C::zero(); w.checked_mul(d).unwrap()];
        CountMinSketch {
            table: table,
            w: w,
            d: d,
        }
    }

    /// Get number of columns of internal counter table.
    pub fn w(&self) -> usize {
        self.w
    }

    /// Get number of rows of internal counter table.
    pub fn d(&self) -> usize {
        self.d
    }

    /// Add one to the counter of the given element.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        self.add_n(&obj, C::one())
    }

    /// Add `n` to the counter of the given element.
    pub fn add_n<T>(&mut self, obj: &T, n: C)
    where
        T: Hash,
    {
        let bh = BuildHasherDefault::<DefaultHasher>::default();
        for (i, pos) in HashIter::new(self.w, self.d, obj, bh).enumerate() {
            let x = i * self.w + pos;
            self.table[x] = self.table[x].checked_add(n).unwrap();
        }
    }

    /// Runs a point query, i.e. a query for the count of a single object.
    pub fn query_point<T>(&self, obj: &T) -> C
    where
        T: Hash,
    {
        let bh = BuildHasherDefault::<DefaultHasher>::default();
        HashIter::new(self.w, self.d, obj, bh)
            .enumerate()
            .map(|(i, pos)| i * self.w + pos)
            .map(|x| self.table[x])
            .min()
            .unwrap()
    }
}

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

    #[test]
    fn getter() {
        let cms = CountMinSketch::<usize>::with_params(10, 20);
        assert_eq!(cms.w(), 10);
        assert_eq!(cms.d(), 20);
    }

    #[test]
    fn empty() {
        let cms = CountMinSketch::<usize>::with_params(10, 10);
        assert_eq!(cms.query_point(&1), 0);
    }

    #[test]
    fn add_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        assert_eq!(cms.query_point(&1), 1);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&2);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 1);
        assert_eq!(cms.query_point(&3), 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 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.

#![no_main]

use std::io::Cursor;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::mem::size_of;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;

use base::Event;
use cros_fuzz::fuzz_target;
use devices::virtio::base_features;
use devices::virtio::BlockAsync;
use devices::virtio::Interrupt;
use devices::virtio::Queue;
use devices::virtio::VirtioDevice;
use devices::IrqLevelEvent;
use hypervisor::ProtectionType;
use vm_memory::GuestAddress;
use vm_memory::GuestMemory;

const MEM_SIZE: u64 = 256 * 1024 * 1024;
const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
const QUEUE_SIZE: u16 = 16; // Max entries in the queue.
const CMD_SIZE: usize = 16; // Bytes in the command.

fuzz_target!(|bytes| {
    let size_u64 = size_of::<u64>();
    let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap();

    // The fuzz data is interpreted as:
    // starting index 8 bytes
    // command location 8 bytes
    // command 16 bytes
    // descriptors circular buffer 16 bytes * 3
    if bytes.len() < 4 * size_u64 {
        // Need an index to start.
        return;
    }

    let mut data_image = Cursor::new(bytes);

    let first_index = read_u64(&mut data_image);
    if first_index > MEM_SIZE / DESC_SIZE {
        return;
    }
    let first_offset = first_index * DESC_SIZE;
    if first_offset as usize + size_u64 > bytes.len() {
        return;
    }

    let command_addr = read_u64(&mut data_image);
    if command_addr > MEM_SIZE - CMD_SIZE as u64 {
        return;
    }
    if mem
        .write_all_at_addr(
            &bytes[2 * size_u64..(2 * size_u64) + CMD_SIZE],
            GuestAddress(command_addr as u64),
        )
        .is_err()
    {
        return;
    }

    data_image.seek(SeekFrom::Start(first_offset)).unwrap();
    let desc_table = read_u64(&mut data_image);

    if mem
        .write_all_at_addr(&bytes[32..], GuestAddress(desc_table as u64))
        .is_err()
    {
        return;
    }

    let mut q = Queue::new(QUEUE_SIZE);
    q.set_ready(true);
    q.set_size(QUEUE_SIZE / 2);
    q.max_size = QUEUE_SIZE;

    let queue_evts: Vec<Event> = vec![Event::new().unwrap()];
    let queue_evt = queue_evts[0].try_clone().unwrap();

    let features = base_features(ProtectionType::Unprotected);

    let disk_file = tempfile::tempfile().unwrap();
    let mut block =
        BlockAsync::new(features, Box::new(disk_file), false, true, 512, None, None).unwrap();

    block.activate(
        mem,
        Interrupt::new(
            Arc::new(AtomicUsize::new(0)),
            IrqLevelEvent::new().unwrap(),
            None,   // msix_config
            0xFFFF, // VIRTIO_MSI_NO_VECTOR
        ),
        vec![q],
        queue_evts,
    );

    queue_evt.write(77).unwrap(); // Rings the doorbell, any byte will do.
});

fn read_u64<T: Read>(readable: &mut T) -> u64 {
    let mut buf = [0u8; size_of::<u64>()];
    readable.read_exact(&mut buf[..]).unwrap();
    u64::from_le_bytes(buf)
}
<commit_msg>crosvm-fuzz: fix breakage caused by Interrupt:new<commit_after>// Copyright 2018 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.

#![no_main]

use std::io::Cursor;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::mem::size_of;

use base::Event;
use cros_fuzz::fuzz_target;
use devices::virtio::base_features;
use devices::virtio::BlockAsync;
use devices::virtio::Interrupt;
use devices::virtio::Queue;
use devices::virtio::VirtioDevice;
use devices::IrqLevelEvent;
use hypervisor::ProtectionType;
use vm_memory::GuestAddress;
use vm_memory::GuestMemory;

const MEM_SIZE: u64 = 256 * 1024 * 1024;
const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
const QUEUE_SIZE: u16 = 16; // Max entries in the queue.
const CMD_SIZE: usize = 16; // Bytes in the command.

fuzz_target!(|bytes| {
    let size_u64 = size_of::<u64>();
    let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap();

    // The fuzz data is interpreted as:
    // starting index 8 bytes
    // command location 8 bytes
    // command 16 bytes
    // descriptors circular buffer 16 bytes * 3
    if bytes.len() < 4 * size_u64 {
        // Need an index to start.
        return;
    }

    let mut data_image = Cursor::new(bytes);

    let first_index = read_u64(&mut data_image);
    if first_index > MEM_SIZE / DESC_SIZE {
        return;
    }
    let first_offset = first_index * DESC_SIZE;
    if first_offset as usize + size_u64 > bytes.len() {
        return;
    }

    let command_addr = read_u64(&mut data_image);
    if command_addr > MEM_SIZE - CMD_SIZE as u64 {
        return;
    }
    if mem
        .write_all_at_addr(
            &bytes[2 * size_u64..(2 * size_u64) + CMD_SIZE],
            GuestAddress(command_addr as u64),
        )
        .is_err()
    {
        return;
    }

    data_image.seek(SeekFrom::Start(first_offset)).unwrap();
    let desc_table = read_u64(&mut data_image);

    if mem
        .write_all_at_addr(&bytes[32..], GuestAddress(desc_table as u64))
        .is_err()
    {
        return;
    }

    let mut q = Queue::new(QUEUE_SIZE);
    q.set_ready(true);
    q.set_size(QUEUE_SIZE / 2);
    q.max_size = QUEUE_SIZE;

    let queue_evts: Vec<Event> = vec![Event::new().unwrap()];
    let queue_evt = queue_evts[0].try_clone().unwrap();

    let features = base_features(ProtectionType::Unprotected);

    let disk_file = tempfile::tempfile().unwrap();
    let mut block =
        BlockAsync::new(features, Box::new(disk_file), false, true, 512, None, None).unwrap();

    block.activate(
        mem,
        Interrupt::new(
            IrqLevelEvent::new().unwrap(),
            None,   // msix_config
            0xFFFF, // VIRTIO_MSI_NO_VECTOR
        ),
        vec![q],
        queue_evts,
    );

    queue_evt.write(77).unwrap(); // Rings the doorbell, any byte will do.
});

fn read_u64<T: Read>(readable: &mut T) -> u64 {
    let mut buf = [0u8; size_of::<u64>()];
    readable.read_exact(&mut buf[..]).unwrap();
    u64::from_le_bytes(buf)
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Binary_digits
use std::vec::Vec;
use std::string::String;

#[cfg(not(test))]
fn main() {
    let bins=binaries(16u);
    for s in bins.iter() {
        println!("{}", s);
    }
}

fn binaries(n:uint) -> Vec<String> {
    let mut bins = Vec::<String>::with_capacity(n);
    for i in range(0u, n) {
        bins.push(format!("{:t}", i));
    }
    bins
}

#[test]
fn test_digits() {
    let bins=binaries(16u);
    assert_eq!(bins, vec![String::from_str("0")
                        ,String::from_str("1")
                        ,String::from_str("10")
                        ,String::from_str("11")
                        ,String::from_str("100")
                        ,String::from_str("101")
                        ,String::from_str("110")
                        ,String::from_str("111")
                        ,String::from_str("1000")
                        ,String::from_str("1001")
                        ,String::from_str("1010")
                        ,String::from_str("1011")
                        ,String::from_str("1100")
                        ,String::from_str("1101")
                        ,String::from_str("1110")
                        ,String::from_str("1111")]);
}<commit_msg>Make Binary Digits' solution more functional.<commit_after>// Implements http://rosettacode.org/wiki/Binary_digits
use std::vec::Vec;
use std::string::String;

#[cfg(not(test))]
fn main() {
    let bins=binaries(16u);
    for s in bins.iter() {
        println!("{}", s);
    }
}

fn binaries(n:uint) -> Vec<String> {
    range(0, n).map(|i| format!("{:t}", i)).collect()
}

#[test]
fn test_digits() {
    let bins=binaries(16u);
    assert_eq!(bins, vec![String::from_str("0")
                        ,String::from_str("1")
                        ,String::from_str("10")
                        ,String::from_str("11")
                        ,String::from_str("100")
                        ,String::from_str("101")
                        ,String::from_str("110")
                        ,String::from_str("111")
                        ,String::from_str("1000")
                        ,String::from_str("1001")
                        ,String::from_str("1010")
                        ,String::from_str("1011")
                        ,String::from_str("1100")
                        ,String::from_str("1101")
                        ,String::from_str("1110")
                        ,String::from_str("1111")]);
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

//! Documentation generation for rustbuild.
//!
//! This module implements generation for all bits and pieces of documentation
//! for the Rust project. This notably includes suites like the rust book, the
//! nomicon, standalone documentation, etc.
//!
//! Everything here is basically just a shim around calling either `rustbook` or
//! `rustdoc`.

use std::fs::{self, File};
use std::io::prelude::*;
use std::process::Command;

use {Build, Compiler, Mode};
use util::{up_to_date, cp_r};

/// Invoke `rustbook` as compiled in `stage` for `target` for the doc book
/// `name` into the `out` path.
///
/// This will not actually generate any documentation if the documentation has
/// already been generated.
pub fn rustbook(build: &Build, target: &str, name: &str) {
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));

    let out = out.join(name);
    let compiler = Compiler::new(0, &build.config.build);
    let src = build.src.join("src/doc").join(name);
    let index = out.join("index.html");
    let rustbook = build.tool(&compiler, "rustbook");
    if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
        return
    }
    println!("Rustbook ({}) - {}", target, name);
    let _ = fs::remove_dir_all(&out);
    build.run(build.tool_cmd(&compiler, "rustbook")
                   .arg("build")
                   .arg(&src)
                   .arg(out));
}

/// Generates all standalone documentation as compiled by the rustdoc in `stage`
/// for the `target` into `out`.
///
/// This will list all of `src/doc` looking for markdown files and appropriately
/// perform transformations like substituting `VERSION`, `SHORT_HASH`, and
/// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
///
/// In the end, this is just a glorified wrapper around rustdoc!
pub fn standalone(build: &Build, target: &str) {
    println!("Documenting standalone ({})", target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));

    let compiler = Compiler::new(0, &build.config.build);

    let favicon = build.src.join("src/doc/favicon.inc");
    let footer = build.src.join("src/doc/footer.inc");
    let full_toc = build.src.join("src/doc/full-toc.inc");
    t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));

    let version_input = build.src.join("src/doc/version_info.html.template");
    let version_info = out.join("version_info.html");

    if !up_to_date(&version_input, &version_info) {
        let mut info = String::new();
        t!(t!(File::open(&version_input)).read_to_string(&mut info));
        let blank = String::new();
        let short = build.short_ver_hash.as_ref().unwrap_or(&blank);
        let hash = build.ver_hash.as_ref().unwrap_or(&blank);
        let info = info.replace("VERSION", &build.release)
                       .replace("SHORT_HASH", short)
                       .replace("STAMP", hash);
        t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
    }

    for file in t!(fs::read_dir(build.src.join("src/doc"))) {
        let file = t!(file);
        let path = file.path();
        let filename = path.file_name().unwrap().to_str().unwrap();
        if !filename.ends_with(".md") || filename == "README.md" {
            continue
        }

        let html = out.join(filename).with_extension("html");
        let rustdoc = build.rustdoc(&compiler);
        if up_to_date(&path, &html) &&
           up_to_date(&footer, &html) &&
           up_to_date(&favicon, &html) &&
           up_to_date(&full_toc, &html) &&
           up_to_date(&version_info, &html) &&
           up_to_date(&rustdoc, &html) {
            continue
        }

        let mut cmd = Command::new(&rustdoc);
        build.add_rustc_lib_path(&compiler, &mut cmd);
        cmd.arg("--html-after-content").arg(&footer)
           .arg("--html-before-content").arg(&version_info)
           .arg("--html-in-header").arg(&favicon)
           .arg("--markdown-playground-url")
           .arg("https://play.rust-lang.org/")
           .arg("-o").arg(&out)
           .arg(&path);

        if filename == "reference.md" {
           cmd.arg("--html-in-header").arg(&full_toc);
        }

        if filename == "not_found.md" {
            cmd.arg("--markdown-no-toc")
               .arg("--markdown-css")
               .arg("https://doc.rust-lang.org/rust.css");
        } else {
            cmd.arg("--markdown-css").arg("rust.css");
        }
        build.run(&mut cmd);
    }
}

/// Compile all standard library documentation.
///
/// This will generate all documentation for the standard library and its
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn std(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} std ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Libstd)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    build.clear_if_dirty(&out_dir, &rustdoc);

    let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
         .arg("--features").arg(build.std_features())
         .arg("-p").arg("std");
    build.run(&mut cargo);
    cp_r(&out_dir, &out)
}

/// Compile all libtest documentation.
///
/// This will generate all documentation for libtest and its dependencies. This
/// is largely just a wrapper around `cargo doc`.
pub fn test(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} test ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Libtest)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    build.clear_if_dirty(&out_dir, &rustdoc);

    let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
    build.run(&mut cargo);
    cp_r(&out_dir, &out)
}

/// Generate all compiler documentation.
///
/// This will generate all documentation for the compiler libraries and their
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn rustc(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} compiler ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Librustc)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);
    if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) && out_dir.exists() {
        t!(fs::remove_dir_all(&out_dir));
    }
    let mut cargo = build.cargo(&compiler, Mode::Librustc, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/rustc/Cargo.toml"))
         .arg("--features").arg(build.rustc_features());
    build.run(&mut cargo);
    cp_r(&out_dir, &out)
}

/// Generates the HTML rendered error-index by running the
/// `error_index_generator` tool.
pub fn error_index(build: &Build, target: &str) {
    println!("Documenting error index ({})", target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(0, &build.config.build);
    let mut index = build.tool_cmd(&compiler, "error_index_generator");
    index.arg("html");
    index.arg(out.join("error-index.html"));

    // FIXME: shouldn't have to pass this env var
    index.env("CFG_BUILD", &build.config.build);

    build.run(&mut index);
}
<commit_msg>Auto merge of #38858 - ollie27:rustbuild_docs_std, r=alexcrichton<commit_after>// Copyright 2016 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.

//! Documentation generation for rustbuild.
//!
//! This module implements generation for all bits and pieces of documentation
//! for the Rust project. This notably includes suites like the rust book, the
//! nomicon, standalone documentation, etc.
//!
//! Everything here is basically just a shim around calling either `rustbook` or
//! `rustdoc`.

use std::fs::{self, File};
use std::io::prelude::*;
use std::process::Command;

use {Build, Compiler, Mode};
use util::{up_to_date, cp_r};

/// Invoke `rustbook` as compiled in `stage` for `target` for the doc book
/// `name` into the `out` path.
///
/// This will not actually generate any documentation if the documentation has
/// already been generated.
pub fn rustbook(build: &Build, target: &str, name: &str) {
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));

    let out = out.join(name);
    let compiler = Compiler::new(0, &build.config.build);
    let src = build.src.join("src/doc").join(name);
    let index = out.join("index.html");
    let rustbook = build.tool(&compiler, "rustbook");
    if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
        return
    }
    println!("Rustbook ({}) - {}", target, name);
    let _ = fs::remove_dir_all(&out);
    build.run(build.tool_cmd(&compiler, "rustbook")
                   .arg("build")
                   .arg(&src)
                   .arg(out));
}

/// Generates all standalone documentation as compiled by the rustdoc in `stage`
/// for the `target` into `out`.
///
/// This will list all of `src/doc` looking for markdown files and appropriately
/// perform transformations like substituting `VERSION`, `SHORT_HASH`, and
/// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
///
/// In the end, this is just a glorified wrapper around rustdoc!
pub fn standalone(build: &Build, target: &str) {
    println!("Documenting standalone ({})", target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));

    let compiler = Compiler::new(0, &build.config.build);

    let favicon = build.src.join("src/doc/favicon.inc");
    let footer = build.src.join("src/doc/footer.inc");
    let full_toc = build.src.join("src/doc/full-toc.inc");
    t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));

    let version_input = build.src.join("src/doc/version_info.html.template");
    let version_info = out.join("version_info.html");

    if !up_to_date(&version_input, &version_info) {
        let mut info = String::new();
        t!(t!(File::open(&version_input)).read_to_string(&mut info));
        let blank = String::new();
        let short = build.short_ver_hash.as_ref().unwrap_or(&blank);
        let hash = build.ver_hash.as_ref().unwrap_or(&blank);
        let info = info.replace("VERSION", &build.release)
                       .replace("SHORT_HASH", short)
                       .replace("STAMP", hash);
        t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
    }

    for file in t!(fs::read_dir(build.src.join("src/doc"))) {
        let file = t!(file);
        let path = file.path();
        let filename = path.file_name().unwrap().to_str().unwrap();
        if !filename.ends_with(".md") || filename == "README.md" {
            continue
        }

        let html = out.join(filename).with_extension("html");
        let rustdoc = build.rustdoc(&compiler);
        if up_to_date(&path, &html) &&
           up_to_date(&footer, &html) &&
           up_to_date(&favicon, &html) &&
           up_to_date(&full_toc, &html) &&
           up_to_date(&version_info, &html) &&
           up_to_date(&rustdoc, &html) {
            continue
        }

        let mut cmd = Command::new(&rustdoc);
        build.add_rustc_lib_path(&compiler, &mut cmd);
        cmd.arg("--html-after-content").arg(&footer)
           .arg("--html-before-content").arg(&version_info)
           .arg("--html-in-header").arg(&favicon)
           .arg("--markdown-playground-url")
           .arg("https://play.rust-lang.org/")
           .arg("-o").arg(&out)
           .arg(&path);

        if filename == "reference.md" {
           cmd.arg("--html-in-header").arg(&full_toc);
        }

        if filename == "not_found.md" {
            cmd.arg("--markdown-no-toc")
               .arg("--markdown-css")
               .arg("https://doc.rust-lang.org/rust.css");
        } else {
            cmd.arg("--markdown-css").arg("rust.css");
        }
        build.run(&mut cmd);
    }
}

/// Compile all standard library documentation.
///
/// This will generate all documentation for the standard library and its
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn std(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} std ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Libstd)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    build.clear_if_dirty(&out_dir, &rustdoc);

    let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
         .arg("--features").arg(build.std_features())
         .arg("--no-deps");

    for krate in &["alloc", "collections", "core", "std", "std_unicode"] {
        cargo.arg("-p").arg(krate);
        // Create all crate output directories first to make sure rustdoc uses
        // relative links.
        // FIXME: Cargo should probably do this itself.
        t!(fs::create_dir_all(out_dir.join(krate)));
    }

    build.run(&mut cargo);
    cp_r(&out_dir, &out)
}

/// Compile all libtest documentation.
///
/// This will generate all documentation for libtest and its dependencies. This
/// is largely just a wrapper around `cargo doc`.
pub fn test(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} test ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Libtest)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    build.clear_if_dirty(&out_dir, &rustdoc);

    let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
    build.run(&mut cargo);
    cp_r(&out_dir, &out)
}

/// Generate all compiler documentation.
///
/// This will generate all documentation for the compiler libraries and their
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn rustc(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} compiler ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Librustc)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);
    if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) && out_dir.exists() {
        t!(fs::remove_dir_all(&out_dir));
    }
    let mut cargo = build.cargo(&compiler, Mode::Librustc, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/rustc/Cargo.toml"))
         .arg("--features").arg(build.rustc_features());
    build.run(&mut cargo);
    cp_r(&out_dir, &out)
}

/// Generates the HTML rendered error-index by running the
/// `error_index_generator` tool.
pub fn error_index(build: &Build, target: &str) {
    println!("Documenting error index ({})", target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(0, &build.config.build);
    let mut index = build.tool_cmd(&compiler, "error_index_generator");
    index.arg("html");
    index.arg(out.join("error-index.html"));

    // FIXME: shouldn't have to pass this env var
    index.env("CFG_BUILD", &build.config.build);

    build.run(&mut index);
}
<|endoftext|>