<commit_before>use super::{function, trait_impls};
use crate::{
    analysis::enums::Info,
    analysis::special_functions::Type,
    codegen::general::{
        self, cfg_deprecated, derives, doc_alias, version_condition, version_condition_no_doc,
        version_condition_string,
    },
    config::gobjects::GObject,
    env::Env,
    file_saver,
    library::*,
    nameutil::{enum_member_name, use_glib_if_needed, use_glib_type},
    traits::*,
    version::Version,
};
use std::{
    collections::HashSet,
    io::{prelude::*, Result},
    path::Path,
};

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    if env.analysis.enumerations.is_empty() {
        return;
    }

    let path = root_path.join("enums.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::uses(w, env, &env.analysis.enum_imports, None)?;
        writeln!(w)?;

        mod_rs.push("\nmod enums;".into());
        for enum_analysis in &env.analysis.enumerations {
            let config = &env.config.objects[&enum_analysis.full_name];
            let enum_ = enum_analysis.type_(&env.library);

            if let Some(cfg) = version_condition_string(env, enum_.version, false, 0) {
                mod_rs.push(cfg);
            }
            mod_rs.push(format!("pub use self::enums::{};", enum_.name));
            generate_enum(env, w, enum_, config, enum_analysis)?;
        }

        Ok(())
    });
}

#[allow(clippy::write_literal)]
fn generate_enum(
    env: &Env,
    w: &mut dyn Write,
    enum_: &Enumeration,
    config: &GObject,
    analysis: &Info,
) -> Result<()> {
    struct Member {
        name: String,
        c_name: String,
        value: String,
        version: Option<Version>,
        deprecated_version: Option<Version>,
    }

    let mut members: Vec<Member> = Vec::new();
    let mut vals: HashSet<String> = HashSet::new();
    let sys_crate_name = env.main_sys_crate_name();

    for member in &enum_.members {
        let member_config = config.members.matched(&member.name);
        let is_alias = member_config.iter().any(|m| m.alias);
        let generate = member_config.iter().all(|m| m.status.need_generate());
        if is_alias || !generate || vals.contains(&member.value) {
            continue;
        }
        vals.insert(member.value.clone());
        let deprecated_version = member_config
            .iter()
            .filter_map(|m| m.deprecated_version)
            .next();
        let version = member_config.iter().filter_map(|m| m.version).next();
        members.push(Member {
            name: enum_member_name(&member.name),
            c_name: member.c_identifier.clone(),
            value: member.value.clone(),
            version,
            deprecated_version,
        });
    }

    cfg_deprecated(w, env, enum_.deprecated_version, false, 0)?;
    version_condition(w, env, enum_.version, false, 0)?;
    if config.must_use {
        writeln!(w, "#[must_use]")?;
    }

    if let Some(ref d) = config.derives {
        derives(w, &d, 1)?;
    } else {
        writeln!(w, "#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]")?;
    }
    writeln!(w, "#[derive(Clone, Copy)]")?;
    writeln!(w, "#[non_exhaustive]")?;
    doc_alias(w, &enum_.c_type, "", 0)?;

    writeln!(w, "pub enum {} {{", enum_.name)?;
    for member in &members {
        cfg_deprecated(w, env, member.deprecated_version, false, 1)?;
        version_condition(w, env, member.version, false, 1)?;
        // Don't generate a doc_alias if the C name is the same as the Rust one
        if member.c_name != member.name {
            doc_alias(w, &member.c_name, "", 1)?;
        }
        writeln!(w, "\t{},", member.name)?;
    }
    writeln!(
        w,
        "\
    #[doc(hidden)]
    __Unknown(i32),
}}"
    )?;

    let functions = analysis
        .functions
        .iter()
        .filter(|f| f.status.need_generate())
        .collect::<Vec<_>>();

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

    trait_impls::generate(
        w,
        env,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        None,
        None,
    )?;

    writeln!(w)?;

    if config.generate_display_trait && !analysis.specials.has_trait(Type::Display) {
        // Generate Display trait implementation.
        version_condition(w, env, enum_.version, false, 0)?;
        writeln!(
            w,
            "impl fmt::Display for {} {{\n\
             \tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
             \t\twrite!(f, \"Self::{{}}\", match *self {{",
            enum_.name
        )?;
        for member in &members {
            version_condition_no_doc(w, env, member.version, false, 3)?;
            writeln!(w, "\t\t\tSelf::{0} => \"{0}\",", member.name)?;
        }
        writeln!(
            w,
            "\t\t\t_ => \"Unknown\",\n\
             \t\t}})\n\
             \t}}\n\
             }}\n"
        )?;
    }

    // Generate IntoGlib trait implementation.
    version_condition(w, env, enum_.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl IntoGlib for {name} {{
    type GlibType = {sys_crate_name}::{ffi_name};

    fn into_glib(self) -> {sys_crate_name}::{ffi_name} {{
        match self {{",
        sys_crate_name = sys_crate_name,
        name = enum_.name,
        ffi_name = enum_.c_type
    )?;
    for member in &members {
        version_condition_no_doc(w, env, member.version, false, 3)?;
        writeln!(
            w,
            "\t\t\tSelf::{} => {}::{},",
            member.name, sys_crate_name, member.c_name
        )?;
    }
    writeln!(w, "\t\t\tSelf::__Unknown(value) => value,")?;
    writeln!(
        w,
        "\
        }}
    }}
}}
"
    )?;

    let assert = if env.config.generate_safety_asserts {
        "skip_assert_initialized!();\n\t\t"
    } else {
        ""
    };

    // Generate FromGlib trait implementation.
    version_condition(w, env, enum_.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
    unsafe fn from_glib(value: {sys_crate_name}::{ffi_name}) -> Self {{
        {assert}match value {{",
        sys_crate_name = sys_crate_name,
        name = enum_.name,
        ffi_name = enum_.c_type,
        assert = assert
    )?;
    for member in &members {
        version_condition_no_doc(w, env, member.version, false, 3)?;
        writeln!(w, "\t\t\t{} => Self::{},", member.value, member.name)?;
    }
    writeln!(w, "\t\t\tvalue => Self::__Unknown(value),")?;
    writeln!(
        w,
        "\
        }}
    }}
}}
"
    )?;

    // Generate ErrorDomain trait implementation.
    if let Some(ref domain) = enum_.error_domain {
        let has_failed_member = members.iter().any(|m| m.name == "Failed");

        version_condition(w, env, enum_.version, false, 0)?;
        writeln!(
            w,
            "impl ErrorDomain for {name} {{
    fn domain() -> Quark {{
        {assert}",
            name = enum_.name,
            assert = assert
        )?;

        match domain {
            ErrorDomain::Quark(ref quark) => {
                writeln!(
                    w,
                    "        static QUARK: once_cell::sync::Lazy<{0}ffi::GQuark> = once_cell::sync::Lazy::new(|| unsafe {{
            {0}ffi::g_quark_from_static_string(b\"{1}\\0\".as_ptr() as *const _)
        }});
        unsafe {{ from_glib(*QUARK) }}",
                    use_glib_if_needed(env, ""),
                    quark,
                )?;
            }
            ErrorDomain::Function(ref f) => {
                writeln!(
                    w,
                    "        unsafe {{ from_glib({sys_crate_name}::{get_quark}()) }}",
                    sys_crate_name = sys_crate_name,
                    get_quark = f
                )?;
            }
        }

        writeln!(
            w,
            "    }}

    fn code(self) -> i32 {{
        self.into_glib()
    }}

    fn from(code: i32) -> Option<Self> {{
        {assert}match code {{",
            assert = assert
        )?;

        for member in &members {
            version_condition_no_doc(w, env, member.version, false, 3)?;
            writeln!(w, "\t\t\t{} => Some(Self::{}),", member.value, member.name)?;
        }
        if has_failed_member {
            writeln!(w, "\t\t\t_ => Some(Self::Failed),")?;
        } else {
            writeln!(w, "\t\t\tvalue => Some(Self::__Unknown(value)),")?;
        }

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

    // Generate StaticType trait implementation.
    if let Some(ref get_type) = enum_.glib_get_type {
        let configured_functions = config.functions.matched("get_type");
        let version = std::iter::once(enum_.version)
            .chain(configured_functions.iter().map(|f| f.version))
            .max()
            .flatten();

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl StaticType for {name} {{
    fn static_type() -> Type {{
        unsafe {{ from_glib({sys_crate_name}::{get_type}()) }}
    }}
}}",
            sys_crate_name = sys_crate_name,
            name = enum_.name,
            get_type = get_type
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl {valuetype} for {name} {{
    type Type = Self;
}}",
            name = enum_.name,
            valuetype = use_glib_type(env, "value::ValueType"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "unsafe impl<'a> FromValue<'a> for {name} {{
    type Checker = {genericwrongvaluetypechecker}<Self>;

    unsafe fn from_value(value: &'a {gvalue}) -> Self {{
        {assert}from_glib({glib}(value.to_glib_none().0))
    }}
}}",
            name = enum_.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_get_enum"),
            gvalue = use_glib_type(env, "Value"),
            genericwrongvaluetypechecker = use_glib_type(env, "value::GenericValueTypeChecker"),
            assert = assert,
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl ToValue for {name} {{
    fn to_value(&self) -> {gvalue} {{
        let mut value = {gvalue}::for_value_type::<Self>();
        unsafe {{
            {glib}(value.to_glib_none_mut().0, self.into_glib());
        }}
        value
    }}

    fn value_type(&self) -> {gtype} {{
        Self::static_type()
    }}
}}",
            name = enum_.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_set_enum"),
            gvalue = use_glib_type(env, "Value"),
            gtype = use_glib_type(env, "Type"),
        )?;
        writeln!(w)?;
    }

    Ok(())
}
<commit_msg>codegen/enums: Keep emitting name of `Self` in string literals<commit_after>use super::{function, trait_impls};
use crate::{
    analysis::enums::Info,
    analysis::special_functions::Type,
    codegen::general::{
        self, cfg_deprecated, derives, doc_alias, version_condition, version_condition_no_doc,
        version_condition_string,
    },
    config::gobjects::GObject,
    env::Env,
    file_saver,
    library::*,
    nameutil::{enum_member_name, use_glib_if_needed, use_glib_type},
    traits::*,
    version::Version,
};
use std::{
    collections::HashSet,
    io::{prelude::*, Result},
    path::Path,
};

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    if env.analysis.enumerations.is_empty() {
        return;
    }

    let path = root_path.join("enums.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::uses(w, env, &env.analysis.enum_imports, None)?;
        writeln!(w)?;

        mod_rs.push("\nmod enums;".into());
        for enum_analysis in &env.analysis.enumerations {
            let config = &env.config.objects[&enum_analysis.full_name];
            let enum_ = enum_analysis.type_(&env.library);

            if let Some(cfg) = version_condition_string(env, enum_.version, false, 0) {
                mod_rs.push(cfg);
            }
            mod_rs.push(format!("pub use self::enums::{};", enum_.name));
            generate_enum(env, w, enum_, config, enum_analysis)?;
        }

        Ok(())
    });
}

#[allow(clippy::write_literal)]
fn generate_enum(
    env: &Env,
    w: &mut dyn Write,
    enum_: &Enumeration,
    config: &GObject,
    analysis: &Info,
) -> Result<()> {
    struct Member {
        name: String,
        c_name: String,
        value: String,
        version: Option<Version>,
        deprecated_version: Option<Version>,
    }

    let mut members: Vec<Member> = Vec::new();
    let mut vals: HashSet<String> = HashSet::new();
    let sys_crate_name = env.main_sys_crate_name();

    for member in &enum_.members {
        let member_config = config.members.matched(&member.name);
        let is_alias = member_config.iter().any(|m| m.alias);
        let generate = member_config.iter().all(|m| m.status.need_generate());
        if is_alias || !generate || vals.contains(&member.value) {
            continue;
        }
        vals.insert(member.value.clone());
        let deprecated_version = member_config
            .iter()
            .filter_map(|m| m.deprecated_version)
            .next();
        let version = member_config.iter().filter_map(|m| m.version).next();
        members.push(Member {
            name: enum_member_name(&member.name),
            c_name: member.c_identifier.clone(),
            value: member.value.clone(),
            version,
            deprecated_version,
        });
    }

    cfg_deprecated(w, env, enum_.deprecated_version, false, 0)?;
    version_condition(w, env, enum_.version, false, 0)?;
    if config.must_use {
        writeln!(w, "#[must_use]")?;
    }

    if let Some(ref d) = config.derives {
        derives(w, &d, 1)?;
    } else {
        writeln!(w, "#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]")?;
    }
    writeln!(w, "#[derive(Clone, Copy)]")?;
    writeln!(w, "#[non_exhaustive]")?;
    doc_alias(w, &enum_.c_type, "", 0)?;

    writeln!(w, "pub enum {} {{", enum_.name)?;
    for member in &members {
        cfg_deprecated(w, env, member.deprecated_version, false, 1)?;
        version_condition(w, env, member.version, false, 1)?;
        // Don't generate a doc_alias if the C name is the same as the Rust one
        if member.c_name != member.name {
            doc_alias(w, &member.c_name, "", 1)?;
        }
        writeln!(w, "\t{},", member.name)?;
    }
    writeln!(
        w,
        "\
    #[doc(hidden)]
    __Unknown(i32),
}}"
    )?;

    let functions = analysis
        .functions
        .iter()
        .filter(|f| f.status.need_generate())
        .collect::<Vec<_>>();

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

    trait_impls::generate(
        w,
        env,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        None,
        None,
    )?;

    writeln!(w)?;

    if config.generate_display_trait && !analysis.specials.has_trait(Type::Display) {
        // Generate Display trait implementation.
        version_condition(w, env, enum_.version, false, 0)?;
        writeln!(
            w,
            "impl fmt::Display for {0} {{\n\
             \tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
             \t\twrite!(f, \"{0}::{{}}\", match *self {{",
            enum_.name
        )?;
        for member in &members {
            version_condition_no_doc(w, env, member.version, false, 3)?;
            writeln!(w, "\t\t\tSelf::{0} => \"{0}\",", member.name)?;
        }
        writeln!(
            w,
            "\t\t\t_ => \"Unknown\",\n\
             \t\t}})\n\
             \t}}\n\
             }}\n"
        )?;
    }

    // Generate IntoGlib trait implementation.
    version_condition(w, env, enum_.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl IntoGlib for {name} {{
    type GlibType = {sys_crate_name}::{ffi_name};

    fn into_glib(self) -> {sys_crate_name}::{ffi_name} {{
        match self {{",
        sys_crate_name = sys_crate_name,
        name = enum_.name,
        ffi_name = enum_.c_type
    )?;
    for member in &members {
        version_condition_no_doc(w, env, member.version, false, 3)?;
        writeln!(
            w,
            "\t\t\tSelf::{} => {}::{},",
            member.name, sys_crate_name, member.c_name
        )?;
    }
    writeln!(w, "\t\t\tSelf::__Unknown(value) => value,")?;
    writeln!(
        w,
        "\
        }}
    }}
}}
"
    )?;

    let assert = if env.config.generate_safety_asserts {
        "skip_assert_initialized!();\n\t\t"
    } else {
        ""
    };

    // Generate FromGlib trait implementation.
    version_condition(w, env, enum_.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
    unsafe fn from_glib(value: {sys_crate_name}::{ffi_name}) -> Self {{
        {assert}match value {{",
        sys_crate_name = sys_crate_name,
        name = enum_.name,
        ffi_name = enum_.c_type,
        assert = assert
    )?;
    for member in &members {
        version_condition_no_doc(w, env, member.version, false, 3)?;
        writeln!(w, "\t\t\t{} => Self::{},", member.value, member.name)?;
    }
    writeln!(w, "\t\t\tvalue => Self::__Unknown(value),")?;
    writeln!(
        w,
        "\
        }}
    }}
}}
"
    )?;

    // Generate ErrorDomain trait implementation.
    if let Some(ref domain) = enum_.error_domain {
        let has_failed_member = members.iter().any(|m| m.name == "Failed");

        version_condition(w, env, enum_.version, false, 0)?;
        writeln!(
            w,
            "impl ErrorDomain for {name} {{
    fn domain() -> Quark {{
        {assert}",
            name = enum_.name,
            assert = assert
        )?;

        match domain {
            ErrorDomain::Quark(ref quark) => {
                writeln!(
                    w,
                    "        static QUARK: once_cell::sync::Lazy<{0}ffi::GQuark> = once_cell::sync::Lazy::new(|| unsafe {{
            {0}ffi::g_quark_from_static_string(b\"{1}\\0\".as_ptr() as *const _)
        }});
        unsafe {{ from_glib(*QUARK) }}",
                    use_glib_if_needed(env, ""),
                    quark,
                )?;
            }
            ErrorDomain::Function(ref f) => {
                writeln!(
                    w,
                    "        unsafe {{ from_glib({sys_crate_name}::{get_quark}()) }}",
                    sys_crate_name = sys_crate_name,
                    get_quark = f
                )?;
            }
        }

        writeln!(
            w,
            "    }}

    fn code(self) -> i32 {{
        self.into_glib()
    }}

    fn from(code: i32) -> Option<Self> {{
        {assert}match code {{",
            assert = assert
        )?;

        for member in &members {
            version_condition_no_doc(w, env, member.version, false, 3)?;
            writeln!(w, "\t\t\t{} => Some(Self::{}),", member.value, member.name)?;
        }
        if has_failed_member {
            writeln!(w, "\t\t\t_ => Some(Self::Failed),")?;
        } else {
            writeln!(w, "\t\t\tvalue => Some(Self::__Unknown(value)),")?;
        }

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

    // Generate StaticType trait implementation.
    if let Some(ref get_type) = enum_.glib_get_type {
        let configured_functions = config.functions.matched("get_type");
        let version = std::iter::once(enum_.version)
            .chain(configured_functions.iter().map(|f| f.version))
            .max()
            .flatten();

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl StaticType for {name} {{
    fn static_type() -> Type {{
        unsafe {{ from_glib({sys_crate_name}::{get_type}()) }}
    }}
}}",
            sys_crate_name = sys_crate_name,
            name = enum_.name,
            get_type = get_type
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl {valuetype} for {name} {{
    type Type = Self;
}}",
            name = enum_.name,
            valuetype = use_glib_type(env, "value::ValueType"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "unsafe impl<'a> FromValue<'a> for {name} {{
    type Checker = {genericwrongvaluetypechecker}<Self>;

    unsafe fn from_value(value: &'a {gvalue}) -> Self {{
        {assert}from_glib({glib}(value.to_glib_none().0))
    }}
}}",
            name = enum_.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_get_enum"),
            gvalue = use_glib_type(env, "Value"),
            genericwrongvaluetypechecker = use_glib_type(env, "value::GenericValueTypeChecker"),
            assert = assert,
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl ToValue for {name} {{
    fn to_value(&self) -> {gvalue} {{
        let mut value = {gvalue}::for_value_type::<Self>();
        unsafe {{
            {glib}(value.to_glib_none_mut().0, self.into_glib());
        }}
        value
    }}

    fn value_type(&self) -> {gtype} {{
        Self::static_type()
    }}
}}",
            name = enum_.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_set_enum"),
            gvalue = use_glib_type(env, "Value"),
            gtype = use_glib_type(env, "Type"),
        )?;
        writeln!(w)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use url::form_urlencoded;
use command::{Command, Query};
use command::Command::Dump;

#[derive(Clone, Debug)]
pub struct CommandQuery {
    command: Command,
    arguments: Query,
    prefix: String,
}

impl Default for CommandQuery {
    fn default() -> CommandQuery {
        CommandQuery {
            command: Dump,
            arguments: vec![],
            prefix: "/d".to_string(),
        }
    }
}

impl CommandQuery {
    pub fn new(command: Command, query: Query) -> CommandQuery {
        let default: CommandQuery = Default::default();
        CommandQuery {
            command: command,
            arguments: query,
            prefix: default.prefix,
        }
    }

    /// Get command enum constant to construct url encoded query.
    pub fn get_command(&mut self) -> Command {
        self.command.clone()
    }

    /// Get vectorize `("key", "value")` pairs to construct url encoded query.
    pub fn get_argument(&mut self) -> Query {
        self.arguments.clone()
    }

    /// Set vectorize `("key", "value")` pairs to construct url encoded query.
    pub fn set_argument(&mut self, arguments: Query) {
        self.arguments = arguments
    }

    #[doc(hidden)]
    // get HTTP URI prefix. default: /d
    // This function is mainly provided for internal usage.
    pub fn get_prefix(&mut self) -> String {
        self.prefix.clone()
    }

    #[doc(hidden)]
    // set HTTP URI prefix. This function is provided for advanced user.
    pub fn set_prefix(&mut self, prefix: String) {
        self.prefix = prefix
    }

    /// Create url encoded command query.
    ///
    /// `vec![("key","value")]` interprets to `"key=value"`.
    /// And two or more value pair are concatinate with `&`.
    pub fn make_query(&mut self) -> String {
        form_urlencoded::Serializer::new(String::new())
            .extend_pairs(self.arguments.to_owned())
            .finish()
    }

    ///
    /// Create Groonga HTTP server query URL.
    pub fn encode(&mut self) -> String {
        format!("{}/{}?{}",
                self.get_prefix(),
                self.get_command(),
                self.make_query())
    }
}

#[cfg(test)]
mod test {
    use super::CommandQuery;
    use select::SelectCommand;
    use load::{LoadCommand, InputType};
    use status::StatusCommand;
    use dump::DumpCommand;
    use delete::DeleteCommand;
    use table_create::TableCreateCommand;
    use types::table_flag_type::TableFlagType;
    use column_create::ColumnCreateCommand;
    use types::data_type::DataType;

    #[test]
    fn test_select() {
        let (command, query) = SelectCommand::new("Test".to_string())
            .filter("output_column @ \"type_safe\"".to_string())
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/select?table=Test&filter=%27output_column+%40+%22type_safe%22%27";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_load() {
        let load_data: &'static str = r#"[
{"_key":"http://example.org/","title":"This is test record 1!"},
]"#;
        let (command, query, values) = LoadCommand::new("test".to_string(), load_data.to_string())
            .input_type(InputType::Json)
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/load?table=test&input_type=json";
        assert_eq!(url_encoded.to_string(), command_query);
        assert_eq!(load_data.to_string(), values);
    }

    #[test]
    fn test_status() {
        let (command, query) = StatusCommand::new().build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/status?";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_dump() {
        let (command, query) = DumpCommand::new()
            .tables(vec!["Books".to_string(), "Categories".to_string()])
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/dump?tables=Books%2CCategories";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_delete() {
        let (command, query) = DeleteCommand::new("Books".to_string())
            .filter("author == unknown".to_string())
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/delete?table=Books&filter=%27author+%3D%3D+unknown%27";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_table_create() {
        let (command, query) = TableCreateCommand::new("Test".to_string())
            .flags(vec![(TableFlagType::PatKey), (TableFlagType::KeyWithSIS)])
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/table_create?name=Test&flags=TABLE_PAT_KEY%7CKEY_WITH_SIS";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_column_create() {
        let (command, query) = ColumnCreateCommand::new("Test".to_string(), "element".to_string())
            .column_type(DataType::LongText)
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/column_create?table=Test&name=element&type=LongText";
        assert_eq!(url_encoded.to_string(), command_query);
    }
}
<commit_msg>command_query: Try to use Cow<commit_after>use url::form_urlencoded;
use command::{Command, Query};
use command::Command::Dump;
use std::borrow::Cow;

#[derive(Clone, Debug)]
pub struct CommandQuery {
    command: Command,
    arguments: Query,
    prefix: String,
}

impl Default for CommandQuery {
    fn default() -> CommandQuery {
        CommandQuery {
            command: Dump,
            arguments: vec![],
            prefix: "/d".to_string(),
        }
    }
}

impl CommandQuery {
    pub fn new(command: Command, query: Query) -> CommandQuery {
        let default: CommandQuery = Default::default();
        CommandQuery {
            command: command,
            arguments: query,
            prefix: default.prefix,
        }
    }

    /// Get command enum constant to construct url encoded query.
    pub fn get_command(&mut self) -> Cow<Command> {
        Cow::Borrowed(&self.command)
    }

    /// Get vectorize `("key", "value")` pairs to construct url encoded query.
    pub fn get_argument(&mut self) -> Cow<Query> {
        Cow::Borrowed(&self.arguments)
    }

    /// Set vectorize `("key", "value")` pairs to construct url encoded query.
    pub fn set_argument(&mut self, arguments: Query) {
        self.arguments = arguments
    }

    #[doc(hidden)]
    // get HTTP URI prefix. default: /d
    // This function is mainly provided for internal usage.
    pub fn get_prefix(&mut self) -> Cow<String> {
        Cow::Borrowed(&self.prefix)
    }

    #[doc(hidden)]
    // set HTTP URI prefix. This function is provided for advanced user.
    pub fn set_prefix(&mut self, prefix: String) {
        self.prefix = prefix
    }

    /// Create url encoded command query.
    ///
    /// `vec![("key","value")]` interprets to `"key=value"`.
    /// And two or more value pair are concatinate with `&`.
    pub fn make_query(&mut self) -> String {
        form_urlencoded::Serializer::new(String::new())
            .extend_pairs(self.arguments.to_owned())
            .finish()
    }

    ///
    /// Create Groonga HTTP server query URL.
    pub fn encode(&mut self) -> String {
        format!("{}/{}?{}",
                self.get_prefix().into_owned(),
                self.get_command().into_owned(),
                self.make_query())
    }
}

#[cfg(test)]
mod test {
    use super::CommandQuery;
    use select::SelectCommand;
    use load::{LoadCommand, InputType};
    use status::StatusCommand;
    use dump::DumpCommand;
    use delete::DeleteCommand;
    use table_create::TableCreateCommand;
    use types::table_flag_type::TableFlagType;
    use column_create::ColumnCreateCommand;
    use types::data_type::DataType;

    #[test]
    fn test_select() {
        let (command, query) = SelectCommand::new("Test".to_string())
            .filter("output_column @ \"type_safe\"".to_string())
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/select?table=Test&filter=%27output_column+%40+%22type_safe%22%27";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_load() {
        let load_data: &'static str = r#"[
{"_key":"http://example.org/","title":"This is test record 1!"},
]"#;
        let (command, query, values) = LoadCommand::new("test".to_string(), load_data.to_string())
            .input_type(InputType::Json)
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/load?table=test&input_type=json";
        assert_eq!(url_encoded.to_string(), command_query);
        assert_eq!(load_data.to_string(), values);
    }

    #[test]
    fn test_status() {
        let (command, query) = StatusCommand::new().build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/status?";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_dump() {
        let (command, query) = DumpCommand::new()
            .tables(vec!["Books".to_string(), "Categories".to_string()])
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/dump?tables=Books%2CCategories";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_delete() {
        let (command, query) = DeleteCommand::new("Books".to_string())
            .filter("author == unknown".to_string())
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/delete?table=Books&filter=%27author+%3D%3D+unknown%27";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_table_create() {
        let (command, query) = TableCreateCommand::new("Test".to_string())
            .flags(vec![(TableFlagType::PatKey), (TableFlagType::KeyWithSIS)])
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/table_create?name=Test&flags=TABLE_PAT_KEY%7CKEY_WITH_SIS";
        assert_eq!(url_encoded.to_string(), command_query);
    }

    #[test]
    fn test_column_create() {
        let (command, query) = ColumnCreateCommand::new("Test".to_string(), "element".to_string())
            .column_type(DataType::LongText)
            .build();
        let command_query = CommandQuery::new(command, query).encode();
        let url_encoded = "/d/column_create?table=Test&name=element&type=LongText";
        assert_eq!(url_encoded.to_string(), command_query);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use ::compiler::{
    Cacheable,
    Compiler,
    CompilerArguments,
    ParsedArguments,
    run_input_output,
};
use log::LogLevel::Trace;
use mock_command::{
    CommandCreator,
    CommandCreatorSync,
    RunCommand,
};
use std::collections::HashMap;
use std::fs::File;
use std::io::{
    self,
    Error,
    ErrorKind,
    Write,
};
use std::path::Path;
use std::process;
use tempdir::TempDir;

pub fn parse_arguments(arguments: &[String]) -> CompilerArguments {
    let mut output_arg = None;
    let mut input_arg = None;
    let mut common_args = vec!();
    let mut compilation = false;
    let mut debug_info = false;
    let mut pdb = None;

    //TODO: support arguments that start with / as well.
    let mut it = arguments.iter();
    loop {
        match it.next() {
            Some(arg) => {
                match arg.as_ref() {
                    //TODO: support -dep
                    "-c" => compilation = true,
                    v @ _ if v.starts_with("-Fo") => {
                        output_arg = Some(String::from(&v[3..]));
                    }
                    // Arguments that take a value.
                    "-FI" => {
                        common_args.push(arg.clone());
                        if let Some(arg_val) = it.next() {
                            common_args.push(arg_val.clone());
                        }
                    }
                    // Arguments we can't handle.
                    "-showIncludes" => return CompilerArguments::CannotCache,
                    a @ _ if a.starts_with('@') => return CompilerArguments::CannotCache,
                    // Arguments we can't handle because they output more files.
                    // TODO: support more multi-file outputs.
                    "-FA" | "-Fa" | "-Fe" | "-Fm" | "-Fp" | "-FR" | "-Fx" => return CompilerArguments::CannotCache,
                    "-Zi" => {
                        debug_info = true;
                        common_args.push(arg.clone());
                    }
                    v @ _ if v.starts_with("-Fd") => {
                        pdb = Some(String::from(&v[3..]));
                        common_args.push(arg.clone());
                    }
                    // Other options.
                    v @ _ if v.starts_with('-') && v.len() > 1 => {
                        common_args.push(arg.clone());
                    }
                    // Anything else is an input file.
                    v @ _ => {
                        if input_arg.is_some() {
                            // Can't cache compilations with multiple inputs.
                            return CompilerArguments::CannotCache;
                        }
                        input_arg = Some(v);
                    }
                }
            }
            None => break,
        }
    }
    // We only support compilation.
    if !compilation {
        return CompilerArguments::NotCompilation;
    }
    let (input, extension) = match input_arg {
        Some(i) => {
            match Path::new(i).extension().and_then(|e| e.to_str()) {
                Some(e) => (i.to_owned(), e.to_owned()),
                _ => {
                    trace!("Bad or missing source extension: {:?}", i);
                    return CompilerArguments::CannotCache;
                }
            }
        }
        // We can't cache compilation without an input.
        None => return CompilerArguments::CannotCache,
    };
    let mut outputs = HashMap::new();
    match output_arg {
        // We can't cache compilation that doesn't go to a file
        None => return CompilerArguments::CannotCache,
        Some(o) => {
            outputs.insert("obj", o.to_owned());
            // -Fd is not taken into account unless -Zi is given
            if debug_info {
                match pdb {
                    Some(p) => outputs.insert("pdb", p.to_owned()),
                    None => {
                        // -Zi without -Fd defaults to vcxxx.pdb (where xxx depends on the
                        // MSVC version), and that's used for all compilations with the same
                        // working directory. We can't cache such a pdb.
                        return CompilerArguments::CannotCache;
                    }
                };
            }
        }
    }
    CompilerArguments::Ok(ParsedArguments {
        input: input,
        extension: extension,
        outputs: outputs,
        preprocessor_args: vec!(),
        common_args: common_args,
    })
}

pub fn preprocess<T : CommandCreatorSync>(mut creator: T, compiler: &Compiler, parsed_args: &ParsedArguments, cwd: &str) -> io::Result<process::Output> {
    trace!("preprocess");
    //TODO: support depfile by way of -showIncludes
    let mut cmd = creator.new_command_sync(&compiler.executable);
    cmd.arg("-E")
        .arg(&parsed_args.input)
        .arg("-nologo")
        .args(&parsed_args.common_args)
        .current_dir(cwd);

    if log_enabled!(Trace) {
        trace!("preprocess: {:?}", cmd);
    }

    run_input_output(cmd, None)
}

pub fn compile<T : CommandCreatorSync>(mut creator: T, compiler: &Compiler, preprocessor_output: Vec<u8>, parsed_args: &ParsedArguments, cwd: &str) -> io::Result<(Cacheable, process::Output)> {
    trace!("compile");
    let output = try!(parsed_args.outputs.get("obj").ok_or(Error::new(ErrorKind::Other, "Missing object file output")));
    //TODO: check for the presence of the pdb file, refuse to cache if present.
    // MSVC doesn't read anything from stdin, so it needs a temporary file
    // as input.
    let tempdir = try!(TempDir::new("sccache"));
    let filename = try!(Path::new(&parsed_args.input).file_name().ok_or(Error::new(ErrorKind::Other, "Missing input filename")));
    let input = tempdir.path().join(filename);
    {
        try!(File::create(&input)
             .and_then(|mut f| f.write_all(&preprocessor_output)))
    }

    let mut cmd = creator.new_command_sync(&compiler.executable);
    cmd.arg("-c")
        .arg(&input)
        .arg(&format!("-Fo{}", output))
        .args(&parsed_args.common_args)
        .current_dir(cwd);

    let output = try!(run_input_output(cmd, None));
    Ok((Cacheable::Yes, output))
}

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

    #[test]
    fn test_parse_arguments_simple() {
        match parse_arguments(&stringvec!["-c", "foo.c", "-Fofoo.obj"]) {
            CompilerArguments::Ok(ParsedArguments { input, extension, outputs, preprocessor_args, common_args }) => {
                assert!(true, "Parsed ok");
                assert_eq!("foo.c", input);
                assert_eq!("c", extension);
                assert_map_contains!(outputs, ("obj", "foo.obj"));
                //TODO: fix assert_map_contains to assert no extra keys!
                assert_eq!(1, outputs.len());
                assert!(preprocessor_args.is_empty());
                assert!(common_args.is_empty());
            }
            o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
        }
    }

    #[test]
    fn test_parse_arguments_extra() {
        match parse_arguments(&stringvec!["-c", "foo.c", "-foo", "-Fofoo.obj", "-bar"]) {
            CompilerArguments::Ok(ParsedArguments { input, extension, outputs, preprocessor_args, common_args }) => {
                assert!(true, "Parsed ok");
                assert_eq!("foo.c", input);
                assert_eq!("c", extension);
                assert_map_contains!(outputs, ("obj", "foo.obj"));
                //TODO: fix assert_map_contains to assert no extra keys!
                assert_eq!(1, outputs.len());
                assert!(preprocessor_args.is_empty());
                assert_eq!(common_args, &["-foo", "-bar"]);
            }
            o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
        }
    }

    #[test]
    fn test_parse_arguments_values() {
        match parse_arguments(&stringvec!["-c", "foo.c", "-FI", "file", "-Fofoo.obj"]) {
            CompilerArguments::Ok(ParsedArguments { input, extension, outputs, preprocessor_args, common_args }) => {
                assert!(true, "Parsed ok");
                assert_eq!("foo.c", input);
                assert_eq!("c", extension);
                assert_map_contains!(outputs, ("obj", "foo.obj"));
                //TODO: fix assert_map_contains to assert no extra keys!
                assert_eq!(1, outputs.len());
                assert!(preprocessor_args.is_empty());
                assert_eq!(common_args, &["-FI", "file"]);
            }
            o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
        }
    }

    #[test]
    fn test_parse_arguments_pdb() {
        match parse_arguments(&stringvec!["-c", "foo.c", "-Zi", "-Fdfoo.pdb", "-Fofoo.obj"]) {
            CompilerArguments::Ok(ParsedArguments { input, extension, outputs, preprocessor_args, common_args }) => {
                assert!(true, "Parsed ok");
                assert_eq!("foo.c", input);
                assert_eq!("c", extension);
                assert_map_contains!(outputs, ("obj", "foo.obj"), ("pdb", "foo.pdb"));
                //TODO: fix assert_map_contains to assert no extra keys!
                assert_eq!(2, outputs.len());
                assert!(preprocessor_args.is_empty());
                assert_eq!(common_args, &["-Zi", "-Fdfoo.pdb"]);
            }
            o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
        }
    }

    #[test]
    fn test_parse_arguments_empty_args() {
        assert_eq!(CompilerArguments::NotCompilation,
                   parse_arguments(&vec!()));
    }

    #[test]
    fn test_parse_arguments_not_compile() {
        assert_eq!(CompilerArguments::NotCompilation,
                   parse_arguments(&stringvec!["-Fofoo", "foo.c"]));
    }

    #[test]
    fn test_parse_arguments_too_many_inputs() {
        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "-Fofoo.obj", "bar.c"]));
    }

    #[test]
    fn test_parse_arguments_unsupported() {
        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "-Fofoo.obj", "-FA"]));

        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-Fa", "-c", "foo.c", "-Fofoo.obj"]));

        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "-FR", "-Fofoo.obj"]));
    }

    #[test]
    fn test_parse_arguments_response_file() {
        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "@foo", "-Fofoo.obj"]));
    }

    #[test]
    fn test_parse_arguments_missing_pdb() {
        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "-Zi", "-Fofoo.obj"]));
    }
}
<commit_msg>make MSVC compile but not cache if using a PDB that's already present<commit_after>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use ::compiler::{
    Cacheable,
    Compiler,
    CompilerArguments,
    ParsedArguments,
    run_input_output,
};
use log::LogLevel::Trace;
use mock_command::{
    CommandCreator,
    CommandCreatorSync,
    RunCommand,
};
use std::collections::HashMap;
use std::fs::File;
use std::io::{
    self,
    Error,
    ErrorKind,
    Write,
};
use std::path::Path;
use std::process;
use tempdir::TempDir;

pub fn parse_arguments(arguments: &[String]) -> CompilerArguments {
    let mut output_arg = None;
    let mut input_arg = None;
    let mut common_args = vec!();
    let mut compilation = false;
    let mut debug_info = false;
    let mut pdb = None;

    //TODO: support arguments that start with / as well.
    let mut it = arguments.iter();
    loop {
        match it.next() {
            Some(arg) => {
                match arg.as_ref() {
                    //TODO: support -dep
                    "-c" => compilation = true,
                    v @ _ if v.starts_with("-Fo") => {
                        output_arg = Some(String::from(&v[3..]));
                    }
                    // Arguments that take a value.
                    "-FI" => {
                        common_args.push(arg.clone());
                        if let Some(arg_val) = it.next() {
                            common_args.push(arg_val.clone());
                        }
                    }
                    // Arguments we can't handle.
                    "-showIncludes" => return CompilerArguments::CannotCache,
                    a @ _ if a.starts_with('@') => return CompilerArguments::CannotCache,
                    // Arguments we can't handle because they output more files.
                    // TODO: support more multi-file outputs.
                    "-FA" | "-Fa" | "-Fe" | "-Fm" | "-Fp" | "-FR" | "-Fx" => return CompilerArguments::CannotCache,
                    "-Zi" => {
                        debug_info = true;
                        common_args.push(arg.clone());
                    }
                    v @ _ if v.starts_with("-Fd") => {
                        pdb = Some(String::from(&v[3..]));
                        common_args.push(arg.clone());
                    }
                    // Other options.
                    v @ _ if v.starts_with('-') && v.len() > 1 => {
                        common_args.push(arg.clone());
                    }
                    // Anything else is an input file.
                    v @ _ => {
                        if input_arg.is_some() {
                            // Can't cache compilations with multiple inputs.
                            return CompilerArguments::CannotCache;
                        }
                        input_arg = Some(v);
                    }
                }
            }
            None => break,
        }
    }
    // We only support compilation.
    if !compilation {
        return CompilerArguments::NotCompilation;
    }
    let (input, extension) = match input_arg {
        Some(i) => {
            match Path::new(i).extension().and_then(|e| e.to_str()) {
                Some(e) => (i.to_owned(), e.to_owned()),
                _ => {
                    trace!("Bad or missing source extension: {:?}", i);
                    return CompilerArguments::CannotCache;
                }
            }
        }
        // We can't cache compilation without an input.
        None => return CompilerArguments::CannotCache,
    };
    let mut outputs = HashMap::new();
    match output_arg {
        // We can't cache compilation that doesn't go to a file
        None => return CompilerArguments::CannotCache,
        Some(o) => {
            outputs.insert("obj", o.to_owned());
            // -Fd is not taken into account unless -Zi is given
            if debug_info {
                match pdb {
                    Some(p) => outputs.insert("pdb", p.to_owned()),
                    None => {
                        // -Zi without -Fd defaults to vcxxx.pdb (where xxx depends on the
                        // MSVC version), and that's used for all compilations with the same
                        // working directory. We can't cache such a pdb.
                        return CompilerArguments::CannotCache;
                    }
                };
            }
        }
    }
    CompilerArguments::Ok(ParsedArguments {
        input: input,
        extension: extension,
        outputs: outputs,
        preprocessor_args: vec!(),
        common_args: common_args,
    })
}

pub fn preprocess<T : CommandCreatorSync>(mut creator: T, compiler: &Compiler, parsed_args: &ParsedArguments, cwd: &str) -> io::Result<process::Output> {
    trace!("preprocess");
    //TODO: support depfile by way of -showIncludes
    let mut cmd = creator.new_command_sync(&compiler.executable);
    cmd.arg("-E")
        .arg(&parsed_args.input)
        .arg("-nologo")
        .args(&parsed_args.common_args)
        .current_dir(cwd);

    if log_enabled!(Trace) {
        trace!("preprocess: {:?}", cmd);
    }

    run_input_output(cmd, None)
}

pub fn compile<T : CommandCreatorSync>(mut creator: T, compiler: &Compiler, preprocessor_output: Vec<u8>, parsed_args: &ParsedArguments, cwd: &str) -> io::Result<(Cacheable, process::Output)> {
    trace!("compile");
    let output = try!(parsed_args.outputs.get("obj").ok_or(Error::new(ErrorKind::Other, "Missing object file output")));
    // See if this compilation will produce a PDB.
    let cacheable = parsed_args.outputs.get("pdb")
        .map(|pdb| {
            // If the PDB exists, we don't know if it's shared with another
            // compilation. If it is, we can't cache.
            if Path::new(cwd).join(pdb).exists() {
                Cacheable::No
            } else {
                Cacheable::Yes
            }
        })
        .unwrap_or(Cacheable::Yes);
    // MSVC doesn't read anything from stdin, so it needs a temporary file
    // as input.
    let tempdir = try!(TempDir::new("sccache"));
    let filename = try!(Path::new(&parsed_args.input).file_name().ok_or(Error::new(ErrorKind::Other, "Missing input filename")));
    let input = tempdir.path().join(filename);
    {
        try!(File::create(&input)
             .and_then(|mut f| f.write_all(&preprocessor_output)))
    }

    let mut cmd = creator.new_command_sync(&compiler.executable);
    cmd.arg("-c")
        .arg(&input)
        .arg(&format!("-Fo{}", output))
        .args(&parsed_args.common_args)
        .current_dir(cwd);

    let output = try!(run_input_output(cmd, None));
    Ok((cacheable, output))
}

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

    #[test]
    fn test_parse_arguments_simple() {
        match parse_arguments(&stringvec!["-c", "foo.c", "-Fofoo.obj"]) {
            CompilerArguments::Ok(ParsedArguments { input, extension, outputs, preprocessor_args, common_args }) => {
                assert!(true, "Parsed ok");
                assert_eq!("foo.c", input);
                assert_eq!("c", extension);
                assert_map_contains!(outputs, ("obj", "foo.obj"));
                //TODO: fix assert_map_contains to assert no extra keys!
                assert_eq!(1, outputs.len());
                assert!(preprocessor_args.is_empty());
                assert!(common_args.is_empty());
            }
            o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
        }
    }

    #[test]
    fn test_parse_arguments_extra() {
        match parse_arguments(&stringvec!["-c", "foo.c", "-foo", "-Fofoo.obj", "-bar"]) {
            CompilerArguments::Ok(ParsedArguments { input, extension, outputs, preprocessor_args, common_args }) => {
                assert!(true, "Parsed ok");
                assert_eq!("foo.c", input);
                assert_eq!("c", extension);
                assert_map_contains!(outputs, ("obj", "foo.obj"));
                //TODO: fix assert_map_contains to assert no extra keys!
                assert_eq!(1, outputs.len());
                assert!(preprocessor_args.is_empty());
                assert_eq!(common_args, &["-foo", "-bar"]);
            }
            o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
        }
    }

    #[test]
    fn test_parse_arguments_values() {
        match parse_arguments(&stringvec!["-c", "foo.c", "-FI", "file", "-Fofoo.obj"]) {
            CompilerArguments::Ok(ParsedArguments { input, extension, outputs, preprocessor_args, common_args }) => {
                assert!(true, "Parsed ok");
                assert_eq!("foo.c", input);
                assert_eq!("c", extension);
                assert_map_contains!(outputs, ("obj", "foo.obj"));
                //TODO: fix assert_map_contains to assert no extra keys!
                assert_eq!(1, outputs.len());
                assert!(preprocessor_args.is_empty());
                assert_eq!(common_args, &["-FI", "file"]);
            }
            o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
        }
    }

    #[test]
    fn test_parse_arguments_pdb() {
        match parse_arguments(&stringvec!["-c", "foo.c", "-Zi", "-Fdfoo.pdb", "-Fofoo.obj"]) {
            CompilerArguments::Ok(ParsedArguments { input, extension, outputs, preprocessor_args, common_args }) => {
                assert!(true, "Parsed ok");
                assert_eq!("foo.c", input);
                assert_eq!("c", extension);
                assert_map_contains!(outputs, ("obj", "foo.obj"), ("pdb", "foo.pdb"));
                //TODO: fix assert_map_contains to assert no extra keys!
                assert_eq!(2, outputs.len());
                assert!(preprocessor_args.is_empty());
                assert_eq!(common_args, &["-Zi", "-Fdfoo.pdb"]);
            }
            o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
        }
    }

    #[test]
    fn test_parse_arguments_empty_args() {
        assert_eq!(CompilerArguments::NotCompilation,
                   parse_arguments(&vec!()));
    }

    #[test]
    fn test_parse_arguments_not_compile() {
        assert_eq!(CompilerArguments::NotCompilation,
                   parse_arguments(&stringvec!["-Fofoo", "foo.c"]));
    }

    #[test]
    fn test_parse_arguments_too_many_inputs() {
        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "-Fofoo.obj", "bar.c"]));
    }

    #[test]
    fn test_parse_arguments_unsupported() {
        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "-Fofoo.obj", "-FA"]));

        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-Fa", "-c", "foo.c", "-Fofoo.obj"]));

        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "-FR", "-Fofoo.obj"]));
    }

    #[test]
    fn test_parse_arguments_response_file() {
        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "@foo", "-Fofoo.obj"]));
    }

    #[test]
    fn test_parse_arguments_missing_pdb() {
        assert_eq!(CompilerArguments::CannotCache,
                   parse_arguments(&stringvec!["-c", "foo.c", "-Zi", "-Fofoo.obj"]));
    }
}
<|endoftext|>


<commit_before>import check::{fn_ctxt, impl_self_ty, methods};

fn has_iface_bounds(tps: ~[ty::param_bounds]) -> bool {
    vec::any(tps, |bs| {
        vec::any(*bs, |b| {
            alt b { ty::bound_iface(_) { true } _ { false } }
        })
    })
}

fn lookup_vtables(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
                  bounds: @~[ty::param_bounds], substs: ty::substs,
                  allow_unsafe: bool) -> vtable_res {
    let tcx = fcx.ccx.tcx;
    let mut result = ~[], i = 0u;
    for substs.tps.each |ty| {
        for vec::each(*bounds[i]) |bound| {
            alt bound {
              ty::bound_iface(i_ty) {
                let i_ty = ty::subst(tcx, substs, i_ty);
                vec::push(result, lookup_vtable(fcx, isc, sp, ty, i_ty,
                                         allow_unsafe));
              }
              _ {}
            }
        }
        i += 1u;
    }
    @result
}

fn fixup_substs(fcx: @fn_ctxt, sp: span,
                id: ast::def_id, substs: ty::substs) -> ty::substs {
    let tcx = fcx.ccx.tcx;
    // use a dummy type just to package up the substs that need fixing up
    let t = ty::mk_iface(tcx, id, substs);
    let t_f = fixup_ty(fcx, sp, t);
    alt check ty::get(t_f).struct {
      ty::ty_iface(_, substs_f) { substs_f }
    }
}

fn relate_iface_tys(fcx: @fn_ctxt, sp: span,
                    exp_iface_ty: ty::t, act_iface_ty: ty::t) {
    demand::suptype(fcx, sp, exp_iface_ty, act_iface_ty)
}

/*
Look up the vtable to use when treating an item of type <t>
as if it has type <iface_ty>
*/
fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
                 ty: ty::t, iface_ty: ty::t, allow_unsafe: bool)
    -> vtable_origin {

    #debug["lookup_vtable(ty=%s, iface_ty=%s)",
           fcx.infcx.ty_to_str(ty), fcx.infcx.ty_to_str(iface_ty)];
    let _i = indenter();

    let tcx = fcx.ccx.tcx;
    let (iface_id, iface_substs) = alt check ty::get(iface_ty).struct {
      ty::ty_iface(did, substs) { (did, substs) }
    };
    let ty = fixup_ty(fcx, sp, ty);
    alt ty::get(ty).struct {
      ty::ty_param(n, did) {
        let mut n_bound = 0u;
        for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| {
            alt bound {
              ty::bound_send | ty::bound_copy | ty::bound_const {
                /* ignore */
              }
              ty::bound_iface(ity) {
                alt check ty::get(ity).struct {
                  ty::ty_iface(idid, substs) {
                    if iface_id == idid {
                        #debug("(checking vtable) @0 relating ty to iface ty
                                with did %?", idid);
                        relate_iface_tys(fcx, sp, iface_ty, ity);
                        ret vtable_param(n, n_bound);
                    }
                  }
                }
                n_bound += 1u;
              }
            }
        }
      }

      ty::ty_iface(did, substs) if iface_id == did {
        #debug("(checking vtable) @1 relating ty to iface ty with did %?",
               did);

        relate_iface_tys(fcx, sp, iface_ty, ty);
        if !allow_unsafe {
            for vec::each(*ty::iface_methods(tcx, did)) |m| {
                if ty::type_has_self(ty::mk_fn(tcx, m.fty)) {
                    tcx.sess.span_err(
                        sp, "a boxed iface with self types may not be \
                             passed as a bounded type");
                } else if (*m.tps).len() > 0u {
                    tcx.sess.span_err(
                        sp, "a boxed iface with generic methods may not \
                             be passed as a bounded type");

                }
            }
        }
        ret vtable_iface(did, substs.tps);
      }

      _ {
        let mut found = ~[];

        for list::each(isc) |impls| {
            /* For each impl in scope... */
            for vec::each(*impls) |im| {
                    // im = one specific impl
                    // find the iface that im implements (if any)
                    let of_ty = alt ty::impl_iface(tcx, im.did) {
                      some(of_ty) { of_ty }
                      _ { cont; }
                    };

                    // it must have the same id as the expected one
                    alt ty::get(of_ty).struct {
                      ty::ty_iface(id, _) if id != iface_id { cont; }
                      _ { /* ok */ }
                    }

                    // check whether the type unifies with the type
                    // that the impl is for, and continue if not
                    let {substs: substs, ty: for_ty} =
                        impl_self_ty(fcx, im.did);
                    let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
                    alt fcx.mk_subty(ty, for_ty) {
                      result::err(_) { cont; }
                      result::ok(()) { }
                    }

                    // check that desired iface type unifies
                    #debug("(checking vtable) @2 relating iface ty %s to \
                            of_ty %s",
                            fcx.infcx.ty_to_str(iface_ty),
                            fcx.infcx.ty_to_str(of_ty));
                    let of_ty = ty::subst(tcx, substs, of_ty);
                    relate_iface_tys(fcx, sp, iface_ty, of_ty);

                    // recursively process the bounds
                    let iface_tps = iface_substs.tps;
                    let substs_f = fixup_substs(fcx, sp, iface_id, substs);
                    connect_iface_tps(fcx, sp, substs_f.tps,
                                      iface_tps, im.did);
                    let subres = lookup_vtables(fcx, isc, sp,
                                                im_bs, substs_f, false);
                    vec::push(found,
                              vtable_static(im.did, substs_f.tps, subres));
                }

                alt found.len() {
                  0u { /* fallthrough */ }
                  1u { ret found[0]; }
                  _ {
                    fcx.ccx.tcx.sess.span_err(
                        sp, "multiple applicable methods in scope");
                    ret found[0];
                  }
                }
            }
          }
        }

        tcx.sess.span_fatal(
            sp, "failed to find an implementation of interface " +
            ty_to_str(tcx, iface_ty) + " for " +
            ty_to_str(tcx, ty));
    }

fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t) -> ty::t {
    let tcx = fcx.ccx.tcx;
    alt infer::resolve_deep(fcx.infcx, ty, force_all) {
      result::ok(new_type) { new_type }
      result::err(e) {
        tcx.sess.span_fatal(
            sp,
            #fmt["cannot determine a type \
                  for this bounded type parameter: %s",
                 infer::fixup_err_to_str(e)])
      }
    }
}

fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: ~[ty::t],
                     iface_tys: ~[ty::t], impl_did: ast::def_id) {
    let tcx = fcx.ccx.tcx;
    let ity = option::get(ty::impl_iface(tcx, impl_did));
    let iface_ty = ty::subst_tps(tcx, impl_tys, ity);
    #debug("(connect iface tps) iface type is %?, impl did is %?",
           ty::get(iface_ty).struct, impl_did);
    alt check ty::get(iface_ty).struct {
      ty::ty_iface(_, substs) {
        vec::iter2(substs.tps, iface_tys,
                   |a, b| demand::suptype(fcx, sp, a, b));
      }
    }
}

fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
    let cx = fcx.ccx;
    alt ex.node {
      ast::expr_path(*) {
        alt fcx.opt_node_ty_substs(ex.id) {
          some(substs) {
            let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
            let item_ty = ty::lookup_item_type(cx.tcx, did);
            if has_iface_bounds(*item_ty.bounds) {
                let impls = cx.impl_map.get(ex.id);
                cx.vtable_map.insert(ex.id, lookup_vtables(
                    fcx, impls, ex.span,
                    item_ty.bounds, substs, false));
            }
          }
          _ {}
        }
      }
      // Must resolve bounds on methods with bounded params
      ast::expr_field(*) | ast::expr_binary(*) |
      ast::expr_unary(*) | ast::expr_assign_op(*) |
      ast::expr_index(*) {
        alt cx.method_map.find(ex.id) {
          some({origin: method_static(did), _}) {
            let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
            if has_iface_bounds(*bounds) {
                let callee_id = alt ex.node {
                  ast::expr_field(_, _, _) { ex.id }
                  _ { ast_util::op_expr_callee_id(ex) }
                };
                let substs = fcx.node_ty_substs(callee_id);
                let iscs = cx.impl_map.get(ex.id);
                cx.vtable_map.insert(callee_id, lookup_vtables(
                    fcx, iscs, ex.span, bounds, substs, false));
            }
          }
          _ {}
        }
      }
      ast::expr_cast(src, _) {
        let target_ty = fcx.expr_ty(ex);
        alt ty::get(target_ty).struct {
          ty::ty_iface(*) {
            /* Casting to an interface type.
            Look up all impls for the cast expr...
            */
            let impls = cx.impl_map.get(ex.id);
            /*
            Look up vtables for the type we're casting to,
            passing in the source and target type
            */
            let vtable = lookup_vtable(fcx, impls, ex.span,
                                       fcx.expr_ty(src), target_ty,
                                       true);
            /*
            Map this expression to that vtable (that is: "ex has
            vtable <vtable>")
            */
            cx.vtable_map.insert(ex.id, @~[vtable]);
          }
          _ {}
        }
      }
      _ {}
    }
    visit::visit_expr(ex, fcx, v);
}

// Detect points where an interface-bounded type parameter is
// instantiated, resolve the impls for the parameters.
fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) {
    visit::visit_block(bl, fcx, visit::mk_vt(@{
        visit_expr: resolve_expr,
        visit_item: fn@(_i: @ast::item, &&_e: @fn_ctxt,
                        _v: visit::vt<@fn_ctxt>) {}
        with *visit::default_visitor()
    }));
}

<commit_msg>Fix some indentation in check::vtable.<commit_after>import check::{fn_ctxt, impl_self_ty, methods};

fn has_iface_bounds(tps: ~[ty::param_bounds]) -> bool {
    vec::any(tps, |bs| {
        vec::any(*bs, |b| {
            alt b { ty::bound_iface(_) { true } _ { false } }
        })
    })
}

fn lookup_vtables(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
                  bounds: @~[ty::param_bounds], substs: ty::substs,
                  allow_unsafe: bool) -> vtable_res {
    let tcx = fcx.ccx.tcx;
    let mut result = ~[], i = 0u;
    for substs.tps.each |ty| {
        for vec::each(*bounds[i]) |bound| {
            alt bound {
              ty::bound_iface(i_ty) {
                let i_ty = ty::subst(tcx, substs, i_ty);
                vec::push(result, lookup_vtable(fcx, isc, sp, ty, i_ty,
                                         allow_unsafe));
              }
              _ {}
            }
        }
        i += 1u;
    }
    @result
}

fn fixup_substs(fcx: @fn_ctxt, sp: span,
                id: ast::def_id, substs: ty::substs) -> ty::substs {
    let tcx = fcx.ccx.tcx;
    // use a dummy type just to package up the substs that need fixing up
    let t = ty::mk_iface(tcx, id, substs);
    let t_f = fixup_ty(fcx, sp, t);
    alt check ty::get(t_f).struct {
      ty::ty_iface(_, substs_f) { substs_f }
    }
}

fn relate_iface_tys(fcx: @fn_ctxt, sp: span,
                    exp_iface_ty: ty::t, act_iface_ty: ty::t) {
    demand::suptype(fcx, sp, exp_iface_ty, act_iface_ty)
}

/*
Look up the vtable to use when treating an item of type <t>
as if it has type <iface_ty>
*/
fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
                 ty: ty::t, iface_ty: ty::t, allow_unsafe: bool)
    -> vtable_origin {

    #debug["lookup_vtable(ty=%s, iface_ty=%s)",
           fcx.infcx.ty_to_str(ty), fcx.infcx.ty_to_str(iface_ty)];
    let _i = indenter();

    let tcx = fcx.ccx.tcx;
    let (iface_id, iface_substs) = alt check ty::get(iface_ty).struct {
      ty::ty_iface(did, substs) { (did, substs) }
    };
    let ty = fixup_ty(fcx, sp, ty);
    alt ty::get(ty).struct {
      ty::ty_param(n, did) {
        let mut n_bound = 0u;
        for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| {
            alt bound {
              ty::bound_send | ty::bound_copy | ty::bound_const {
                /* ignore */
              }
              ty::bound_iface(ity) {
                alt check ty::get(ity).struct {
                  ty::ty_iface(idid, substs) {
                    if iface_id == idid {
                        #debug("(checking vtable) @0 relating ty to iface ty
                                with did %?", idid);
                        relate_iface_tys(fcx, sp, iface_ty, ity);
                        ret vtable_param(n, n_bound);
                    }
                  }
                }
                n_bound += 1u;
              }
            }
        }
      }

      ty::ty_iface(did, substs) if iface_id == did {
        #debug("(checking vtable) @1 relating ty to iface ty with did %?",
               did);

        relate_iface_tys(fcx, sp, iface_ty, ty);
        if !allow_unsafe {
            for vec::each(*ty::iface_methods(tcx, did)) |m| {
                if ty::type_has_self(ty::mk_fn(tcx, m.fty)) {
                    tcx.sess.span_err(
                        sp, "a boxed iface with self types may not be \
                             passed as a bounded type");
                } else if (*m.tps).len() > 0u {
                    tcx.sess.span_err(
                        sp, "a boxed iface with generic methods may not \
                             be passed as a bounded type");

                }
            }
        }
        ret vtable_iface(did, substs.tps);
      }

      _ {
        let mut found = ~[];

        for list::each(isc) |impls| {
            /* For each impl in scope... */
            for vec::each(*impls) |im| {
                // im = one specific impl
                // find the iface that im implements (if any)
                let of_ty = alt ty::impl_iface(tcx, im.did) {
                  some(of_ty) { of_ty }
                  _ { cont; }
                };

                // it must have the same id as the expected one
                alt ty::get(of_ty).struct {
                  ty::ty_iface(id, _) if id != iface_id { cont; }
                  _ { /* ok */ }
                }

                // check whether the type unifies with the type
                // that the impl is for, and continue if not
                let {substs: substs, ty: for_ty} =
                    impl_self_ty(fcx, im.did);
                let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
                alt fcx.mk_subty(ty, for_ty) {
                  result::err(_) { cont; }
                  result::ok(()) { }
                }

                // check that desired iface type unifies
                #debug("(checking vtable) @2 relating iface ty %s to \
                        of_ty %s",
                       fcx.infcx.ty_to_str(iface_ty),
                       fcx.infcx.ty_to_str(of_ty));
                let of_ty = ty::subst(tcx, substs, of_ty);
                relate_iface_tys(fcx, sp, iface_ty, of_ty);

                // recursively process the bounds
                let iface_tps = iface_substs.tps;
                let substs_f = fixup_substs(fcx, sp, iface_id, substs);
                connect_iface_tps(fcx, sp, substs_f.tps,
                                  iface_tps, im.did);
                let subres = lookup_vtables(fcx, isc, sp,
                                            im_bs, substs_f, false);
                vec::push(found,
                          vtable_static(im.did, substs_f.tps, subres));
            }

            alt found.len() {
              0u { /* fallthrough */ }
              1u { ret found[0]; }
              _ {
                fcx.ccx.tcx.sess.span_err(
                    sp, "multiple applicable methods in scope");
                ret found[0];
              }
            }
        }
      }
    }

    tcx.sess.span_fatal(
        sp, "failed to find an implementation of interface " +
        ty_to_str(tcx, iface_ty) + " for " +
        ty_to_str(tcx, ty));
}

fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t) -> ty::t {
    let tcx = fcx.ccx.tcx;
    alt infer::resolve_deep(fcx.infcx, ty, force_all) {
      result::ok(new_type) { new_type }
      result::err(e) {
        tcx.sess.span_fatal(
            sp,
            #fmt["cannot determine a type \
                  for this bounded type parameter: %s",
                 infer::fixup_err_to_str(e)])
      }
    }
}

fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: ~[ty::t],
                     iface_tys: ~[ty::t], impl_did: ast::def_id) {
    let tcx = fcx.ccx.tcx;
    let ity = option::get(ty::impl_iface(tcx, impl_did));
    let iface_ty = ty::subst_tps(tcx, impl_tys, ity);
    #debug("(connect iface tps) iface type is %?, impl did is %?",
           ty::get(iface_ty).struct, impl_did);
    alt check ty::get(iface_ty).struct {
      ty::ty_iface(_, substs) {
        vec::iter2(substs.tps, iface_tys,
                   |a, b| demand::suptype(fcx, sp, a, b));
      }
    }
}

fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
    let cx = fcx.ccx;
    alt ex.node {
      ast::expr_path(*) {
        alt fcx.opt_node_ty_substs(ex.id) {
          some(substs) {
            let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
            let item_ty = ty::lookup_item_type(cx.tcx, did);
            if has_iface_bounds(*item_ty.bounds) {
                let impls = cx.impl_map.get(ex.id);
                cx.vtable_map.insert(ex.id, lookup_vtables(
                    fcx, impls, ex.span,
                    item_ty.bounds, substs, false));
            }
          }
          _ {}
        }
      }
      // Must resolve bounds on methods with bounded params
      ast::expr_field(*) | ast::expr_binary(*) |
      ast::expr_unary(*) | ast::expr_assign_op(*) |
      ast::expr_index(*) {
        alt cx.method_map.find(ex.id) {
          some({origin: method_static(did), _}) {
            let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
            if has_iface_bounds(*bounds) {
                let callee_id = alt ex.node {
                  ast::expr_field(_, _, _) { ex.id }
                  _ { ast_util::op_expr_callee_id(ex) }
                };
                let substs = fcx.node_ty_substs(callee_id);
                let iscs = cx.impl_map.get(ex.id);
                cx.vtable_map.insert(callee_id, lookup_vtables(
                    fcx, iscs, ex.span, bounds, substs, false));
            }
          }
          _ {}
        }
      }
      ast::expr_cast(src, _) {
        let target_ty = fcx.expr_ty(ex);
        alt ty::get(target_ty).struct {
          ty::ty_iface(*) {
            /* Casting to an interface type.
            Look up all impls for the cast expr...
            */
            let impls = cx.impl_map.get(ex.id);
            /*
            Look up vtables for the type we're casting to,
            passing in the source and target type
            */
            let vtable = lookup_vtable(fcx, impls, ex.span,
                                       fcx.expr_ty(src), target_ty,
                                       true);
            /*
            Map this expression to that vtable (that is: "ex has
            vtable <vtable>")
            */
            cx.vtable_map.insert(ex.id, @~[vtable]);
          }
          _ {}
        }
      }
      _ {}
    }
    visit::visit_expr(ex, fcx, v);
}

// Detect points where an interface-bounded type parameter is
// instantiated, resolve the impls for the parameters.
fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) {
    visit::visit_block(bl, fcx, visit::mk_vt(@{
        visit_expr: resolve_expr,
        visit_item: fn@(_i: @ast::item, &&_e: @fn_ctxt,
                        _v: visit::vt<@fn_ctxt>) {}
        with *visit::default_visitor()
    }));
}

<|endoftext|>


<commit_before>// Test that `-Zpgo-gen` creates expected instrumentation artifacts in LLVM IR.

// needs-profiler-support
// compile-flags: -Z pgo-gen -Ccodegen-units=1

// CHECK: @__llvm_profile_raw_version =
// CHECK: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = private global
// CHECK: @__profd_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = private global
// CHECK: @__profc_{{.*}}pgo_instrumentation{{.*}}main{{.*}} = private global
// CHECK: @__profd_{{.*}}pgo_instrumentation{{.*}}main{{.*}} = private global
// CHECK: @__llvm_profile_filename = {{.*}}"default_%m.profraw\00"{{.*}}

#[inline(never)]
fn some_function() {

}

fn main() {
    some_function();
}
<commit_msg>Make test/codegen/pgo-instrumentation.rs work reliably on Windows.<commit_after>// Test that `-Zpgo-gen` creates expected instrumentation artifacts in LLVM IR.
// Compiling with `-Cpanic=abort` because PGO+unwinding isn't supported on all platforms.

// needs-profiler-support
// compile-flags: -Z pgo-gen -Ccodegen-units=1 -Cpanic=abort

// CHECK: @__llvm_profile_raw_version =
// CHECK: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = private global
// CHECK: @__profd_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = private global
// CHECK: @__profc_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = private global
// CHECK: @__profd_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = private global
// CHECK: @__llvm_profile_filename = {{.*}}"default_%m.profraw\00"{{.*}}

#![crate_type="lib"]

#[inline(never)]
fn some_function() {

}

pub fn some_other_function() {
    some_function();
}
<|endoftext|>


<commit_before>use irc::client::prelude::*;
use irc::error::IrcError;

use std::collections::HashMap;
use std::sync::Mutex;

use plugin::*;

macro_rules! try_lock {
    ( $m:expr ) => {
        match $m.lock() {
            Ok(guard) => guard,
            Err(poisoned) => poisoned.into_inner(),
        }
    }
}

#[derive(PluginName, Default, Debug)]
pub struct Tell {
    tells: Mutex<HashMap<String, TellMessage>>,
}

#[derive(Default, Debug)]
struct TellMessage {
    sender: String,
    // TODO Add time
    message: String,
}

impl Tell {
    pub fn new() -> Tell {
        Tell {
            tells: Mutex::new(HashMap::new()),
        }
    }

    fn tell_command(&self, client: &IrcClient, command: &PluginCommand) -> Result<&str, String> {
        if command.tokens.len() < 2 {
            return Err(self.invalid_command(client));
        }

        let receiver = command.tokens[0].to_string();
        let sender = command.source.to_owned();

        if receiver == sender {
            return Err(String::from("That's your name!"));
        }

        if command.source != command.target {
            if let Some(users) = client.list_users(&command.target) {
                if users.iter().any(|u| u.get_nickname() == receiver) {
                    return Err(format!("{} is in this channel.", receiver));
                }
            }
        }

        let message = command.tokens[1..].join(" ");
        let tell = TellMessage {
            sender: sender,
            message: message,
        };

        try_lock!(self.tells).insert(receiver.clone(), tell);

        Ok("Got it!")
    }

    fn send_tell(&self, client: &IrcClient, receiver: &str) -> ExecutionStatus {
        let mut tells = try_lock!(self.tells);
        if let Some(tell) = tells.get(receiver) {
            if let Err(e) = client.send_notice(
                receiver,
                &format!("Tell from {}: {}", tell.sender, tell.message),
            ) {
                return ExecutionStatus::Err(e);
            }
            debug!("Sent {:?} from {:?} to {:?}", tell.message, tell.sender, receiver);
        }
        tells.remove(receiver);
        ExecutionStatus::Done
    }

    fn invalid_command(&self, client: &IrcClient) -> String {
        format!(
            "Incorrect Command. \
             Send \"{} tell help\" for help.",
            client.current_nickname()
        )
    }

    fn help(&self, client: &IrcClient) -> String {
        format!(
            "usage: {} tell user message\r\n\
             example: {0} tell Foobar Hello!",
            client.current_nickname()
        )
    }
}

impl Plugin for Tell {
    fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::JOIN(_, _, _) => self.send_tell(client, message.source_nickname().unwrap()),
            Command::PRIVMSG(_, _) => self.send_tell(client, message.source_nickname().unwrap()),
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), IrcError> {
        panic!("Tell should not use threading")
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), IrcError> {
        if command.tokens.is_empty() {
            return client.send_notice(&command.source, &self.invalid_command(client));
        }

        match command.tokens[0].as_ref() {
            "help" => client.send_notice(&command.source, &self.help(client)),
            _ => match self.tell_command(client, &command) {
                Ok(msg) => client.send_notice(&command.source, msg),
                Err(msg) => client.send_notice(&command.source, &msg),
            },
        }
    }

    fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
        Err(String::from("This Plugin does not implement any commands."))
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Save multiple tells per person<commit_after>use irc::client::prelude::*;
use irc::error::IrcError;

use std::collections::HashMap;
use std::sync::Mutex;

use plugin::*;

macro_rules! try_lock {
    ( $m:expr ) => {
        match $m.lock() {
            Ok(guard) => guard,
            Err(poisoned) => poisoned.into_inner(),
        }
    }
}

#[derive(PluginName, Default, Debug)]
pub struct Tell {
    tells: Mutex<HashMap<String, Vec<TellMessage>>>,
}

#[derive(Default, Debug)]
struct TellMessage {
    sender: String,
    // TODO Add time
    message: String,
}

impl Tell {
    pub fn new() -> Tell {
        Tell {
            tells: Mutex::new(HashMap::new()),
        }
    }

    fn tell_command(&self, client: &IrcClient, command: &PluginCommand) -> Result<&str, String> {
        if command.tokens.len() < 2 {
            return Err(self.invalid_command(client));
        }

        let receiver = command.tokens[0].to_string();
        let sender = command.source.to_owned();

        if receiver == sender {
            return Err(String::from("That's your name!"));
        }

        if command.source != command.target {
            if let Some(users) = client.list_users(&command.target) {
                if users.iter().any(|u| u.get_nickname() == receiver) {
                    return Err(format!("{} is in this channel.", receiver));
                }
            }
        }

        let message = command.tokens[1..].join(" ");
        let tell = TellMessage {
            sender: sender,
            message: message,
        };

        let mut tells = try_lock!(self.tells);
        let tell_messages = tells.entry(receiver).or_insert(Vec::with_capacity(3));
        (*tell_messages).push(tell);

        Ok("Got it!")
    }

    fn send_tell(&self, client: &IrcClient, receiver: &str) -> ExecutionStatus {
        let mut tells = try_lock!(self.tells);
        if let Some(tell_messages) = tells.get_mut(receiver) {
            for tell in tell_messages {
                if let Err(e) = client.send_notice(
                    receiver,
                    &format!("Tell from {}: {}", tell.sender, tell.message),
                ) {
                    return ExecutionStatus::Err(e);
                }
                debug!("Sent {:?} from {:?} to {:?}", tell.message, tell.sender, receiver);
            }
        }
        tells.remove(receiver);
        ExecutionStatus::Done
    }

    fn invalid_command(&self, client: &IrcClient) -> String {
        format!(
            "Incorrect Command. \
             Send \"{} tell help\" for help.",
            client.current_nickname()
        )
    }

    fn help(&self, client: &IrcClient) -> String {
        format!(
            "usage: {} tell user message\r\n\
             example: {0} tell Foobar Hello!",
            client.current_nickname()
        )
    }
}

impl Plugin for Tell {
    fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::JOIN(_, _, _) => self.send_tell(client, message.source_nickname().unwrap()),
            Command::PRIVMSG(_, _) => self.send_tell(client, message.source_nickname().unwrap()),
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), IrcError> {
        panic!("Tell should not use threading")
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), IrcError> {
        if command.tokens.is_empty() {
            return client.send_notice(&command.source, &self.invalid_command(client));
        }

        match command.tokens[0].as_ref() {
            "help" => client.send_notice(&command.source, &self.help(client)),
            _ => match self.tell_command(client, &command) {
                Ok(msg) => client.send_notice(&command.source, msg),
                Err(msg) => client.send_notice(&command.source, &msg),
            },
        }
    }

    fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
        Err(String::from("This Plugin does not implement any commands."))
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>


<commit_before>use std::env;
use std::time::{Instant, Duration};

const PRIMES_COUNT: u32 = 10000000;

fn get_primes7(count: u32) -> Vec<u32> {
    if count < 2 {
        return vec![];
    } else if count == 2 {
        return vec![2];
    }

    let mut s = Vec::with_capacity(count as usize / 2);
    let mut i = 3;
    while i < count+1 {
        s.push(i);
        i += 2;
    }

    let mroot = (count as f32).sqrt() as u32;
    let half = s.len() as u32;

    let mut i: u32 = 0;
    let mut m: u32 = 3;

    while m <= mroot {
        if s.get(i as usize).is_some() && s[i as usize] != 0 {
            let mut j = (m*m-3)/2;
            s[j as usize] = 0;
            while j < half {
                s[j as usize] = 0;
                j += m;
            }
        }
        i += 1;
        m = 2*i+3;
    }

    //s.push(2);
    //s.retain(|&x| x != 0);
    //s

    //let mut res = Vec::with_capacity(count as usize /2);
    let mut res = Vec::new();
    res.push(2);
    res.extend(s.into_iter().filter(|x| *x != 0));
    res
}

fn main() {
    let run_time_secs = match env::var("RUN_TIME") {
        Ok(v) => match v.parse::<u32>() {
            Ok(i) => i,
            Err(err) => panic!("RUN_TIME environment variable error: {}", err),
        },
        Err(err) => panic!("RUN_TIME environment variable error: {}", err),
    };

    let run_time = Duration::new(run_time_secs as u64, 0);
    let start = Instant::now();

    while start.elapsed() < run_time {
	    let primes = get_primes7(PRIMES_COUNT);
        println!("Found {} prime numbers.", primes.len());
    }
}

<commit_msg>Do not preallocate the vec to the known size so we are fair and do what other tests are doing<commit_after>use std::env;
use std::time::{Instant, Duration};

const PRIMES_COUNT: u32 = 10000000;

fn get_primes7(count: u32) -> Vec<u32> {
    if count < 2 {
        return vec![];
    } else if count == 2 {
        return vec![2];
    }

    let mut s = Vec::new();
    let mut i = 3;
    while i < count+1 {
        s.push(i);
        i += 2;
    }

    let mroot = (count as f32).sqrt() as u32;
    let half = s.len() as u32;

    let mut i: u32 = 0;
    let mut m: u32 = 3;

    while m <= mroot {
        if s.get(i as usize).is_some() && s[i as usize] != 0 {
            let mut j = (m*m-3)/2;
            s[j as usize] = 0;
            while j < half {
                s[j as usize] = 0;
                j += m;
            }
        }
        i += 1;
        m = 2*i+3;
    }

    let mut res = Vec::new();
    res.push(2);
    res.extend(s.into_iter().filter(|x| *x != 0));
    res
}

fn main() {
    let run_time_secs = match env::var("RUN_TIME") {
        Ok(v) => match v.parse::<u32>() {
            Ok(i) => i,
            Err(err) => panic!("RUN_TIME environment variable error: {}", err),
        },
        Err(err) => panic!("RUN_TIME environment variable error: {}", err),
    };

    let run_time = Duration::new(run_time_secs as u64, 0);
    let start = Instant::now();

    while start.elapsed() < run_time {
	    let primes = get_primes7(PRIMES_COUNT);
        println!("Found {} prime numbers.", primes.len());
    }
}

<|endoftext|>