<commit_before>use linked_hash_map::LinkedHashMap;
use std::collections::HashSet;

use crate::options::{ImportStyle, Options, StringTransform};
use crate::shape::{self, Shape};
use crate::to_singular::to_singular;
use crate::util::{kebab_case, lower_camel_case, snake_case, type_case};

#[derive(PartialEq, PartialOrd, Ord, Eq, Hash, Clone, Copy)]
enum Import {
    Any,
    Optional,
    BaseModel,
    Field,
}

impl Import {
    fn pair(&self) -> (&'static str, &'static str) {
        match self {
            Import::Any => ("typing", "Any"),
            Import::Optional => ("typing", "Optional"),
            Import::BaseModel => ("pydantic", "BaseModel"),
            Import::Field => ("pydantic", "Field"),
        }
    }
    fn identifier(&self) -> &'static str {
        self.pair().1
    }
    fn qualified(&self) -> String {
        let (module, identifier) = self.pair();
        format!("{}.{}", module, identifier)
    }
}

struct Ctxt {
    options: Options,
    type_names: HashSet<String>,
    imports: HashSet<Import>,
    created_classes: Vec<(Shape, Ident)>,
}

pub type Ident = String;
pub type Code = String;

pub fn python_types(name: &str, shape: &Shape, options: Options) -> Code {
    let mut ctxt = Ctxt {
        options,
        type_names: HashSet::new(),
        imports: HashSet::new(),
        created_classes: Vec::new(),
    };

    if !matches!(shape, Shape::Struct { .. }) {
        // reserve the requested name
        ctxt.type_names.insert(name.to_string());
    }

    let (ident, code) = type_from_shape(&mut ctxt, name, shape);
    let mut code = code.unwrap_or_default();

    if !ctxt.imports.is_empty() {
        let mut imports: Vec<_> = ctxt.imports.drain().collect();
        imports.sort();
        let mut import_code = String::new();
        for import in imports {
            match ctxt.options.import_style {
                ImportStyle::AssumeExisting => {}
                ImportStyle::AddImports => {
                    let (module, identifier) = import.pair();
                    import_code += &format!("from {} import {}\n", module, identifier);
                }
                ImportStyle::QualifiedPaths => {
                    let (module, identifier) = import.pair();
                    import_code += &format!("import {}.{}\n", module, identifier);
                }
            }
        }
        import_code += "\n\n";
        code = import_code + &code;
    }

    if ident != name {
        code += &format!("\n\n{} = {}", name, ident);
    }
    code
}

fn type_from_shape(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> (Ident, Option<Code>) {
    use crate::shape::Shape::*;
    match shape {
        Null | Any | Bottom => (import(ctxt, Import::Any), None),
        Bool => ("bool".into(), None),
        StringT => ("str".into(), None),
        Integer => ("int".into(), None),
        Floating => ("float".into(), None),
        Tuple(shapes, _n) => {
            let folded = shape::fold_shapes(shapes.clone());
            if folded == Any && shapes.iter().any(|s| s != &Any) {
                generate_tuple_type(ctxt, path, shapes)
            } else {
                generate_vec_type(ctxt, path, &folded)
            }
        }
        VecT { elem_type: e } => generate_vec_type(ctxt, path, e),
        Struct { fields } => generate_data_class(ctxt, path, fields, shape),
        MapT { val_type: v } => generate_map_type(ctxt, path, v),
        Opaque(t) => (t.clone(), None),
        Optional(e) => {
            let (inner, defs) = type_from_shape(ctxt, path, e);
            if ctxt.options.use_default_for_missing_fields {
                (inner, defs)
            } else {
                let optional = import(ctxt, Import::Optional);
                (format!("{}[{}]", optional, inner), defs)
            }
        }
    }
}

fn generate_vec_type(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> (Ident, Option<Code>) {
    let singular = to_singular(path);
    let (inner, defs) = type_from_shape(ctxt, &singular, shape);
    (format!("list[{}]", inner), defs)
}

fn generate_map_type(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> (Ident, Option<Code>) {
    let singular = to_singular(path);
    let (inner, defs) = type_from_shape(ctxt, &singular, shape);
    (format!("dict[str, {}]", inner), defs)
}

fn generate_tuple_type(ctxt: &mut Ctxt, path: &str, shapes: &[Shape]) -> (Ident, Option<Code>) {
    let mut types = Vec::new();
    let mut defs = Vec::new();

    for shape in shapes {
        let (typ, def) = type_from_shape(ctxt, path, shape);
        types.push(typ);
        if let Some(code) = def {
            defs.push(code)
        }
    }

    (
        format!("tuple[{}]", types.join(", ")),
        Some(defs.join("\n\n")),
    )
}

fn field_name(name: &str, used_names: &HashSet<String>) -> Ident {
    type_or_field_name(name, used_names, "field", snake_case)
}

fn type_name(name: &str, used_names: &HashSet<String>) -> Ident {
    type_or_field_name(name, used_names, "GeneratedType", type_case)
}

// https://docs.python.org/3/reference/lexical_analysis.html#keywords
#[rustfmt::skip]
const PYTHON_KEYWORDS: &[&str] = &[
    "False", "None", "True",
    "and", "as", "assert", "async", "await", "break", "class", "continue",
    "def", "del", "elif", "else", "except", "finally", "for", "from", "global",
    "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass",
    "raise", "return", "try", "while", "with", "yield",
];

fn type_or_field_name(
    name: &str,
    used_names: &HashSet<String>,
    default_name: &str,
    case_fn: fn(&str) -> String,
) -> Ident {
    let name = name.trim();
    let mut output_name = case_fn(name);
    if PYTHON_KEYWORDS.contains(&&*output_name) {
        output_name.push_str("_field");
    }
    if output_name.is_empty() {
        output_name.push_str(default_name);
    }
    if let Some(c) = output_name.chars().next() {
        if c.is_ascii_digit() {
            output_name = String::from("n") + &output_name;
        }
    }
    if !used_names.contains(&output_name) {
        return output_name;
    }
    for n in 2.. {
        let temp = format!("{}{}", output_name, n);
        if !used_names.contains(&temp) {
            return temp;
        }
    }
    unreachable!()
}

fn import(ctxt: &mut Ctxt, import: Import) -> String {
    ctxt.imports.insert(import);
    match ctxt.options.import_style {
        ImportStyle::QualifiedPaths => import.qualified(),
        _ => import.identifier().into(),
    }
}

fn generate_data_class(
    ctxt: &mut Ctxt,
    path: &str,
    field_shapes: &LinkedHashMap<String, Shape>,
    containing_shape: &Shape,
) -> (Ident, Option<Code>) {
    for (created_for_shape, ident) in ctxt.created_classes.iter() {
        if created_for_shape.is_acceptable_substitution_for(containing_shape) {
            return (ident.into(), None);
        }
    }

    let type_name = type_name(path, &ctxt.type_names);
    ctxt.type_names.insert(type_name.clone());
    ctxt.created_classes
        .push((containing_shape.clone(), type_name.clone()));

    let mut field_names = HashSet::new();
    let mut defs = Vec::new();

    let fields: Vec<Code> = field_shapes
        .iter()
        .map(|(name, typ)| {
            let field_name = field_name(name, &field_names);
            field_names.insert(field_name.clone());

            let (field_type, child_defs) = type_from_shape(ctxt, name, typ);

            if let Some(code) = child_defs {
                defs.push(code);
            }

            let mut field_code = String::new();
            let transformed = apply_transform(ctxt, &field_name, &name);
            if transformed != field_name {
                field_code += &format!(" = {}(alias = \"{}\")", import(ctxt, Import::Field), transformed)
            }

            format!("    {}: {}{}", field_name, field_type, field_code)
        })
        .collect();

    let mut code = String::new();

    code += &format!(
        "class {}({}):\n",
        type_name,
        import(ctxt, Import::BaseModel)
    );

    if fields.is_empty() {
        code += "    pass\n";
    } else {
        code += &fields.join("\n");
        code += "\n";
    }

    if !defs.is_empty() {
        let mut d = defs.join("\n\n");
        d += "\n\n";
        d += &code;
        code = d;
    }

    (type_name, Some(code))
}

fn apply_transform(ctxt: &Ctxt, field_name: &str, name: &str) -> String {
    match ctxt.options.property_name_format {
        Some(StringTransform::LowerCase) => field_name.to_ascii_lowercase(),
        Some(StringTransform::PascalCase) => type_case(field_name),
        Some(StringTransform::SnakeCase) => snake_case(field_name),
        Some(StringTransform::KebabCase) => kebab_case(field_name),
        Some(StringTransform::UpperCase) => field_name.to_ascii_uppercase(),
        Some(StringTransform::CamelCase) => lower_camel_case(field_name),
        Some(StringTransform::ScreamingSnakeCase) => snake_case(field_name).to_ascii_uppercase(),
        Some(StringTransform::ScreamingKebabCase) => kebab_case(field_name).to_ascii_uppercase(),
        None => name.to_string(),
    }
}

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

    #[test]
    fn field_names_test() {
        fn field_name_test(from: &str, to: &str) {
            assert_eq!(
                field_name(from, &HashSet::new()),
                to.to_string(),
                r#"From "{}" to "{}""#,
                from,
                to
            );
        }

        field_name_test("valid", "valid");
        field_name_test("1", "n1");
        field_name_test("+1", "n1");
        field_name_test("", "field");
        field_name_test("def", "def_field");
    }
}
<commit_msg>shared: Fix python module import.<commit_after>use linked_hash_map::LinkedHashMap;
use std::collections::HashSet;

use crate::options::{ImportStyle, Options, StringTransform};
use crate::shape::{self, Shape};
use crate::to_singular::to_singular;
use crate::util::{kebab_case, lower_camel_case, snake_case, type_case};

#[derive(PartialEq, PartialOrd, Ord, Eq, Hash, Clone, Copy)]
enum Import {
    Any,
    Optional,
    BaseModel,
    Field,
}

impl Import {
    fn pair(&self) -> (&'static str, &'static str) {
        match self {
            Import::Any => ("typing", "Any"),
            Import::Optional => ("typing", "Optional"),
            Import::BaseModel => ("pydantic", "BaseModel"),
            Import::Field => ("pydantic", "Field"),
        }
    }
    fn module(&self) -> &'static str {
        self.pair().0
    }
    fn identifier(&self) -> &'static str {
        self.pair().1
    }
    fn qualified(&self) -> String {
        let (module, identifier) = self.pair();
        format!("{}.{}", module, identifier)
    }
}

struct Ctxt {
    options: Options,
    type_names: HashSet<String>,
    imports: HashSet<Import>,
    created_classes: Vec<(Shape, Ident)>,
}

pub type Ident = String;
pub type Code = String;

pub fn python_types(name: &str, shape: &Shape, options: Options) -> Code {
    let mut ctxt = Ctxt {
        options,
        type_names: HashSet::new(),
        imports: HashSet::new(),
        created_classes: Vec::new(),
    };

    if !matches!(shape, Shape::Struct { .. }) {
        // reserve the requested name
        ctxt.type_names.insert(name.to_string());
    }

    let (ident, code) = type_from_shape(&mut ctxt, name, shape);
    let mut code = code.unwrap_or_default();

    if !ctxt.imports.is_empty() {
        let mut imports: Vec<_> = ctxt.imports.drain().collect();
        imports.sort();
        let mut import_code = String::new();
        for import in imports {
            match ctxt.options.import_style {
                ImportStyle::AssumeExisting => {}
                ImportStyle::AddImports => {
                    let (module, identifier) = import.pair();
                    import_code += &format!("from {} import {}\n", module, identifier);
                }
                ImportStyle::QualifiedPaths => {
                    import_code += &format!("import {}\n", import.module());
                }
            }
        }
        import_code += "\n\n";
        code = import_code + &code;
    }

    if ident != name {
        code += &format!("\n\n{} = {}", name, ident);
    }
    code
}

fn type_from_shape(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> (Ident, Option<Code>) {
    use crate::shape::Shape::*;
    match shape {
        Null | Any | Bottom => (import(ctxt, Import::Any), None),
        Bool => ("bool".into(), None),
        StringT => ("str".into(), None),
        Integer => ("int".into(), None),
        Floating => ("float".into(), None),
        Tuple(shapes, _n) => {
            let folded = shape::fold_shapes(shapes.clone());
            if folded == Any && shapes.iter().any(|s| s != &Any) {
                generate_tuple_type(ctxt, path, shapes)
            } else {
                generate_vec_type(ctxt, path, &folded)
            }
        }
        VecT { elem_type: e } => generate_vec_type(ctxt, path, e),
        Struct { fields } => generate_data_class(ctxt, path, fields, shape),
        MapT { val_type: v } => generate_map_type(ctxt, path, v),
        Opaque(t) => (t.clone(), None),
        Optional(e) => {
            let (inner, defs) = type_from_shape(ctxt, path, e);
            if ctxt.options.use_default_for_missing_fields {
                (inner, defs)
            } else {
                let optional = import(ctxt, Import::Optional);
                (format!("{}[{}]", optional, inner), defs)
            }
        }
    }
}

fn generate_vec_type(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> (Ident, Option<Code>) {
    let singular = to_singular(path);
    let (inner, defs) = type_from_shape(ctxt, &singular, shape);
    (format!("list[{}]", inner), defs)
}

fn generate_map_type(ctxt: &mut Ctxt, path: &str, shape: &Shape) -> (Ident, Option<Code>) {
    let singular = to_singular(path);
    let (inner, defs) = type_from_shape(ctxt, &singular, shape);
    (format!("dict[str, {}]", inner), defs)
}

fn generate_tuple_type(ctxt: &mut Ctxt, path: &str, shapes: &[Shape]) -> (Ident, Option<Code>) {
    let mut types = Vec::new();
    let mut defs = Vec::new();

    for shape in shapes {
        let (typ, def) = type_from_shape(ctxt, path, shape);
        types.push(typ);
        if let Some(code) = def {
            defs.push(code)
        }
    }

    (
        format!("tuple[{}]", types.join(", ")),
        Some(defs.join("\n\n")),
    )
}

fn field_name(name: &str, used_names: &HashSet<String>) -> Ident {
    type_or_field_name(name, used_names, "field", snake_case)
}

fn type_name(name: &str, used_names: &HashSet<String>) -> Ident {
    type_or_field_name(name, used_names, "GeneratedType", type_case)
}

// https://docs.python.org/3/reference/lexical_analysis.html#keywords
#[rustfmt::skip]
const PYTHON_KEYWORDS: &[&str] = &[
    "False", "None", "True",
    "and", "as", "assert", "async", "await", "break", "class", "continue",
    "def", "del", "elif", "else", "except", "finally", "for", "from", "global",
    "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass",
    "raise", "return", "try", "while", "with", "yield",
];

fn type_or_field_name(
    name: &str,
    used_names: &HashSet<String>,
    default_name: &str,
    case_fn: fn(&str) -> String,
) -> Ident {
    let name = name.trim();
    let mut output_name = case_fn(name);
    if PYTHON_KEYWORDS.contains(&&*output_name) {
        output_name.push_str("_field");
    }
    if output_name.is_empty() {
        output_name.push_str(default_name);
    }
    if let Some(c) = output_name.chars().next() {
        if c.is_ascii_digit() {
            output_name = String::from("n") + &output_name;
        }
    }
    if !used_names.contains(&output_name) {
        return output_name;
    }
    for n in 2.. {
        let temp = format!("{}{}", output_name, n);
        if !used_names.contains(&temp) {
            return temp;
        }
    }
    unreachable!()
}

fn import(ctxt: &mut Ctxt, import: Import) -> String {
    ctxt.imports.insert(import);
    match ctxt.options.import_style {
        ImportStyle::QualifiedPaths => import.qualified(),
        _ => import.identifier().into(),
    }
}

fn generate_data_class(
    ctxt: &mut Ctxt,
    path: &str,
    field_shapes: &LinkedHashMap<String, Shape>,
    containing_shape: &Shape,
) -> (Ident, Option<Code>) {
    for (created_for_shape, ident) in ctxt.created_classes.iter() {
        if created_for_shape.is_acceptable_substitution_for(containing_shape) {
            return (ident.into(), None);
        }
    }

    let type_name = type_name(path, &ctxt.type_names);
    ctxt.type_names.insert(type_name.clone());
    ctxt.created_classes
        .push((containing_shape.clone(), type_name.clone()));

    let mut field_names = HashSet::new();
    let mut defs = Vec::new();

    let fields: Vec<Code> = field_shapes
        .iter()
        .map(|(name, typ)| {
            let field_name = field_name(name, &field_names);
            field_names.insert(field_name.clone());

            let (field_type, child_defs) = type_from_shape(ctxt, name, typ);

            if let Some(code) = child_defs {
                defs.push(code);
            }

            let mut field_code = String::new();
            let transformed = apply_transform(ctxt, &field_name, &name);
            if transformed != field_name {
                field_code += &format!(" = {}(alias = \"{}\")", import(ctxt, Import::Field), transformed)
            }

            format!("    {}: {}{}", field_name, field_type, field_code)
        })
        .collect();

    let mut code = String::new();

    code += &format!(
        "class {}({}):\n",
        type_name,
        import(ctxt, Import::BaseModel)
    );

    if fields.is_empty() {
        code += "    pass\n";
    } else {
        code += &fields.join("\n");
        code += "\n";
    }

    if !defs.is_empty() {
        let mut d = defs.join("\n\n");
        d += "\n\n";
        d += &code;
        code = d;
    }

    (type_name, Some(code))
}

fn apply_transform(ctxt: &Ctxt, field_name: &str, name: &str) -> String {
    match ctxt.options.property_name_format {
        Some(StringTransform::LowerCase) => field_name.to_ascii_lowercase(),
        Some(StringTransform::PascalCase) => type_case(field_name),
        Some(StringTransform::SnakeCase) => snake_case(field_name),
        Some(StringTransform::KebabCase) => kebab_case(field_name),
        Some(StringTransform::UpperCase) => field_name.to_ascii_uppercase(),
        Some(StringTransform::CamelCase) => lower_camel_case(field_name),
        Some(StringTransform::ScreamingSnakeCase) => snake_case(field_name).to_ascii_uppercase(),
        Some(StringTransform::ScreamingKebabCase) => kebab_case(field_name).to_ascii_uppercase(),
        None => name.to_string(),
    }
}

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

    #[test]
    fn field_names_test() {
        fn field_name_test(from: &str, to: &str) {
            assert_eq!(
                field_name(from, &HashSet::new()),
                to.to_string(),
                r#"From "{}" to "{}""#,
                from,
                to
            );
        }

        field_name_test("valid", "valid");
        field_name_test("1", "n1");
        field_name_test("+1", "n1");
        field_name_test("", "field");
        field_name_test("def", "def_field");
    }
}
<|endoftext|>


<commit_before>use std::comm::SharedChan;
use std::hashmap::HashMap;
use std::hash::Hash;

fn main() {
    // Reading 10 books from Project Gutenberg
    let mut docs: ~[~str] = ~[~"books/Beowulf.txt", ~"books/Adventures_in_Wonderland.txt", ~"books/Pride_and_Prejudice.txt",
                                ~"books/Sherlock_Holmes.txt", ~"books/The_Prince.txt", ~"books/Dorian_Gray.txt", ~"books/Dracula.txt",
                                ~"books/Dubliners.txt", ~"books/Great_Expectations.txt", ~"books/Siddhartha.txt"];

    docs = docs.map(|file| {
        readFile(file.to_owned())
    });

    // Defining instance of mapper to get word counts
    fn mapper(doc: ~str) -> ~[(~str, uint)] {
        let words: ~[~str] = doc.split_iter(' ')
            .filter(|&x| x != "")
            .map(|x| {
                x.to_owned()
            }).collect();

        let mut ret: ~[(~str, uint)] = ~[];
        for w in words.iter() {
            let tup: (~str, uint) = (w.to_str(), 1);
            ret.push(tup);
        }

        ret
    }

    // Defining instance of reducer to get word counts
    fn reducer(key: ~str, vals: ~[uint]) -> ~[(~str, uint)] {
        let mut result: uint = 0;
        for val in vals.iter() {
            result += *val;
        }
        ~[(key, result)]
    }

    // Launching job
    docs.mapreduce::<~str,uint>(mapper, reducer);

}

// Exposing trait
trait MapReduce {
    fn mapreduce<K2: Clone + Send + Hash + Equiv<K2> + Eq, V2: Clone + Send>( &self, extern fn(~str) -> ~[(K2, V2)], extern fn(K2, ~[V2]) -> ~[(K2, V2)] );
}

// Implementation of mapreduce trait
impl MapReduce for ~[~str] {
    fn mapreduce<K2: Clone + Send + Hash + Equiv<K2> + Eq, V2: Clone + Send>( &self, mapper: extern fn(~str) -> ~[(K2, V2)], reducer: extern fn(K2, ~[V2]) -> ~[(K2, V2)] ) {
        // First we map in parallel
        let (port, chan): (Port<~[(K2, V2)]>, Chan<~[(K2, V2)]>) = stream();
        let chan = SharedChan::new(chan);
        let mut chans: int = 0;
        for doc in self.iter() {
            let child_chan = chan.clone();
            let doc_owned = doc.clone();
            chans += 1;
            do spawn {
                let ivals: ~[(K2, V2)] = mapper(doc_owned.clone());
                child_chan.send(ivals);
            }
        }

        // Aggregate intermediate keys
        let mut key_vals_map: HashMap<K2, ~[V2]> = HashMap::new();
        for _ in range(0, chans) {
            let ivals: ~[(K2, V2)] = port.recv();

            for ival in ivals.iter() {

		let mut key: K2;
		let mut val: V2;
	    	match (*ival).clone() {
		      (a, b) => { key = a; val = b;},
		}

                if key_vals_map.contains_key_equiv(&key) {
                    let list = key_vals_map.get_mut(&key);
                    list.push(val);
                } else {
                    key_vals_map.find_or_insert(key, ~[val]);
                }
            }
        }

        // Finally, reduce in parallel
        chans = 0;
        key_vals_map.each_key(|key| {
                let values = key_vals_map.get(key);
                let child_chan = chan.clone();
                let key_owned = key.clone();
                let values_owned = values.clone();
                chans += 1;
                do spawn {
                    let rvals: ~[(K2, V2)] = reducer(key_owned.clone(), values_owned.clone());
                    child_chan.send(rvals);
                }
                true
            });

        // Print reduced values
        for _ in range(0, chans) {
            let rvals: ~[(K2, V2)] = port.recv();
            println(fmt!("%?", rvals));
        }
    }
}

// Auxiliary function to read entire file
fn readFile(filename: ~str) -> ~str {
    let contents = std::io::read_whole_file_str(&std::path::PosixPath{
        is_absolute: false,
        components: ~[filename]
    });

    let ret = match contents {
        Ok(T) => T,
        _ => ~""
    };
    ret
}
<commit_msg>Changed how the mapper splits. Splits all but a few corner cases successfully now<commit_after>use std::comm::SharedChan;
use std::hashmap::HashMap;
use std::hash::Hash;

fn main() {
    // Reading 10 books from Project Gutenberg
    let mut docs: ~[~str] = ~[~"books/Beowulf.txt", ~"books/Adventures_in_Wonderland.txt", ~"books/Pride_and_Prejudice.txt",
                                ~"books/Sherlock_Holmes.txt", ~"books/The_Prince.txt", ~"books/Dorian_Gray.txt", ~"books/Dracula.txt",
                                ~"books/Dubliners.txt", ~"books/Great_Expectations.txt", ~"books/Siddhartha.txt"];

    docs = docs.map(|file| {
        readFile(file.to_owned())
    });

    // Defining instance of mapper to get word counts
    fn mapper(doc: ~str) -> ~[(~str, uint)] {
	let words: ~[~str] = doc.split_iter(|c: char| { c.is_whitespace() ||
            !(c.is_alphanumeric() || ['\'', '-'].contains(&c)) })
            .filter(|&x| x != "")
            .map(|x| {
                x.to_owned()
            }).collect();

        let mut ret: ~[(~str, uint)] = ~[];
        for w in words.iter() {
            let tup: (~str, uint) = (w.to_str(), 1);
            ret.push(tup);
        }

        ret
    }

    // Defining instance of reducer to get word counts
    fn reducer(key: ~str, vals: ~[uint]) -> ~[(~str, uint)] {
        let mut result: uint = 0;
        for val in vals.iter() {
            result += *val;
        }
        ~[(key, result)]
    }

    // Launching job
    docs.mapreduce::<~str,uint>(mapper, reducer);

}

// Exposing trait
trait MapReduce {
    fn mapreduce<K2: Clone + Send + Hash + Equiv<K2> + Eq, V2: Clone + Send>( &self, extern fn(~str) -> ~[(K2, V2)], extern fn(K2, ~[V2]) -> ~[(K2, V2)] );
}

// Implementation of mapreduce trait
impl MapReduce for ~[~str] {
    fn mapreduce<K2: Clone + Send + Hash + Equiv<K2> + Eq, V2: Clone + Send>( &self, mapper: extern fn(~str) -> ~[(K2, V2)], reducer: extern fn(K2, ~[V2]) -> ~[(K2, V2)] ) {
        // First we map in parallel
        let (port, chan): (Port<~[(K2, V2)]>, Chan<~[(K2, V2)]>) = stream();
        let chan = SharedChan::new(chan);
        let mut chans: int = 0;
        for doc in self.iter() {
            let child_chan = chan.clone();
            let doc_owned = doc.clone();
            chans += 1;
            do spawn {
                let ivals: ~[(K2, V2)] = mapper(doc_owned.clone());
                child_chan.send(ivals);
            }
        }

        // Aggregate intermediate keys
        let mut key_vals_map: HashMap<K2, ~[V2]> = HashMap::new();
        for _ in range(0, chans) {
            let ivals: ~[(K2, V2)] = port.recv();

            for ival in ivals.iter() {

		let mut key: K2;
		let mut val: V2;
	    	match (*ival).clone() {
		      (a, b) => { key = a; val = b;},
		}

                if key_vals_map.contains_key_equiv(&key) {
                    let list = key_vals_map.get_mut(&key);
                    list.push(val);
                } else {
                    key_vals_map.find_or_insert(key, ~[val]);
                }
            }
        }

        // Finally, reduce in parallel
        chans = 0;
        key_vals_map.each_key(|key| {
                let values = key_vals_map.get(key);
                let child_chan = chan.clone();
                let key_owned = key.clone();
                let values_owned = values.clone();
                chans += 1;
                do spawn {
                    let rvals: ~[(K2, V2)] = reducer(key_owned.clone(), values_owned.clone());
                    child_chan.send(rvals);
                }
                true
            });

        // Print reduced values
        for _ in range(0, chans) {
            let rvals: ~[(K2, V2)] = port.recv();
            println(fmt!("%?", rvals));
        }
    }
}

// Auxiliary function to read entire file
fn readFile(filename: ~str) -> ~str {
    let contents = std::io::read_whole_file_str(&std::path::PosixPath{
        is_absolute: false,
        components: ~[filename]
    });

    let ret = match contents {
        Ok(T) => T,
        _ => ~""
    };
    ret
}
<|endoftext|>


<commit_before>pub fn hex_to_int(hex: &str) -> Option<u64> {
    let mut res = 0;
    // TODO: fails if hex digits are larger than u64

    for x in hex.chars() {
        res *= 16;
        res += match x {
            '0' => 0,
            '1' => 1,
            '2' => 2,
            '3' => 3,
            '4' => 4,
            '5' => 5,
            '6' => 6,
            '7' => 7,
            '8' => 8,
            '9' => 9,
            'a' => 10,
            'b' => 11,
            'c' => 12,
            'd' => 13,
            'e' => 14,
            'f' => 15,

            // error in decoding
            _ => return None,
        };
    }
    Some(res)
}
<commit_msg>Rust: Hexadecimal shorten conversion into numbers<commit_after>pub fn hex_to_int(hex: &str) -> Option<u64> {
    let mut res = 0;
    // TODO: fails if hex digits are larger than u64

    for x in hex.chars() {
        res *= 16;
        res += match x {
            '0'...'9' => (x as u8 - b'0') as u64,
            'A'...'F' => (x as u8 - b'A' + 10u8) as u64,
            'a'...'f' => (x as u8 - b'a' + 10u8) as u64,

            // error in decoding
            _ => return None,
        };
    }
    Some(res)
}
<|endoftext|>


<commit_before>use kernel::eyre::Result;
use kernel_micro::{include_file, MicroKernel};

pub async fn new() -> Result<MicroKernel> {
    MicroKernel::new(
        "bash",
        ("bash", "*", &["{{script}}"]),
        include_file!("bash-kernel.sh"),
        &[],
        "{{name}}=\"{{json}}\"",
        "echo ${{name}}",
    )
    .await
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::KernelTrait;
    use test_utils::{assert_json_eq, print_logs};

    #[tokio::test]
    async fn basic() -> Result<()> {
        print_logs();

        let mut kernel = new().await?;
        kernel.start().await?;

        let result = kernel.exec("echo foo").await?;
        assert_json_eq!(result.0, ["foo\n"]);

        Ok(())
    }
}
<commit_msg>test(Bash kernel): Add basic tests<commit_after>use kernel::eyre::Result;
use kernel_micro::{include_file, MicroKernel};

pub async fn new() -> Result<MicroKernel> {
    MicroKernel::new(
        "bash",
        ("bash", "*", &["{{script}}"]),
        include_file!("bash-kernel.sh"),
        &[],
        "{{name}}=\"{{json}}\"",
        "echo ${{name}}",
    )
    .await
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{stencila_schema::Node, KernelTrait};
    use test_utils::{assert_json_eq, serde_json::json};

    /// Tests of basic functionality
    /// This test is replicated in all the microkernels.
    /// Other test should be written for language specific quirks and regressions.
    #[tokio::test]
    async fn basics() -> Result<()> {
        let mut kernel = new().await?;
        kernel.start().await?;

        // Assign a variable and output it
        let (outputs, messages) = kernel.exec("a=2\necho $a").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [2]);

        // Print the variable twice and then output it
        // For bash, we need to separate outputs manually using the Unicode separator character
        let (outputs, messages) = kernel
            .exec("echo $a\u{10ABBA}\necho $a\u{10ABBA}\necho $a")
            .await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [2, 2, 2]);

        // Syntax error
        let (outputs, messages) = kernel.exec("if").await?;
        messages[0]
            .error_message
            .ends_with("syntax error: unexpected end of file\n");

        assert_json_eq!(outputs, json!([]));

        // Runtime error
        let (outputs, messages) = kernel.exec("foo").await?;
        messages[0]
            .error_message
            .ends_with("foo: command not found\n");
        assert_json_eq!(outputs, json!([]));

        // Set and get another variable
        kernel.set("b", Node::Integer(3)).await?;
        let b = kernel.get("b").await?;
        assert_json_eq!(b, 3);

        // Use both variables
        let (outputs, messages) = kernel.exec("echo $a$b").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [23]);

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


<commit_before>extern crate crypto;
extern crate reqwest;

use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;

use crypto::md5::Md5;
use crypto::digest::Digest;

use reqwest::{Client, StatusCode};

#[derive(Debug)]
struct LoLVersion {
    region: &'static str,
    version: &'static str,
    desc: &'static str,
}

static VERSIONS: &'static [LoLVersion] = &[
    LoLVersion { region: "EUW", version: "2016_11_10", desc: "EU West" },
    LoLVersion { region: "NA", version: "2016_05_13", desc: "North America" },
    LoLVersion { region: "EUNE", version: "2016_11_10", desc: "EU Nordic & East" },
    LoLVersion { region: "OC1", version: "2016_05_13", desc: "Oceania" },
    LoLVersion { region: "RU", version: "2016_05_13", desc: "Russia" },
    LoLVersion { region: "LA1", version: "2016_05_26", desc: "Latin America North" },
    LoLVersion { region: "LA2", version: "2016_05_27", desc: "Latin America South" },
    LoLVersion { region: "BR", version: "2016_05_13", desc: "Brazil" },
];

fn main() {
    let cache_path = Path::new("filecache");

    if !cache_path.exists() {
        fs::create_dir(cache_path).expect("Could not create cache directory");
    }

    let mut found = Vec::new();
    let mut hash = Md5::new();
    let http_client = Client::new().expect("Could not create http client");

    for v in VERSIONS {
        let url = format!("https://riotgamespatcher-a.akamaihd.net/ShellInstaller/{region}/LeagueofLegends_{region}_Installer_{version}.exe",
            region = v.region, version = v.version);

        println!("Calculating hash for url: {}", url);

        let exec = cache_path.join(format!("LeagueofLegends_{}_Installer_{}.exe", v.region, v.version));

        // If the installer doesn't exist try to download it.
        if !exec.exists() {
            let mut res = http_client.get(&url).send().expect("Could not download file");

            if *res.status() != StatusCode::Ok {
                println!("Warning: Couldn't download file {}", url);
                continue;
            }

            let mut buf = vec![];
            res.read_to_end(&mut buf).expect("Could not read from response");

            let mut file = File::create(&exec).expect(&format!("Could not create installer at: {:?}", exec));
            file.write_all(&buf).expect("Could not write to file {}");
        }

        let mut file = File::open(&exec).expect(&format!("Could not find installer: {:?}", exec));

        let mut buf = vec![];
        file.read_to_end(&mut buf).expect("Could not read installer data");
        hash.input(&buf);

        let hash_str = hash.result_str();
        println!("{}", hash_str);

        hash.reset();

        found.push((hash_str, url, v));
    }

    // Create string outputs for hashes, urls, regions, and descriptions using 4 string allocations.
    let (mut hashes, mut urls, mut regions, mut desc) = found.iter()
        .fold((String::new(), String::new(), String::new(), String::new()), |s, &(ref hash, ref url, v)| {
            ((s.0 + "[\"" + v.desc + "\"]=\"" + hash + "\" "),
             (s.1 + "[\"" + v.desc + "\"]=\"" + url + "\" "),
             (s.2 + "[\"" + v.desc + "\"]=\"" + v.region + "\" "),
             (s.3 + v.desc + "|"))
        });

    // For now we just pop the extra last character off of each string because of the fold.
    hashes.pop(); urls.pop(); regions.pop(); desc.pop();

    println!("declare -A HASHES=( {} )", hashes);
    println!("declare -A URLS=( {} )", urls);
    println!("declare -A REGIONS=( {} )", regions);
    println!("REGION_DESC=\"{}\"", desc);
}<commit_msg>A little bit more cleanup.<commit_after>extern crate crypto;
extern crate reqwest;

use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;

use crypto::md5::Md5;
use crypto::digest::Digest;

use reqwest::{Client, StatusCode};

#[derive(Debug)]
struct LoLVersion {
    region: &'static str,
    version: &'static str,
    desc: &'static str,
}

static VERSIONS: &'static [LoLVersion] = &[
    LoLVersion { region: "EUW", version: "2016_11_10", desc: "EU West" },
    LoLVersion { region: "NA", version: "2016_05_13", desc: "North America" },
    LoLVersion { region: "EUNE", version: "2016_11_10", desc: "EU Nordic & East" },
    LoLVersion { region: "OC1", version: "2016_05_13", desc: "Oceania" },
    LoLVersion { region: "RU", version: "2016_05_13", desc: "Russia" },
    LoLVersion { region: "LA1", version: "2016_05_26", desc: "Latin America North" },
    LoLVersion { region: "LA2", version: "2016_05_27", desc: "Latin America South" },
    LoLVersion { region: "BR", version: "2016_05_13", desc: "Brazil" },
];

fn main() {
    let cache_path = Path::new("filecache");

    if !cache_path.exists() {
        fs::create_dir(cache_path).expect("Could not create cache directory");
    }

    let mut found = vec![];
    let mut hash = Md5::new();
    let client = Client::new().expect("Could not create http client");

    for v in VERSIONS {
        let url = format!("https://riotgamespatcher-a.akamaihd.net/ShellInstaller/{region}/LeagueofLegends_{region}_Installer_{version}.exe",
            region = v.region, version = v.version);

        println!("Calculating hash for url: {}", url);

        let exec = cache_path.join(format!("LeagueofLegends_{}_Installer_{}.exe", v.region, v.version));
        let mut buf = vec![];

        if exec.exists() {
            if File::open(&exec).and_then(|mut f| f.read_to_end(&mut buf)).is_err() {
                println!("Warning: Could not read from installer: {:?}", exec);
                continue;
            }
        } else {
            match client.get(&url).send() {
                // We are only interested in a successful response.
                Ok(ref mut r) if *r.status() == StatusCode::Ok => {
                    if r.read_to_end(&mut buf).is_err() {
                        println!("Warning: Could not read from downloaded installer: {:?}", exec);
                        continue;
                    }

                    if File::create(&exec).and_then(|mut f| f.write_all(&buf)).is_err() {
                        println!("Warning: Could not save downloaded installer: {:?}", exec);
                        continue;
                    }
                }
                _ => {
                    println!("Warning: Could not download installer: {}", url);
                    continue;
                }
            }
        }

        hash.input(&buf);
        let hash_str = hash.result_str();
        hash.reset();

        println!("{}", hash_str);

        found.push((hash_str, url, v));
    }

    // Create string outputs for hashes, urls, regions, and descriptions
    let (mut hashes, mut urls, mut regions, mut desc) = found.iter()
        .fold((String::new(), String::new(), String::new(), String::new()), |s, &(ref hash, ref url, v)| {
            ((s.0 + "[\"" + v.desc + "\"]=\"" + hash + "\" "),
             (s.1 + "[\"" + v.desc + "\"]=\"" + url + "\" "),
             (s.2 + "[\"" + v.desc + "\"]=\"" + v.region + "\" "),
             (s.3 + v.desc + "|"))
        });

    // For now we just pop the extra last character off of each string because of the fold.
    hashes.pop(); urls.pop(); regions.pop(); desc.pop();

    println!("declare -A HASHES=( {} )", hashes);
    println!("declare -A URLS=( {} )", urls);
    println!("declare -A REGIONS=( {} )", regions);
    println!("REGION_DESC=\"{}\"", desc);
}<|endoftext|>


<commit_before>//! `cpuid` intrinsics
#![allow(clippy::module_name_repetitions)]

#[cfg(test)]
use stdarch_test::assert_instr;

/// Result of the `cpuid` instruction.
#[allow(clippy::missing_inline_in_public_items)]
// ^^ the derived impl of Debug for CpuidResult is not #[inline] and that's OK.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub struct CpuidResult {
    /// EAX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub eax: u32,
    /// EBX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub ebx: u32,
    /// ECX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub ecx: u32,
    /// EDX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub edx: u32,
}

/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
/// and
/// `sub_leaf` (`ECX`).
///
/// The highest-supported leaf value is returned by the first tuple argument of
/// [`__get_cpuid_max(0)`](fn.__get_cpuid_max.html). For leaves containung
/// sub-leaves, the second tuple argument returns the highest-supported
/// sub-leaf
/// value.
///
/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
/// information using the `EAX` and `ECX` registers, and the interpretation of
/// the results returned in `EAX`, `EBX`, `ECX`, and `EDX`.
///
/// The references are:
/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2:
///   Instruction Set Reference, A-Z][intel64_ref].
/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and
///   System Instructions][amd64_ref].
///
/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID
/// [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
    let eax;
    let ebx;
    let ecx;
    let edx;
    #[cfg(target_arch = "x86")]
    {
        llvm_asm!("cpuid"
                  : "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx)
                  : "{eax}"(leaf), "{ecx}"(sub_leaf)
                  : :);
    }
    #[cfg(target_arch = "x86_64")]
    {
        // x86-64 uses %rbx as the base register, so preserve it.
        llvm_asm!("cpuid"
                  : "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx)
                  : "{eax}"(leaf), "{ecx}"(sub_leaf)
                  : "rbx" :);
    }
    CpuidResult { eax, ebx, ecx, edx }
}

/// See [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
    __cpuid_count(leaf, 0)
}

/// Does the host support the `cpuid` instruction?
#[inline]
pub fn has_cpuid() -> bool {
    #[cfg(target_env = "sgx")]
    {
        false
    }
    #[cfg(all(not(target_env = "sgx"), target_arch = "x86_64"))]
    {
        true
    }
    #[cfg(all(not(target_env = "sgx"), target_arch = "x86"))]
    {
        // Optimization for i586 and i686 Rust targets which SSE enabled
        // and support cpuid:
        #[cfg(target_feature = "sse")]
        {
            true
        }

        // If SSE is not enabled, detect whether cpuid is available:
        #[cfg(not(target_feature = "sse"))]
        unsafe {
            // On `x86` the `cpuid` instruction is not always available.
            // This follows the approach indicated in:
            // http://wiki.osdev.org/CPUID#Checking_CPUID_availability
            // https://software.intel.com/en-us/articles/using-cpuid-to-detect-the-presence-of-sse-41-and-sse-42-instruction-sets/
            // which detects whether `cpuid` is available by checking whether
            // the 21st bit of the EFLAGS register is modifiable or not.
            // If it is, then `cpuid` is available.
            let result: u32;
            let _temp: u32;
            llvm_asm!(r#"
                      # Read eflags into $0 and copy it into $1:
                      pushfd
                      pop     $0
                      mov     $1, $0
                      # Flip 21st bit of $0.
                      xor     $0, 0x200000
                      # Set eflags to the value of $0
                      #
                      # Bit 21st can only be modified if cpuid is available
                      push    $0
                      popfd          # A
                      # Read eflags into $0:
                      pushfd         # B
                      pop     $0
                      # xor with the original eflags sets the bits that
                      # have been modified:
                      xor     $0, $1
                      "#
                      : "=r"(result), "=r"(_temp)
                      :
                      : "cc", "memory"
                      : "intel");
            // There is a race between popfd (A) and pushfd (B)
            // where other bits beyond 21st may have been modified due to
            // interrupts, a debugger stepping through the asm, etc.
            //
            // Therefore, explicitly check whether the 21st bit
            // was modified or not.
            //
            // If the result is zero, the cpuid bit was not modified.
            // If the result is `0x200000` (non-zero), then the cpuid
            // was correctly modified and the CPU supports the cpuid
            // instruction:
            (result & 0x200000) != 0
        }
    }
}

/// Returns the highest-supported `leaf` (`EAX`) and sub-leaf (`ECX`) `cpuid`
/// values.
///
/// If `cpuid` is supported, and `leaf` is zero, then the first tuple argument
/// contains the highest `leaf` value that `cpuid` supports. For `leaf`s
/// containing sub-leafs, the second tuple argument contains the
/// highest-supported sub-leaf value.
///
/// See also [`__cpuid`](fn.__cpuid.html) and
/// [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
    let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
    (eax, ebx)
}

#[cfg(test)]
mod tests {
    use crate::core_arch::x86::*;

    #[test]
    fn test_always_has_cpuid() {
        // all currently-tested targets have the instruction
        // FIXME: add targets without `cpuid` to CI
        assert!(cpuid::has_cpuid());
    }

    #[test]
    fn test_has_cpuid_idempotent() {
        assert_eq!(cpuid::has_cpuid(), cpuid::has_cpuid());
    }
}
<commit_msg>Manually preserve rbx across cpuid instruction (#851)<commit_after>//! `cpuid` intrinsics
#![allow(clippy::module_name_repetitions)]

#[cfg(test)]
use stdarch_test::assert_instr;

/// Result of the `cpuid` instruction.
#[allow(clippy::missing_inline_in_public_items)]
// ^^ the derived impl of Debug for CpuidResult is not #[inline] and that's OK.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub struct CpuidResult {
    /// EAX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub eax: u32,
    /// EBX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub ebx: u32,
    /// ECX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub ecx: u32,
    /// EDX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub edx: u32,
}

/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
/// and
/// `sub_leaf` (`ECX`).
///
/// The highest-supported leaf value is returned by the first tuple argument of
/// [`__get_cpuid_max(0)`](fn.__get_cpuid_max.html). For leaves containung
/// sub-leaves, the second tuple argument returns the highest-supported
/// sub-leaf
/// value.
///
/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
/// information using the `EAX` and `ECX` registers, and the interpretation of
/// the results returned in `EAX`, `EBX`, `ECX`, and `EDX`.
///
/// The references are:
/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2:
///   Instruction Set Reference, A-Z][intel64_ref].
/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and
///   System Instructions][amd64_ref].
///
/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID
/// [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
    let eax;
    let ebx;
    let ecx;
    let edx;
    #[cfg(target_arch = "x86")]
    {
        llvm_asm!("cpuid"
                  : "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx)
                  : "{eax}"(leaf), "{ecx}"(sub_leaf)
                  : :);
    }
    #[cfg(target_arch = "x86_64")]
    {
        // x86-64 uses %rbx as the base register, so preserve it.
        // This works around a bug in LLVM with ASAN enabled:
        // https://bugs.llvm.org/show_bug.cgi?id=17907
        llvm_asm!(r#"
                  mov %rbx, %rsi
                  cpuid
                  xchg %rbx, %rsi
                  "#
                  : "={eax}"(eax), "={esi}"(ebx), "={ecx}"(ecx), "={edx}"(edx)
                  : "{eax}"(leaf), "{ecx}"(sub_leaf)
                  : :);
    }
    CpuidResult { eax, ebx, ecx, edx }
}

/// See [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
    __cpuid_count(leaf, 0)
}

/// Does the host support the `cpuid` instruction?
#[inline]
pub fn has_cpuid() -> bool {
    #[cfg(target_env = "sgx")]
    {
        false
    }
    #[cfg(all(not(target_env = "sgx"), target_arch = "x86_64"))]
    {
        true
    }
    #[cfg(all(not(target_env = "sgx"), target_arch = "x86"))]
    {
        // Optimization for i586 and i686 Rust targets which SSE enabled
        // and support cpuid:
        #[cfg(target_feature = "sse")]
        {
            true
        }

        // If SSE is not enabled, detect whether cpuid is available:
        #[cfg(not(target_feature = "sse"))]
        unsafe {
            // On `x86` the `cpuid` instruction is not always available.
            // This follows the approach indicated in:
            // http://wiki.osdev.org/CPUID#Checking_CPUID_availability
            // https://software.intel.com/en-us/articles/using-cpuid-to-detect-the-presence-of-sse-41-and-sse-42-instruction-sets/
            // which detects whether `cpuid` is available by checking whether
            // the 21st bit of the EFLAGS register is modifiable or not.
            // If it is, then `cpuid` is available.
            let result: u32;
            let _temp: u32;
            llvm_asm!(r#"
                      # Read eflags into $0 and copy it into $1:
                      pushfd
                      pop     $0
                      mov     $1, $0
                      # Flip 21st bit of $0.
                      xor     $0, 0x200000
                      # Set eflags to the value of $0
                      #
                      # Bit 21st can only be modified if cpuid is available
                      push    $0
                      popfd          # A
                      # Read eflags into $0:
                      pushfd         # B
                      pop     $0
                      # xor with the original eflags sets the bits that
                      # have been modified:
                      xor     $0, $1
                      "#
                      : "=r"(result), "=r"(_temp)
                      :
                      : "cc", "memory"
                      : "intel");
            // There is a race between popfd (A) and pushfd (B)
            // where other bits beyond 21st may have been modified due to
            // interrupts, a debugger stepping through the asm, etc.
            //
            // Therefore, explicitly check whether the 21st bit
            // was modified or not.
            //
            // If the result is zero, the cpuid bit was not modified.
            // If the result is `0x200000` (non-zero), then the cpuid
            // was correctly modified and the CPU supports the cpuid
            // instruction:
            (result & 0x200000) != 0
        }
    }
}

/// Returns the highest-supported `leaf` (`EAX`) and sub-leaf (`ECX`) `cpuid`
/// values.
///
/// If `cpuid` is supported, and `leaf` is zero, then the first tuple argument
/// contains the highest `leaf` value that `cpuid` supports. For `leaf`s
/// containing sub-leafs, the second tuple argument contains the
/// highest-supported sub-leaf value.
///
/// See also [`__cpuid`](fn.__cpuid.html) and
/// [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
    let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
    (eax, ebx)
}

#[cfg(test)]
mod tests {
    use crate::core_arch::x86::*;

    #[test]
    fn test_always_has_cpuid() {
        // all currently-tested targets have the instruction
        // FIXME: add targets without `cpuid` to CI
        assert!(cpuid::has_cpuid());
    }

    #[test]
    fn test_has_cpuid_idempotent() {
        assert_eq!(cpuid::has_cpuid(), cpuid::has_cpuid());
    }
}
<|endoftext|>


<commit_before>//! Implementation of the `#[simd_test]` macro
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.

#![feature(proc_macro)]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;

use std::env;

use proc_macro2::{Literal, Span, Ident, TokenStream, TokenTree};

fn string(s: &str) -> TokenTree {
    Literal::string(s).into()
}

#[proc_macro_attribute]
pub fn simd_test(
    attr: proc_macro::TokenStream, item: proc_macro::TokenStream
) -> proc_macro::TokenStream {
    let tokens = TokenStream::from(attr)
        .into_iter()
        .collect::<Vec<_>>();
    if tokens.len() != 3 {
        panic!("expected #[simd_test(enable = \"feature\")]");
    }
    match &tokens[0] {
        TokenTree::Ident(tt) if tt.to_string() == "enable" => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    match &tokens[1] {
        TokenTree::Punct(tt) if tt.as_char() == '=' => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    let enable_feature = match &tokens[2] {
        TokenTree::Literal(tt) => tt.to_string(),
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    };
    let enable_feature = enable_feature
        .trim_left_matches('"')
        .trim_right_matches('"');
    let target_features: Vec<String> = enable_feature
        .replace('+', "")
        .split(',')
        .map(|v| String::from(v))
        .collect();

    let enable_feature = string(enable_feature);
    let item = TokenStream::from(item);
    let name = find_name(item.clone());

    let name: TokenStream = name.to_string().parse().expect(&format!(
        "failed to parse name: {}",
        name.to_string()
    ));

    let target = env::var("TARGET")
        .expect("TARGET environment variable should be set for rustc");
    let mut force_test = false;
    let macro_test = match target.split('-').next().expect(&format!(
        "target triple contained no \"-\": {}",
        target
    )) {
        "i686" | "x86_64" | "i586" => "is_x86_feature_detected",
        "arm" | "armv7" => "is_arm_feature_detected",
        "aarch64" => "is_aarch64_feature_detected",
        "powerpc" | "powerpcle" => "is_powerpc_feature_detected",
        "powerpc64" | "powerpc64le" => "is_powerpc64_feature_detected",
        "mips" | "mipsel" => {
            // FIXME:
            // On MIPS CI run-time feature detection always returns false due
            // to this qemu bug: https://bugs.launchpad.net/qemu/+bug/1754372
            //
            // This is a workaround to force the MIPS tests to always run on
            // CI.
            force_test = true;
            "is_mips_feature_detected"
        }
        "mips64" | "mips64el" => {
            // FIXME: see above
            force_test = true;
            "is_mips64_feature_detected"
        }
        t => panic!("unknown target: {}", t),
    };
    let macro_test = Ident::new(macro_test, Span::call_site());

    let mut cfg_target_features = TokenStream::empty();
    use quote::ToTokens;
    for feature in target_features {
        let q = quote_spanned! {
            proc_macro2::Span::call_site() =>
            #macro_test!(#feature) &&
        };
        q.to_tokens(&mut cfg_target_features);
    }
    let q = quote!{ true };
    q.to_tokens(&mut cfg_target_features);

    let ret: TokenStream = quote_spanned! {
        proc_macro2::Span::call_site() =>
        #[allow(non_snake_case)]
        #[test]
        fn #name() {
            if #force_test | (#cfg_target_features) {
                return unsafe { #name() };
            } else {
                ::stdsimd_test::assert_skip_test_ok(stringify!(#name));
            }

            #[target_feature(enable = #enable_feature)]
            #item
        }
    }.into();
    ret.into()
}

fn find_name(item: TokenStream) -> Ident {
    let mut tokens = item.into_iter();
    while let Some(tok) = tokens.next() {
        if let TokenTree::Ident(word) = tok {
            if word == "fn" {
                break;
            }
        }
    }

    match tokens.next() {
        Some(TokenTree::Ident(word)) => word,
        _ => panic!("failed to find function name"),
    }
}
<commit_msg>Add an env variable to ignore the arch-specific tests<commit_after>//! Implementation of the `#[simd_test]` macro
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.

#![feature(proc_macro)]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;

use std::env;

use proc_macro2::{Literal, Span, Ident, TokenStream, TokenTree};

fn string(s: &str) -> TokenTree {
    Literal::string(s).into()
}

#[proc_macro_attribute]
pub fn simd_test(
    attr: proc_macro::TokenStream, item: proc_macro::TokenStream
) -> proc_macro::TokenStream {
    let tokens = TokenStream::from(attr)
        .into_iter()
        .collect::<Vec<_>>();
    if tokens.len() != 3 {
        panic!("expected #[simd_test(enable = \"feature\")]");
    }
    match &tokens[0] {
        TokenTree::Ident(tt) if tt.to_string() == "enable" => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    match &tokens[1] {
        TokenTree::Punct(tt) if tt.as_char() == '=' => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    let enable_feature = match &tokens[2] {
        TokenTree::Literal(tt) => tt.to_string(),
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    };
    let enable_feature = enable_feature
        .trim_left_matches('"')
        .trim_right_matches('"');
    let target_features: Vec<String> = enable_feature
        .replace('+', "")
        .split(',')
        .map(|v| String::from(v))
        .collect();

    let enable_feature = string(enable_feature);
    let item = TokenStream::from(item);
    let name = find_name(item.clone());

    let name: TokenStream = name.to_string().parse().expect(&format!(
        "failed to parse name: {}",
        name.to_string()
    ));

    let target = env::var("TARGET")
        .expect("TARGET environment variable should be set for rustc");
    let mut force_test = false;
    let macro_test = match target.split('-').next().expect(&format!(
        "target triple contained no \"-\": {}",
        target
    )) {
        "i686" | "x86_64" | "i586" => "is_x86_feature_detected",
        "arm" | "armv7" => "is_arm_feature_detected",
        "aarch64" => "is_aarch64_feature_detected",
        "powerpc" | "powerpcle" => "is_powerpc_feature_detected",
        "powerpc64" | "powerpc64le" => "is_powerpc64_feature_detected",
        "mips" | "mipsel" => {
            // FIXME:
            // On MIPS CI run-time feature detection always returns false due
            // to this qemu bug: https://bugs.launchpad.net/qemu/+bug/1754372
            //
            // This is a workaround to force the MIPS tests to always run on
            // CI.
            force_test = true;
            "is_mips_feature_detected"
        }
        "mips64" | "mips64el" => {
            // FIXME: see above
            force_test = true;
            "is_mips64_feature_detected"
        }
        t => panic!("unknown target: {}", t),
    };
    let macro_test = Ident::new(macro_test, Span::call_site());

    let mut cfg_target_features = TokenStream::empty();
    use quote::ToTokens;
    for feature in target_features {
        let q = quote_spanned! {
            proc_macro2::Span::call_site() =>
            #macro_test!(#feature) &&
        };
        q.to_tokens(&mut cfg_target_features);
    }
    let q = quote!{ true };
    q.to_tokens(&mut cfg_target_features);

    let test_norun = std::env::var("STDSIMD_TEST_NORUN").is_ok();
    let maybe_ignore = if !test_norun {
        TokenStream::empty()
    } else {
        (quote! { #[ignore] }).into()
    };

    let ret: TokenStream = quote_spanned! {
        proc_macro2::Span::call_site() =>
        #[allow(non_snake_case)]
        #[test]
        #maybe_ignore
        fn #name() {
            if #force_test | (#cfg_target_features) {
                return unsafe { #name() };
            } else {
                ::stdsimd_test::assert_skip_test_ok(stringify!(#name));
            }

            #[target_feature(enable = #enable_feature)]
            #item
        }
    }.into();
    ret.into()
}

fn find_name(item: TokenStream) -> Ident {
    let mut tokens = item.into_iter();
    while let Some(tok) = tokens.next() {
        if let TokenTree::Ident(word) = tok {
            if word == "fn" {
                break;
            }
        }
    }

    match tokens.next() {
        Some(TokenTree::Ident(word)) => word,
        _ => panic!("failed to find function name"),
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add, Div, Sub, Index};

struct Matrix {
	cols: usize,
	rows: usize,
	data: Vec<f32>
}

impl Matrix {
    fn new(cols: usize, rows: usize, data: Vec<f32>) -> Matrix {
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    fn zeros(cols: usize, rows: usize) -> Matrix {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![0.0; cols*rows]
        }
    }

    fn identity(size: usize) -> Matrix {
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = 1.0;
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn from_diag(diag: &Vec<f32>) -> Matrix {
    	let size = diag.len();
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }
}

impl Mul<f32> for Matrix {
    type Output = Matrix;

    fn mul(self, f: f32) -> Matrix {
        let new_data = self.data.into_iter().map(|v| v * f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Mul<Matrix> for Matrix {
	type Output = Matrix;

	fn mul(self, m: Matrix) -> Matrix {
		// Will use Strassen algorithm if large, traditional otherwise
		return self;
	}
}

impl Add<f32> for Matrix {
	type Output = Matrix;

	fn add(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v + f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Add<Matrix> for Matrix {
	type Output = Matrix;

	fn add(self, m: Matrix) -> Matrix {
		return self;
	}
}

impl Div<f32> for Matrix {
	type Output = Matrix;

	fn div(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v / f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}<commit_msg>Completed matrix - matrix addition.<commit_after>use std::ops::{Mul, Add, Div, Sub, Index};

struct Matrix {
	cols: usize,
	rows: usize,
	data: Vec<f32>
}

impl Matrix {
    fn new(cols: usize, rows: usize, data: Vec<f32>) -> Matrix {
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    fn zeros(cols: usize, rows: usize) -> Matrix {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![0.0; cols*rows]
        }
    }

    fn identity(size: usize) -> Matrix {
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = 1.0;
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn from_diag(diag: &Vec<f32>) -> Matrix {
    	let size = diag.len();
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }
}

impl Mul<f32> for Matrix {
    type Output = Matrix;

    fn mul(self, f: f32) -> Matrix {
        let new_data = self.data.into_iter().map(|v| v * f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Mul<Matrix> for Matrix {
	type Output = Matrix;

	fn mul(self, m: Matrix) -> Matrix {
		// Will use Strassen algorithm if large, traditional otherwise
		return self;
	}
}

impl Add<f32> for Matrix {
	type Output = Matrix;

	fn add(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v + f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Sub<f32> for Matrix {
	type Output = Matrix;

	fn sub(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v - f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Add<Matrix> for Matrix {
	type Output = Matrix;

	fn add(self, m: Matrix) -> Matrix {
		let new_data = self.data.into_iter().enumerate().map(|(i,v)| v + m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl Sub<Matrix> for Matrix {
	type Output = Matrix;

	fn sub(self, m: Matrix) -> Matrix {
		let new_data = self.data.into_iter().enumerate().map(|(i,v)| v - m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl Div<f32> for Matrix {
	type Output = Matrix;

	fn div(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v / f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}<|endoftext|>


<commit_before>extern crate docopt;
extern crate lalrpop;
extern crate rustc_serialize;

use docopt::Docopt;
use lalrpop::Configuration;
use std::env;
use std::io::{self, Write};
use std::process;

fn main() {
    main1().unwrap();
}

fn main1() -> io::Result<()> {
    let mut stderr = std::io::stderr();

    let args: Args =
        Docopt::new(USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

    let mut config = Configuration::new();

    match args.flag_level.unwrap_or(LevelFlag::Info) {
        LevelFlag::Quiet => config.log_quiet(),
        LevelFlag::Info => config.log_info(),
        LevelFlag::Verbose => config.log_verbose(),
        LevelFlag::Debug => config.log_debug(),
    };

    if args.flag_force {
        config.force_build(true);
    }

    if args.flag_color {
        config.always_use_colors();
    }

    if args.flag_comments {
        config.emit_comments(true);
    }

    if args.arg_inputs.len() == 0 {
        try!(writeln!(stderr, "Error: no input files specified! Try --help for help."));
        process::exit(1);
    }

    for arg in args.arg_inputs {
        match config.process_file(&arg) {
            Ok(()) => { }
            Err(err) => {
                try!(writeln!(stderr, "Error encountered processing `{}`: {}",
                              arg, err));
                process::exit(1);
            }
        }
    }

    Ok(())
}

const USAGE: &'static str = "
Usage: lalrpop [options] inputs...
       lalrpop --help

Convert each of the given inputs (which should be a `.lalrpop` file)
into a `.rs` file, just as a `build.rs` script using LALRPOP would do.

Options:
    -l, --level LEVEL    Set the debug level. (Default: info)
                         Valid values: quiet, info, verbose, debug.
    -f, --force          Force execution, even if the .lalrpop file is older than the .rs file.
    -c, --color          Force colorful output, even if this is not a TTY.
    --comments           Enable comments in the generated code.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_inputs: Vec<String>,
    flag_level: Option<LevelFlag>,
    flag_force: bool,
    flag_color: bool,
    flag_comments: bool,
}

#[derive(Debug, RustcDecodable)]
enum LevelFlag {
    Quiet, Info, Verbose, Debug
}
<commit_msg>Fix bug in USAGE and add regression tests.<commit_after>extern crate docopt;
extern crate lalrpop;
extern crate rustc_serialize;

use docopt::Docopt;
use lalrpop::Configuration;
use std::env;
use std::io::{self, Write};
use std::process;

fn main() {
    main1().unwrap();
}

fn main1() -> io::Result<()> {
    let mut stderr = std::io::stderr();

    let args: Args =
        Docopt::new(USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

    let mut config = Configuration::new();

    match args.flag_level.unwrap_or(LevelFlag::Info) {
        LevelFlag::Quiet => config.log_quiet(),
        LevelFlag::Info => config.log_info(),
        LevelFlag::Verbose => config.log_verbose(),
        LevelFlag::Debug => config.log_debug(),
    };

    if args.flag_force {
        config.force_build(true);
    }

    if args.flag_color {
        config.always_use_colors();
    }

    if args.flag_comments {
        config.emit_comments(true);
    }

    if args.arg_inputs.len() == 0 {
        try!(writeln!(stderr, "Error: no input files specified! Try --help for help."));
        process::exit(1);
    }

    for arg in args.arg_inputs {
        match config.process_file(&arg) {
            Ok(()) => { }
            Err(err) => {
                try!(writeln!(stderr, "Error encountered processing `{}`: {}",
                              arg, err));
                process::exit(1);
            }
        }
    }

    Ok(())
}

const USAGE: &'static str = "
Usage: lalrpop [options] <inputs>...
       lalrpop --help

Convert each of the given inputs (which should be a `.lalrpop` file)
into a `.rs` file, just as a `build.rs` script using LALRPOP would do.

Options:
    -l, --level LEVEL    Set the debug level. (Default: info)
                         Valid values: quiet, info, verbose, debug.
    -f, --force          Force execution, even if the .lalrpop file is older than the .rs file.
    -c, --color          Force colorful output, even if this is not a TTY.
    --comments           Enable comments in the generated code.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_inputs: Vec<String>,
    flag_level: Option<LevelFlag>,
    flag_force: bool,
    flag_color: bool,
    flag_comments: bool,
}

#[derive(Debug, RustcDecodable)]
enum LevelFlag {
    Quiet, Info, Verbose, Debug
}

#[cfg(test)]
mod test {
    use docopt::Docopt;
    use super::USAGE;
    use super::Args;

    #[test]
    fn test_usage_help() {
        let argv = || vec!["lalrpop", "--help"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.help(false).argv(argv().into_iter()).decode())
            .unwrap();
    }

    #[test]
    fn test_usage_single_input() {
        let argv = || vec!["lalrpop", "file.lalrpop"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(argv().into_iter()).decode())
            .unwrap();
    }

    #[test]
    fn test_usage_multiple_inputs() {
        let argv = || vec!["lalrpop", "file.lalrpop", "../file2.lalrpop"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(argv().into_iter()).decode())
            .unwrap();
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::{Diagnostic, NoopPerfLogger, SourceLocationKey::Generated};
use console_error_panic_hook;
use fnv::FnvHashSet;
use graphql_ir::Program;
use graphql_syntax;
use graphql_text_printer;
use interner::Intern;
use relay_codegen::{print_fragment, print_operation, JsModuleFormat};
use relay_schema::build_schema_with_extensions;
use relay_transforms::{apply_transforms, ConnectionInterface, FeatureFlags, Programs};
use schema::SDLSchema;
use serde::Serialize;
use serde_json;
use std::sync::Arc;

use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[derive(Serialize, Debug)]
pub struct WasmDiagnostic {
    message: String,
    line_start: u64,
    line_end: u64,
    column_start: u64,
    column_end: u64,
}

enum InputType<'a> {
    Schema(&'a str),
    Document(&'a str),
}

impl<'a> InputType<'a> {
    fn source(&self) -> &'a str {
        match self {
            Self::Schema(source) => source,
            Self::Document(source) => source,
        }
    }
}

#[derive(Serialize, Debug)]
pub enum PlaygroundError {
    DocumentDiagnostics(Vec<WasmDiagnostic>),
    SchemaDiagnostics(Vec<WasmDiagnostic>),
}

pub type PlaygroundResult = Result<String, PlaygroundError>;

#[wasm_bindgen]
pub fn parse_to_ast(document_text: &str) -> String {
    serialize_result(parse_to_ast_impl(document_text))
}

pub fn parse_to_ast_impl(document_text: &str) -> PlaygroundResult {
    let serialized_document = graphql_syntax::parse_executable(document_text, Generated)
        .map(|document| format!("{:?}", document))
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    Ok(serialized_document.into())
}

#[wasm_bindgen]
pub fn parse_to_ir(schema_text: &str, document_text: &str) -> String {
    serialize_result(parse_to_ir_impl(schema_text, document_text))
}

pub fn parse_to_ir_impl(schema_text: &str, document_text: &str) -> PlaygroundResult {
    let document = graphql_syntax::parse_executable(document_text, Generated)
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    let schema = Arc::new(
        build_schema_with_extensions(&[schema_text], &Vec::<&str>::new())
            .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Schema(schema_text)))?,
    );

    let ir = graphql_ir::build(&schema, &document.definitions)
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    Ok(ir
        .iter()
        .map(|definition| format!("{:?}", definition))
        .collect::<Vec<String>>()
        .join("\n")
        .into())
}

#[wasm_bindgen]
pub fn parse_to_reader_ast(schema_text: &str, document_text: &str) -> String {
    serialize_result(parse_to_reader_ast_impl(schema_text, document_text))
}

pub fn parse_to_reader_ast_impl(schema_text: &str, document_text: &str) -> PlaygroundResult {
    let schema = Arc::new(
        build_schema_with_extensions(&[schema_text], &Vec::<&str>::new())
            .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Schema(schema_text)))?,
    );

    let programs = get_programs(&schema, document_text)?;

    let reader_ast_string = programs
        .reader
        .fragments()
        .map(|def| print_fragment(&schema, &def, JsModuleFormat::Haste))
        .chain(
            programs
                .reader
                .operations()
                .map(|def| print_operation(&schema, &def, JsModuleFormat::Haste)),
        )
        .collect::<Vec<_>>()
        .join("\n\n");

    Ok(reader_ast_string.into())
}

#[wasm_bindgen]
pub fn transform(schema_text: &str, document_text: &str) -> String {
    serialize_result(transform_impl(schema_text, document_text))
}

fn transform_impl(schema_text: &str, document_text: &str) -> PlaygroundResult {
    let schema = Arc::new(
        build_schema_with_extensions(&[schema_text], &Vec::<&str>::new())
            .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Schema(schema_text)))?,
    );
    let programs = get_programs(&schema, document_text)?;

    let transformed_operations = programs
        .operation_text
        .operations()
        .map(|operation| graphql_text_printer::print_operation(&schema, operation))
        .collect::<Vec<_>>()
        .join("\n");

    let transformed_fragments = programs
        .operation_text
        .fragments()
        .map(|operation| graphql_text_printer::print_fragment(&schema, operation))
        .collect::<Vec<_>>()
        .join("\n");

    let output = transformed_operations + "\n\n" + &transformed_fragments;
    Ok(output.into())
}

fn get_programs(schema: &Arc<SDLSchema>, document_text: &str) -> Result<Programs, PlaygroundError> {
    let document = graphql_syntax::parse_executable(document_text, Generated)
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    let ir = graphql_ir::build(&schema, &document.definitions)
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    let program = Program::from_definitions(schema.clone(), ir);

    let project_name = "test_project".intern();
    let base_fragment_names = Arc::new(FnvHashSet::default());
    let connection_interface = ConnectionInterface::default();
    let feature_flags = FeatureFlags::default();
    let perf_logger = NoopPerfLogger;

    apply_transforms(
        project_name,
        Arc::new(program),
        base_fragment_names,
        &connection_interface,
        Arc::new(feature_flags),
        Arc::new(perf_logger),
        None,
    )
    .map_err(|diagnostics: Vec<Diagnostic>| {
        map_diagnostics(diagnostics, &InputType::Document(document_text))
    })
}

fn map_diagnostics(diagnostics: Vec<Diagnostic>, source: &InputType<'_>) -> PlaygroundError {
    let wasm_diagnostics = diagnostics
        .iter()
        .map(|diagnostic| {
            let range = diagnostic.location().span().to_range(source.source(), 0, 0);
            WasmDiagnostic {
                message: diagnostic.print_without_source(),
                line_start: range.start.line,
                line_end: range.end.line,
                column_start: range.start.character,
                column_end: range.end.character,
            }
        })
        .collect();
    match source {
        InputType::Document(_) => PlaygroundError::DocumentDiagnostics(wasm_diagnostics),
        InputType::Schema(_) => PlaygroundError::SchemaDiagnostics(wasm_diagnostics),
    }
}

fn serialize_result(result: PlaygroundResult) -> String {
    serde_json::to_string(&result).unwrap()
}

#[wasm_bindgen(start)]
pub fn start() {
    console_error_panic_hook::set_once();
}

// #[test]
fn _disable_test() {
    let schema_text = r#"type User {
        name: String
        age: Int
        best_friend: User
      }

      type Query {
        me: User
      }"#;
    let document_text = r#"query MyQuery {
        me {
          name
          ...AgeFragment
          best_friend {
            ...AgeFragment
          }
        }
      }

      fragment AgeFragment on User {
          age
      }"#;
    let result = serialize_result(transform_impl(schema_text, document_text));

    let expected = r#"{"Ok":"query MyQuery {
  me {
    name
    age
    best_friend {
      age
    }
  }
}"}"#;

    assert_eq!(result, expected)
}
<commit_msg>Fix local build (with cargo)<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::{Diagnostic, NoopPerfLogger, SourceLocationKey::Generated};
use console_error_panic_hook;
use fnv::FnvHashSet;
use graphql_ir::Program;
use graphql_syntax;
use graphql_text_printer;
use interner::Intern;
use relay_codegen::{print_fragment, print_operation, JsModuleFormat};
use relay_schema::build_schema_with_extensions;
use relay_transforms::{apply_transforms, ConnectionInterface, FeatureFlags, Programs};
use schema::SDLSchema;
use serde::Serialize;
use serde_json;
use std::sync::Arc;

use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[derive(Serialize, Debug)]
pub struct WasmDiagnostic {
    message: String,
    line_start: u32,
    line_end: u32,
    column_start: u32,
    column_end: u32,
}

enum InputType<'a> {
    Schema(&'a str),
    Document(&'a str),
}

impl<'a> InputType<'a> {
    fn source(&self) -> &'a str {
        match self {
            Self::Schema(source) => source,
            Self::Document(source) => source,
        }
    }
}

#[derive(Serialize, Debug)]
pub enum PlaygroundError {
    DocumentDiagnostics(Vec<WasmDiagnostic>),
    SchemaDiagnostics(Vec<WasmDiagnostic>),
}

pub type PlaygroundResult = Result<String, PlaygroundError>;

#[wasm_bindgen]
pub fn parse_to_ast(document_text: &str) -> String {
    serialize_result(parse_to_ast_impl(document_text))
}

pub fn parse_to_ast_impl(document_text: &str) -> PlaygroundResult {
    let serialized_document = graphql_syntax::parse_executable(document_text, Generated)
        .map(|document| format!("{:?}", document))
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    Ok(serialized_document.into())
}

#[wasm_bindgen]
pub fn parse_to_ir(schema_text: &str, document_text: &str) -> String {
    serialize_result(parse_to_ir_impl(schema_text, document_text))
}

pub fn parse_to_ir_impl(schema_text: &str, document_text: &str) -> PlaygroundResult {
    let document = graphql_syntax::parse_executable(document_text, Generated)
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    let schema = Arc::new(
        build_schema_with_extensions(&[schema_text], &Vec::<&str>::new())
            .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Schema(schema_text)))?,
    );

    let ir = graphql_ir::build(&schema, &document.definitions)
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    Ok(ir
        .iter()
        .map(|definition| format!("{:?}", definition))
        .collect::<Vec<String>>()
        .join("\n")
        .into())
}

#[wasm_bindgen]
pub fn parse_to_reader_ast(schema_text: &str, document_text: &str) -> String {
    serialize_result(parse_to_reader_ast_impl(schema_text, document_text))
}

pub fn parse_to_reader_ast_impl(schema_text: &str, document_text: &str) -> PlaygroundResult {
    let schema = Arc::new(
        build_schema_with_extensions(&[schema_text], &Vec::<&str>::new())
            .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Schema(schema_text)))?,
    );

    let programs = get_programs(&schema, document_text)?;

    let reader_ast_string = programs
        .reader
        .fragments()
        .map(|def| print_fragment(&schema, &def, JsModuleFormat::Haste))
        .chain(
            programs
                .reader
                .operations()
                .map(|def| print_operation(&schema, &def, JsModuleFormat::Haste)),
        )
        .collect::<Vec<_>>()
        .join("\n\n");

    Ok(reader_ast_string.into())
}

#[wasm_bindgen]
pub fn transform(schema_text: &str, document_text: &str) -> String {
    serialize_result(transform_impl(schema_text, document_text))
}

fn transform_impl(schema_text: &str, document_text: &str) -> PlaygroundResult {
    let schema = Arc::new(
        build_schema_with_extensions(&[schema_text], &Vec::<&str>::new())
            .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Schema(schema_text)))?,
    );
    let programs = get_programs(&schema, document_text)?;

    let transformed_operations = programs
        .operation_text
        .operations()
        .map(|operation| graphql_text_printer::print_operation(&schema, operation))
        .collect::<Vec<_>>()
        .join("\n");

    let transformed_fragments = programs
        .operation_text
        .fragments()
        .map(|operation| graphql_text_printer::print_fragment(&schema, operation))
        .collect::<Vec<_>>()
        .join("\n");

    let output = transformed_operations + "\n\n" + &transformed_fragments;
    Ok(output.into())
}

fn get_programs(schema: &Arc<SDLSchema>, document_text: &str) -> Result<Programs, PlaygroundError> {
    let document = graphql_syntax::parse_executable(document_text, Generated)
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    let ir = graphql_ir::build(&schema, &document.definitions)
        .map_err(|diagnostics| map_diagnostics(diagnostics, &InputType::Document(document_text)))?;

    let program = Program::from_definitions(schema.clone(), ir);

    let project_name = "test_project".intern();
    let base_fragment_names = Arc::new(FnvHashSet::default());
    let connection_interface = ConnectionInterface::default();
    let feature_flags = FeatureFlags::default();
    let perf_logger = NoopPerfLogger;

    apply_transforms(
        project_name,
        Arc::new(program),
        base_fragment_names,
        &connection_interface,
        Arc::new(feature_flags),
        Arc::new(perf_logger),
        None,
    )
    .map_err(|diagnostics: Vec<Diagnostic>| {
        map_diagnostics(diagnostics, &InputType::Document(document_text))
    })
}

fn map_diagnostics(diagnostics: Vec<Diagnostic>, source: &InputType<'_>) -> PlaygroundError {
    let wasm_diagnostics = diagnostics
        .iter()
        .map(|diagnostic| {
            let range = diagnostic.location().span().to_range(source.source(), 0, 0);
            WasmDiagnostic {
                message: diagnostic.print_without_source(),
                line_start: range.start.line,
                line_end: range.end.line,
                column_start: range.start.character,
                column_end: range.end.character,
            }
        })
        .collect();
    match source {
        InputType::Document(_) => PlaygroundError::DocumentDiagnostics(wasm_diagnostics),
        InputType::Schema(_) => PlaygroundError::SchemaDiagnostics(wasm_diagnostics),
    }
}

fn serialize_result(result: PlaygroundResult) -> String {
    serde_json::to_string(&result).unwrap()
}

#[wasm_bindgen(start)]
pub fn start() {
    console_error_panic_hook::set_once();
}

// #[test]
fn _disable_test() {
    let schema_text = r#"type User {
        name: String
        age: Int
        best_friend: User
      }

      type Query {
        me: User
      }"#;
    let document_text = r#"query MyQuery {
        me {
          name
          ...AgeFragment
          best_friend {
            ...AgeFragment
          }
        }
      }

      fragment AgeFragment on User {
          age
      }"#;
    let result = serialize_result(transform_impl(schema_text, document_text));

    let expected = r#"{"Ok":"query MyQuery {
  me {
    name
    age
    best_friend {
      age
    }
  }
}"}"#;

    assert_eq!(result, expected)
}
<|endoftext|>


<commit_before>use crate::MessagePath;

#[test]
fn package_names_must_be_at_least_two_characters() {
    MessagePath::new("foo", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("fo", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("f", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn package_names_must_start_with_lowercase_alphabetic() {
    MessagePath::new("foo_123", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("Foo_123", "MessageName").expect_err("Unexpected correct package name");
    MessagePath::new("1oo_123", "MessageName").expect_err("Unexpected correct package name");
    MessagePath::new("_oo_123", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn package_names_must_not_contain_uppercase_anywhere() {
    MessagePath::new("foo_123", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("foO_123", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn package_names_are_limited_to_lowercase_alphanumeric_and_underscore() {
    MessagePath::new("foo_123", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("foO_123", "MessageName").expect_err("Unexpected correct package name");
    MessagePath::new("foo-123", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn package_names_must_not_contain_multiple_underscores_in_a_row() {
    MessagePath::new("foo_123_", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("f_o_o_1_2_3_", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("foo__123_", "MessageName").expect_err("Unexpected correct package name");
    MessagePath::new("foo___123_", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn format_returns_the_full_message_name() {
    let path: MessagePath =
        MessagePath::new("foo_123", "MessageName").expect("Unexpected incorrect package name");
    assert_eq!(format!("{}", path), "foo_123/MessageName");
}
<commit_msg>Test message path serialization<commit_after>use crate::MessagePath;

#[test]
fn package_names_must_be_at_least_two_characters() {
    MessagePath::new("foo", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("fo", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("f", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn package_names_must_start_with_lowercase_alphabetic() {
    MessagePath::new("foo_123", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("Foo_123", "MessageName").expect_err("Unexpected correct package name");
    MessagePath::new("1oo_123", "MessageName").expect_err("Unexpected correct package name");
    MessagePath::new("_oo_123", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn package_names_must_not_contain_uppercase_anywhere() {
    MessagePath::new("foo_123", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("foO_123", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn package_names_are_limited_to_lowercase_alphanumeric_and_underscore() {
    MessagePath::new("foo_123", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("foO_123", "MessageName").expect_err("Unexpected correct package name");
    MessagePath::new("foo-123", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn package_names_must_not_contain_multiple_underscores_in_a_row() {
    MessagePath::new("foo_123_", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("f_o_o_1_2_3_", "MessageName").expect("Unexpected incorrect package name");
    MessagePath::new("foo__123_", "MessageName").expect_err("Unexpected correct package name");
    MessagePath::new("foo___123_", "MessageName").expect_err("Unexpected correct package name");
}

#[test]
fn format_returns_the_full_message_name() {
    let path: MessagePath =
        MessagePath::new("foo_123", "MessageName").expect("Unexpected incorrect package name");
    assert_eq!(format!("{}", path), "foo_123/MessageName");
}

#[test]
fn serialize_as_string() {
    assert_eq!(
        serde_json::to_string(&MessagePath::new("foo_123", "MessageName").unwrap()).unwrap(),
        "\"foo_123/MessageName\"",
    );
}

#[test]
fn deserialize_from_string() {
    assert_eq!(
        serde_json::from_str::<MessagePath>("\"foo_123/MessageName\"").unwrap(),
        MessagePath::new("foo_123", "MessageName").unwrap(),
    );
}

#[test]
fn deserialize_checks_if_package_name_is_valid() {
    assert!(serde_json::from_str::<MessagePath>("\"foo_123/MessageName\"").is_ok());
    assert!(serde_json::from_str::<MessagePath>("\"Foo_123/MessageName\"").is_err());
}
<|endoftext|>