<commit_before>use quote::quote;
use rustc_hash::FxHashMap;
use smol_str::SmolStr;
use std::{io::Write, str};
use syn::{parse_quote, visit::Visit};

use super::{
    find_cache::{JniCacheMacroCalls, JniCacheMacroCallsVisitor},
    java_code::filter_null_annotation,
    JavaContext, JniForeignMethodSignature,
};
use crate::{
    error::{invalid_src_id_span, panic_on_syn_error, DiagnosticError, Result, SourceIdSpan},
    typemap::ast::DisplayToTokens,
    types::MethodVariant,
    WRITE_TO_MEM_FAILED_MSG,
};

pub(in crate::java_jni) fn predefined_java_type_to_jni_sig() -> FxHashMap<SmolStr, SmolStr> {
    let mut m = FxHashMap::default();
    m.insert("String".into(), "Ljava.lang.String;".into());
    m.insert("Byte".into(), "Ljava.lang.Byte".into());
    m.insert("Short".into(), "Ljava.lang.Short".into());
    m.insert("Integer".into(), "Ljava.lang.Integer".into());
    m.insert("Long".into(), "Ljava.lang.Long".into());
    m.insert("Float".into(), "Ljava.lang.Float".into());
    m.insert("Double".into(), "Ljava.lang.Double".into());
    m.insert("boolean".into(), "Z".into());
    m.insert("byte".into(), "B".into());
    m.insert("char".into(), "C".into());
    m.insert("double".into(), "D".into());
    m.insert("float".into(), "F".into());
    m.insert("int".into(), "I".into());
    m.insert("long".into(), "J".into());
    m.insert("object".into(), "L".into());
    m.insert("short".into(), "S".into());
    m.insert("void".into(), "V".into());
    for elem in &[
        "char", "byte", "double", "float", "int", "long", "short", "boolean",
    ] {
        let jni_sig = m.get(*elem).expect("Internal error: no type");
        let arr_sig = format!("[{}", jni_sig);
        m.insert(format!("{} []", elem).into(), arr_sig.into());
    }
    m
}

fn java_type_to_jni_signature<'a>(ctx: &'a JavaContext, java_type: &str) -> Option<&'a str> {
    if java_type.contains("@NonNull") || java_type.contains("@Nullable") {
        let java_type = filter_null_annotation(java_type);
        ctx.java_type_to_jni_sig_map
            .get(java_type.trim())
            .map(SmolStr::as_str)
    } else {
        ctx.java_type_to_jni_sig_map
            .get(java_type)
            .map(SmolStr::as_str)
    }
}

pub(in crate::java_jni) fn generate_jni_func_name(
    ctx: &JavaContext,
    class_name: &str,
    class_span: SourceIdSpan,
    java_method_name: &str,
    method_type: MethodVariant,
    f_method: &JniForeignMethodSignature,
    overloaded: bool,
) -> Result<String> {
    let mut output = String::new();
    output.push_str("Java_");
    fn escape_underscore(input: &str, output: &mut String) {
        for c in input.chars() {
            match c {
                '.' => output.push('_'),
                '[' => output.push_str("_3"),
                '_' => output.push_str("_1"),
                ';' => output.push_str("_2"),
                _ => output.push(c),
            }
        }
    }
    escape_underscore(&ctx.cfg.package_name, &mut output);
    output.push_str("_");
    escape_underscore(class_name, &mut output);
    output.push_str("_");
    escape_underscore(java_method_name, &mut output);

    if overloaded {
        output.push_str("__");
        if let MethodVariant::Method(_) = method_type {
            output.push('J');
        }
        for arg in &f_method.input {
            let type_name = arg
                .java_converter
                .as_ref()
                .map(|x| x.java_transition_type.display())
                .unwrap_or_else(|| arg.as_ref().name.display());

            let type_name = java_type_to_jni_signature(ctx, type_name).ok_or_else(|| {
                DiagnosticError::new2(
                    class_span,
                    format!(
                        "Can not generate JNI function name for overload method '{}',\
                         unknown java type '{}'",
                        java_method_name,
                        arg.as_ref().name
                    ),
                )
            })?;

            escape_underscore(type_name, &mut output);
        }
    }

    Ok(output)
}

pub(in crate::java_jni) fn jni_method_signature(
    ctx: &JavaContext,
    method: &JniForeignMethodSignature,
) -> String {
    let mut ret: String = "(".into();
    for arg in &method.input {
        let java_type: String = filter_null_annotation(arg.as_ref().name.display())
            .trim()
            .into();
        let sig = java_type_to_jni_signature(ctx, &java_type).unwrap_or_else(|| {
            panic!(
                "Unknown type `{}`, can not generate JNI signature",
                java_type
            )
        });
        let sig = sig.replace('.', "/");
        ret.push_str(&sig);
    }
    ret.push(')');
    let sig =
        java_type_to_jni_signature(ctx, method.output.base.name.display()).unwrap_or_else(|| {
            panic!(
                "Unknown type `{}`, can not generate JNI signature",
                method.output.base.name
            )
        });
    ret.push_str(sig);
    ret
}

pub(in crate::java_jni) fn generate_load_unload_jni_funcs(
    generated_code: &mut Vec<u8>,
) -> Result<()> {
    let code = str::from_utf8(&generated_code).map_err(|err| {
        DiagnosticError::new2(
            invalid_src_id_span(),
            format!("Generated code not valid utf-8: {}", err),
        )
    })?;

    let file = syn::parse_file(code)
        .unwrap_or_else(|err| panic_on_syn_error("generated code", code.into(), err));
    let mut jni_cache_macro_calls = JniCacheMacroCalls::default();
    let mut visitor = JniCacheMacroCallsVisitor {
        inner: &mut jni_cache_macro_calls,
        errors: vec![],
    };
    visitor.visit_file(&file);
    if !visitor.errors.is_empty() {
        panic_on_syn_error("generated code", code.to_string(), visitor.errors.remove(0));
    }

    let mut addon_code = Vec::with_capacity(3);

    addon_code.append(&mut jni_cache_macro_calls.global_vars());

    let mut find_calls = Vec::with_capacity(jni_cache_macro_calls.calls.len());
    let mut free_find_calls = Vec::with_capacity(jni_cache_macro_calls.calls.len());
    for find_class in jni_cache_macro_calls.calls.values() {
        let mut class_get_method_id_calls = Vec::new();
        let class_name = &find_class.path;
        for m in &find_class.methods {
            let method_id = &m.id;
            let method_name = &m.name;
            let method_sig = &m.sig;
            class_get_method_id_calls.push(quote! {
                let method_id: jmethodID = (**env).GetMethodID.unwrap()(
                    env,
                    class,
                    swig_c_str!(#method_name),
                    swig_c_str!(#method_sig),
                );
                assert!(!method_id.is_null(),
                        concat!("GetMethodID for class ", #class_name,
                                " method ", #method_name,
                                " sig ", #method_sig, " failed"));
                #method_id = method_id;
            });
        }

        for m in &find_class.static_methods {
            let method_id = &m.id;
            let method_name = &m.name;
            let method_sig = &m.sig;
            class_get_method_id_calls.push(quote! {
                let method_id: jmethodID = (**env).GetStaticMethodID.unwrap()(
                    env,
                    class,
                    swig_c_str!(#method_name),
                    swig_c_str!(#method_sig),
                );
                assert!(!method_id.is_null(),
                        concat!("GetStaticMethodID for class ", #class_name,
                                " method ", #method_name,
                                " sig ", #method_sig, " failed"));
                #method_id = method_id;
            });
        }

        for m in &find_class.static_fields {
            let field_id = &m.id;
            let field_name = &m.name;
            let method_sig = &m.sig;
            class_get_method_id_calls.push(quote! {
                let field_id: jfieldID = (**env).GetStaticFieldID.unwrap()(
                    env,
                    class,
                    swig_c_str!(#field_name),
                    swig_c_str!(#method_sig),
                );
                assert!(!field_id.is_null(),
                        concat!("GetStaticFieldID for class ", #class_name,
                                " method ", #field_name,
                                " sig ", #method_sig, " failed"));
                #field_id = field_id;
            });
        }

        for m in &find_class.fields {
            let field_id = &m.id;
            let field_name = &m.name;
            let method_sig = &m.sig;
            class_get_method_id_calls.push(quote! {
                let field_id: jfieldID = (**env).GetFieldID.unwrap()(
                    env,
                    class,
                    swig_c_str!(#field_name),
                    swig_c_str!(#method_sig),
                );
                assert!(!field_id.is_null(),
                        concat!("GetStaticFieldID for class ", #class_name,
                                " method ", #field_name,
                                " sig ", #method_sig, " failed"));
                #field_id = field_id;
            });
        }

        let id = &find_class.id;
        find_calls.push(quote! {
            unsafe {
                let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!(#class_name));
                assert!(!class_local_ref.is_null(), concat!("FindClass failed for ", #class_name));
                let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref);
                assert!(!class.is_null(), concat!("FindClass failed for ", #class_name));
                (**env).DeleteLocalRef.unwrap()(env, class_local_ref);
                #id = class;
                #(#class_get_method_id_calls)*
            }
        });
        free_find_calls.push(quote! {
            unsafe {
                (**env).DeleteGlobalRef.unwrap()(env, #id);
                #id = ::std::ptr::null_mut()
            }
        });
    }

    let jni_load_func: syn::Item = parse_quote! {
        #[no_mangle]
        pub extern "system" fn JNI_OnLoad(java_vm: *mut JavaVM, _reserved: *mut ::std::os::raw::c_void) -> jint {
            println!("JNI_OnLoad begin");
            assert!(!java_vm.is_null());
            let mut env: *mut JNIEnv = ::std::ptr::null_mut();
            let res = unsafe {
                (**java_vm).GetEnv.unwrap()(
                    java_vm,
                    (&mut env) as *mut *mut JNIEnv as *mut *mut ::std::os::raw::c_void,
                    SWIG_JNI_VERSION,
                )
            };
            if res != (JNI_OK as jint) {
                panic!("JNI GetEnv in JNI_OnLoad failed, return code {}", res);
            }
            assert!(!env.is_null());
            #(#find_calls)*

            SWIG_JNI_VERSION
        }
    };
    addon_code.push(jni_load_func);
    let jni_unload_func: syn::Item = parse_quote! {
        #[no_mangle]
        pub extern "system" fn JNI_OnUnload(java_vm: *mut JavaVM, _reserved: *mut ::std::os::raw::c_void) {
            println!("JNI_OnUnLoad begin");
            assert!(!java_vm.is_null());
            let mut env: *mut JNIEnv = ::std::ptr::null_mut();
            let res = unsafe {
                (**java_vm).GetEnv.unwrap()(
                    java_vm,
                    (&mut env) as *mut *mut JNIEnv as *mut *mut ::std::os::raw::c_void,
                    SWIG_JNI_VERSION,
                )
            };
            if res != (JNI_OK as jint) {
                panic!("JNI GetEnv in JNI_OnLoad failed, return code {}", res);
            }
            assert!(!env.is_null());
            #(#free_find_calls)*
        }
    };
    addon_code.push(jni_unload_func);

    for elem in addon_code {
        write!(generated_code, "{}", DisplayToTokens(&elem)).expect(WRITE_TO_MEM_FAILED_MSG);
    }

    Ok(())
}
<commit_msg>JNI_OnLoad log::debug rather than println<commit_after>use quote::quote;
use rustc_hash::FxHashMap;
use smol_str::SmolStr;
use std::{io::Write, str};
use syn::{parse_quote, visit::Visit};

use super::{
    find_cache::{JniCacheMacroCalls, JniCacheMacroCallsVisitor},
    java_code::filter_null_annotation,
    JavaContext, JniForeignMethodSignature,
};
use crate::{
    error::{invalid_src_id_span, panic_on_syn_error, DiagnosticError, Result, SourceIdSpan},
    typemap::ast::DisplayToTokens,
    types::MethodVariant,
    WRITE_TO_MEM_FAILED_MSG,
};

pub(in crate::java_jni) fn predefined_java_type_to_jni_sig() -> FxHashMap<SmolStr, SmolStr> {
    let mut m = FxHashMap::default();
    m.insert("String".into(), "Ljava.lang.String;".into());
    m.insert("Byte".into(), "Ljava.lang.Byte".into());
    m.insert("Short".into(), "Ljava.lang.Short".into());
    m.insert("Integer".into(), "Ljava.lang.Integer".into());
    m.insert("Long".into(), "Ljava.lang.Long".into());
    m.insert("Float".into(), "Ljava.lang.Float".into());
    m.insert("Double".into(), "Ljava.lang.Double".into());
    m.insert("boolean".into(), "Z".into());
    m.insert("byte".into(), "B".into());
    m.insert("char".into(), "C".into());
    m.insert("double".into(), "D".into());
    m.insert("float".into(), "F".into());
    m.insert("int".into(), "I".into());
    m.insert("long".into(), "J".into());
    m.insert("object".into(), "L".into());
    m.insert("short".into(), "S".into());
    m.insert("void".into(), "V".into());
    for elem in &[
        "char", "byte", "double", "float", "int", "long", "short", "boolean",
    ] {
        let jni_sig = m.get(*elem).expect("Internal error: no type");
        let arr_sig = format!("[{}", jni_sig);
        m.insert(format!("{} []", elem).into(), arr_sig.into());
    }
    m
}

fn java_type_to_jni_signature<'a>(ctx: &'a JavaContext, java_type: &str) -> Option<&'a str> {
    if java_type.contains("@NonNull") || java_type.contains("@Nullable") {
        let java_type = filter_null_annotation(java_type);
        ctx.java_type_to_jni_sig_map
            .get(java_type.trim())
            .map(SmolStr::as_str)
    } else {
        ctx.java_type_to_jni_sig_map
            .get(java_type)
            .map(SmolStr::as_str)
    }
}

pub(in crate::java_jni) fn generate_jni_func_name(
    ctx: &JavaContext,
    class_name: &str,
    class_span: SourceIdSpan,
    java_method_name: &str,
    method_type: MethodVariant,
    f_method: &JniForeignMethodSignature,
    overloaded: bool,
) -> Result<String> {
    let mut output = String::new();
    output.push_str("Java_");
    fn escape_underscore(input: &str, output: &mut String) {
        for c in input.chars() {
            match c {
                '.' => output.push('_'),
                '[' => output.push_str("_3"),
                '_' => output.push_str("_1"),
                ';' => output.push_str("_2"),
                _ => output.push(c),
            }
        }
    }
    escape_underscore(&ctx.cfg.package_name, &mut output);
    output.push_str("_");
    escape_underscore(class_name, &mut output);
    output.push_str("_");
    escape_underscore(java_method_name, &mut output);

    if overloaded {
        output.push_str("__");
        if let MethodVariant::Method(_) = method_type {
            output.push('J');
        }
        for arg in &f_method.input {
            let type_name = arg
                .java_converter
                .as_ref()
                .map(|x| x.java_transition_type.display())
                .unwrap_or_else(|| arg.as_ref().name.display());

            let type_name = java_type_to_jni_signature(ctx, type_name).ok_or_else(|| {
                DiagnosticError::new2(
                    class_span,
                    format!(
                        "Can not generate JNI function name for overload method '{}',\
                         unknown java type '{}'",
                        java_method_name,
                        arg.as_ref().name
                    ),
                )
            })?;

            escape_underscore(type_name, &mut output);
        }
    }

    Ok(output)
}

pub(in crate::java_jni) fn jni_method_signature(
    ctx: &JavaContext,
    method: &JniForeignMethodSignature,
) -> String {
    let mut ret: String = "(".into();
    for arg in &method.input {
        let java_type: String = filter_null_annotation(arg.as_ref().name.display())
            .trim()
            .into();
        let sig = java_type_to_jni_signature(ctx, &java_type).unwrap_or_else(|| {
            panic!(
                "Unknown type `{}`, can not generate JNI signature",
                java_type
            )
        });
        let sig = sig.replace('.', "/");
        ret.push_str(&sig);
    }
    ret.push(')');
    let sig =
        java_type_to_jni_signature(ctx, method.output.base.name.display()).unwrap_or_else(|| {
            panic!(
                "Unknown type `{}`, can not generate JNI signature",
                method.output.base.name
            )
        });
    ret.push_str(sig);
    ret
}

pub(in crate::java_jni) fn generate_load_unload_jni_funcs(
    generated_code: &mut Vec<u8>,
) -> Result<()> {
    let code = str::from_utf8(&generated_code).map_err(|err| {
        DiagnosticError::new2(
            invalid_src_id_span(),
            format!("Generated code not valid utf-8: {}", err),
        )
    })?;

    let file = syn::parse_file(code)
        .unwrap_or_else(|err| panic_on_syn_error("generated code", code.into(), err));
    let mut jni_cache_macro_calls = JniCacheMacroCalls::default();
    let mut visitor = JniCacheMacroCallsVisitor {
        inner: &mut jni_cache_macro_calls,
        errors: vec![],
    };
    visitor.visit_file(&file);
    if !visitor.errors.is_empty() {
        panic_on_syn_error("generated code", code.to_string(), visitor.errors.remove(0));
    }

    let mut addon_code = Vec::with_capacity(3);

    addon_code.append(&mut jni_cache_macro_calls.global_vars());

    let mut find_calls = Vec::with_capacity(jni_cache_macro_calls.calls.len());
    let mut free_find_calls = Vec::with_capacity(jni_cache_macro_calls.calls.len());
    for find_class in jni_cache_macro_calls.calls.values() {
        let mut class_get_method_id_calls = Vec::new();
        let class_name = &find_class.path;
        for m in &find_class.methods {
            let method_id = &m.id;
            let method_name = &m.name;
            let method_sig = &m.sig;
            class_get_method_id_calls.push(quote! {
                let method_id: jmethodID = (**env).GetMethodID.unwrap()(
                    env,
                    class,
                    swig_c_str!(#method_name),
                    swig_c_str!(#method_sig),
                );
                assert!(!method_id.is_null(),
                        concat!("GetMethodID for class ", #class_name,
                                " method ", #method_name,
                                " sig ", #method_sig, " failed"));
                #method_id = method_id;
            });
        }

        for m in &find_class.static_methods {
            let method_id = &m.id;
            let method_name = &m.name;
            let method_sig = &m.sig;
            class_get_method_id_calls.push(quote! {
                let method_id: jmethodID = (**env).GetStaticMethodID.unwrap()(
                    env,
                    class,
                    swig_c_str!(#method_name),
                    swig_c_str!(#method_sig),
                );
                assert!(!method_id.is_null(),
                        concat!("GetStaticMethodID for class ", #class_name,
                                " method ", #method_name,
                                " sig ", #method_sig, " failed"));
                #method_id = method_id;
            });
        }

        for m in &find_class.static_fields {
            let field_id = &m.id;
            let field_name = &m.name;
            let method_sig = &m.sig;
            class_get_method_id_calls.push(quote! {
                let field_id: jfieldID = (**env).GetStaticFieldID.unwrap()(
                    env,
                    class,
                    swig_c_str!(#field_name),
                    swig_c_str!(#method_sig),
                );
                assert!(!field_id.is_null(),
                        concat!("GetStaticFieldID for class ", #class_name,
                                " method ", #field_name,
                                " sig ", #method_sig, " failed"));
                #field_id = field_id;
            });
        }

        for m in &find_class.fields {
            let field_id = &m.id;
            let field_name = &m.name;
            let method_sig = &m.sig;
            class_get_method_id_calls.push(quote! {
                let field_id: jfieldID = (**env).GetFieldID.unwrap()(
                    env,
                    class,
                    swig_c_str!(#field_name),
                    swig_c_str!(#method_sig),
                );
                assert!(!field_id.is_null(),
                        concat!("GetStaticFieldID for class ", #class_name,
                                " method ", #field_name,
                                " sig ", #method_sig, " failed"));
                #field_id = field_id;
            });
        }

        let id = &find_class.id;
        find_calls.push(quote! {
            unsafe {
                let class_local_ref = (**env).FindClass.unwrap()(env, swig_c_str!(#class_name));
                assert!(!class_local_ref.is_null(), concat!("FindClass failed for ", #class_name));
                let class = (**env).NewGlobalRef.unwrap()(env, class_local_ref);
                assert!(!class.is_null(), concat!("FindClass failed for ", #class_name));
                (**env).DeleteLocalRef.unwrap()(env, class_local_ref);
                #id = class;
                #(#class_get_method_id_calls)*
            }
        });
        free_find_calls.push(quote! {
            unsafe {
                (**env).DeleteGlobalRef.unwrap()(env, #id);
                #id = ::std::ptr::null_mut()
            }
        });
    }

    let jni_load_func: syn::Item = parse_quote! {
        #[no_mangle]
        pub extern "system" fn JNI_OnLoad(java_vm: *mut JavaVM, _reserved: *mut ::std::os::raw::c_void) -> jint {
            log::debug!("JNI_OnLoad begin");
            assert!(!java_vm.is_null());
            let mut env: *mut JNIEnv = ::std::ptr::null_mut();
            let res = unsafe {
                (**java_vm).GetEnv.unwrap()(
                    java_vm,
                    (&mut env) as *mut *mut JNIEnv as *mut *mut ::std::os::raw::c_void,
                    SWIG_JNI_VERSION,
                )
            };
            if res != (JNI_OK as jint) {
                panic!("JNI GetEnv in JNI_OnLoad failed, return code {}", res);
            }
            assert!(!env.is_null());
            #(#find_calls)*

            SWIG_JNI_VERSION
        }
    };
    addon_code.push(jni_load_func);
    let jni_unload_func: syn::Item = parse_quote! {
        #[no_mangle]
        pub extern "system" fn JNI_OnUnload(java_vm: *mut JavaVM, _reserved: *mut ::std::os::raw::c_void) {
            log::debug!("JNI_OnUnLoad begin");
            assert!(!java_vm.is_null());
            let mut env: *mut JNIEnv = ::std::ptr::null_mut();
            let res = unsafe {
                (**java_vm).GetEnv.unwrap()(
                    java_vm,
                    (&mut env) as *mut *mut JNIEnv as *mut *mut ::std::os::raw::c_void,
                    SWIG_JNI_VERSION,
                )
            };
            if res != (JNI_OK as jint) {
                panic!("JNI GetEnv in JNI_OnLoad failed, return code {}", res);
            }
            assert!(!env.is_null());
            #(#free_find_calls)*
        }
    };
    addon_code.push(jni_unload_func);

    for elem in addon_code {
        write!(generated_code, "{}", DisplayToTokens(&elem)).expect(WRITE_TO_MEM_FAILED_MSG);
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Tests for `cargo-features` definitions.

use cargo_test_support::{project, registry};

#[cargo_test]
fn feature_required() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the `im-a-teapot` manifest key is unstable and may not work properly in England

Caused by:
  feature `test-dummy-unstable` is required

  consider adding `cargo-features = [\"test-dummy-unstable\"]` to the manifest
",
        )
        .run();

    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the `im-a-teapot` manifest key is unstable and may not work properly in England

Caused by:
  feature `test-dummy-unstable` is required

  this Cargo does not support nightly features, but if you
  switch to nightly channel you can add
  `cargo-features = [\"test-dummy-unstable\"]` to enable this feature
",
        )
        .run();
}

#[cargo_test]
fn unknown_feature() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["foo"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  unknown cargo feature `foo`
",
        )
        .run();
}

#[cargo_test]
fn stable_feature_warns() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-stable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .with_stderr(
            "\
warning: the cargo feature `test-dummy-stable` has been stabilized in the 1.0 \
release and is no longer necessary to be listed in the manifest
  See https://doc.rust-lang.org/[..]cargo/ for more information about using this feature.
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn allow_features() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc

    p.cargo("-Zallow-features=test-dummy-unstable build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("-Zallow-features=test-dummy-unstable,print-im-a-teapot -Zprint-im-a-teapot build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_stdout("im-a-teapot = true")
        .run();

    p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_status(101)
        .with_stderr(
            "\
error: the feature `print-im-a-teapot` is not in the list of allowed features: [test-dummy-unstable]
",
        )
        .run();

    p.cargo("-Zallow-features= build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the feature `test-dummy-unstable` is not in the list of allowed features: []
",
        )
        .run();
}

#[cargo_test]
fn allow_features_to_rustc() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "a"
                version = "0.0.1"
                authors = []
            "#,
        )
        .file(
            "src/lib.rs",
            r#"
                #![feature(test_2018_feature)]
            "#,
        )
        .build();

    // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc

    p.cargo("-Zallow-features= build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_status(101)
        .with_stderr_contains("[..]E0725[..]")
        .run();

    p.cargo("-Zallow-features=test_2018_feature build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn allow_features_in_cfg() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [unstable]
                allow-features = ["test-dummy-unstable", "print-im-a-teapot"]
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    // NOTE: We need to use RUSTC_BOOTSTRAP here since we also need nightly rustc

    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("-Zprint-im-a-teapot build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_stdout("im-a-teapot = true")
        .with_stderr("[FINISHED] [..]")
        .run();

    p.cargo("-Zunstable-options build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_status(101)
        .with_stderr(
            "\
error: the feature `unstable-options` is not in the list of allowed features: [print-im-a-teapot, test-dummy-unstable]
",
        )
        .run();

    // -Zallow-features overrides .cargo/config
    p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_status(101)
        .with_stderr(
            "\
error: the feature `print-im-a-teapot` is not in the list of allowed features: [test-dummy-unstable]
",
        )
        .run();

    p.cargo("-Zallow-features= build")
        .masquerade_as_nightly_cargo()
        .env("RUSTC_BOOTSTRAP", "1")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the feature `test-dummy-unstable` is not in the list of allowed features: []
",
        )
        .run();
}

#[cargo_test]
fn nightly_feature_requires_nightly() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
  but this is the `stable` channel
  See [..]
  See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \
  information about using this feature.
",
        )
        .run();
}

#[cargo_test]
fn nightly_feature_requires_nightly_in_dep() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "b"
                version = "0.0.1"
                authors = []

                [dependencies]
                a = { path = "a" }
            "#,
        )
        .file("src/lib.rs", "")
        .file(
            "a/Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("a/src/lib.rs", "")
        .build();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[COMPILING] b [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
[ERROR] failed to get `a` as a dependency of package `b v0.0.1 ([..])`

Caused by:
  failed to load source for dependency `a`

Caused by:
  Unable to update [..]

Caused by:
  failed to parse manifest at `[..]`

Caused by:
  the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
  but this is the `stable` channel
  See [..]
  See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \
  information about using this feature.
",
        )
        .run();
}

#[cargo_test]
fn cant_publish() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
  but this is the `stable` channel
  See [..]
  See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \
  information about using this feature.
",
        )
        .run();
}

#[cargo_test]
fn z_flags_rejected() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -Zprint-im-a-teapot")
        .with_status(101)
        .with_stderr(
            "error: the `-Z` flag is only accepted on the nightly \
             channel of Cargo, but this is the `stable` channel\n\
             See [..]",
        )
        .run();

    p.cargo("build -Zarg")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr("error: unknown `-Z` flag specified: arg")
        .run();

    p.cargo("build -Zprint-im-a-teapot")
        .masquerade_as_nightly_cargo()
        .with_stdout("im-a-teapot = true\n")
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn publish_allowed() {
    registry::init();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("publish --token sekrit")
        .masquerade_as_nightly_cargo()
        .run();
}

#[cargo_test]
fn wrong_position() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"
                cargo-features = ["test-dummy-unstable"]
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("check")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at [..]

Caused by:
  cargo-features = [\"test-dummy-unstable\"] was found in the wrong location, it \
  should be set at the top of Cargo.toml before any tables
",
        )
        .run();
}

#[cargo_test]
fn z_stabilized() {
    let p = project().file("src/lib.rs", "").build();

    p.cargo("check -Z cache-messages")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
warning: flag `-Z cache-messages` has been stabilized in the 1.40 release, \
  and is no longer necessary
  Message caching is now always enabled.

[CHECKING] foo [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("check -Z offline")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: flag `-Z offline` has been stabilized in the 1.36 release
  Offline mode is now available via the --offline CLI option

",
        )
        .run();
}
<commit_msg>Don't use RUSTC_BOOTSTRAP for nightly-only tests<commit_after>//! Tests for `cargo-features` definitions.

use cargo_test_support::{is_nightly, project, registry};

#[cargo_test]
fn feature_required() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the `im-a-teapot` manifest key is unstable and may not work properly in England

Caused by:
  feature `test-dummy-unstable` is required

  consider adding `cargo-features = [\"test-dummy-unstable\"]` to the manifest
",
        )
        .run();

    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the `im-a-teapot` manifest key is unstable and may not work properly in England

Caused by:
  feature `test-dummy-unstable` is required

  this Cargo does not support nightly features, but if you
  switch to nightly channel you can add
  `cargo-features = [\"test-dummy-unstable\"]` to enable this feature
",
        )
        .run();
}

#[cargo_test]
fn unknown_feature() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["foo"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  unknown cargo feature `foo`
",
        )
        .run();
}

#[cargo_test]
fn stable_feature_warns() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-stable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .with_stderr(
            "\
warning: the cargo feature `test-dummy-stable` has been stabilized in the 1.0 \
release and is no longer necessary to be listed in the manifest
  See https://doc.rust-lang.org/[..]cargo/ for more information about using this feature.
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn allow_features() {
    if !is_nightly() {
        // -Zallow-features on rustc is nightly only
        eprintln!("skipping test allow_features without nightly rustc");
        return;
    }

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("-Zallow-features=test-dummy-unstable build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("-Zallow-features=test-dummy-unstable,print-im-a-teapot -Zprint-im-a-teapot build")
        .masquerade_as_nightly_cargo()
        .with_stdout("im-a-teapot = true")
        .run();

    p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: the feature `print-im-a-teapot` is not in the list of allowed features: [test-dummy-unstable]
",
        )
        .run();

    p.cargo("-Zallow-features= build")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the feature `test-dummy-unstable` is not in the list of allowed features: []
",
        )
        .run();
}

#[cargo_test]
fn allow_features_to_rustc() {
    if !is_nightly() {
        // -Zallow-features on rustc is nightly only
        eprintln!("skipping test allow_features_to_rustc without nightly rustc");
        return;
    }

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "a"
                version = "0.0.1"
                authors = []
            "#,
        )
        .file(
            "src/lib.rs",
            r#"
                #![feature(test_2018_feature)]
            "#,
        )
        .build();

    p.cargo("-Zallow-features= build")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr_contains("[..]E0725[..]")
        .run();

    p.cargo("-Zallow-features=test_2018_feature build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn allow_features_in_cfg() {
    if !is_nightly() {
        // -Zallow-features on rustc is nightly only
        eprintln!("skipping test allow_features_in_cfg without nightly rustc");
        return;
    }

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [unstable]
                allow-features = ["test-dummy-unstable", "print-im-a-teapot"]
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("-Zprint-im-a-teapot build")
        .masquerade_as_nightly_cargo()
        .with_stdout("im-a-teapot = true")
        .with_stderr("[FINISHED] [..]")
        .run();

    p.cargo("-Zunstable-options build")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: the feature `unstable-options` is not in the list of allowed features: [print-im-a-teapot, test-dummy-unstable]
",
        )
        .run();

    // -Zallow-features overrides .cargo/config
    p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot build")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: the feature `print-im-a-teapot` is not in the list of allowed features: [test-dummy-unstable]
",
        )
        .run();

    p.cargo("-Zallow-features= build")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the feature `test-dummy-unstable` is not in the list of allowed features: []
",
        )
        .run();
}

#[cargo_test]
fn nightly_feature_requires_nightly() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
  but this is the `stable` channel
  See [..]
  See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \
  information about using this feature.
",
        )
        .run();
}

#[cargo_test]
fn nightly_feature_requires_nightly_in_dep() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "b"
                version = "0.0.1"
                authors = []

                [dependencies]
                a = { path = "a" }
            "#,
        )
        .file("src/lib.rs", "")
        .file(
            "a/Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("a/src/lib.rs", "")
        .build();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[COMPILING] b [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
[ERROR] failed to get `a` as a dependency of package `b v0.0.1 ([..])`

Caused by:
  failed to load source for dependency `a`

Caused by:
  Unable to update [..]

Caused by:
  failed to parse manifest at `[..]`

Caused by:
  the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
  but this is the `stable` channel
  See [..]
  See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \
  information about using this feature.
",
        )
        .run();
}

#[cargo_test]
fn cant_publish() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("build")
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at `[..]`

Caused by:
  the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
  but this is the `stable` channel
  See [..]
  See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \
  information about using this feature.
",
        )
        .run();
}

#[cargo_test]
fn z_flags_rejected() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
                im-a-teapot = true
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -Zprint-im-a-teapot")
        .with_status(101)
        .with_stderr(
            "error: the `-Z` flag is only accepted on the nightly \
             channel of Cargo, but this is the `stable` channel\n\
             See [..]",
        )
        .run();

    p.cargo("build -Zarg")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr("error: unknown `-Z` flag specified: arg")
        .run();

    p.cargo("build -Zprint-im-a-teapot")
        .masquerade_as_nightly_cargo()
        .with_stdout("im-a-teapot = true\n")
        .with_stderr(
            "\
[COMPILING] a [..]
[FINISHED] [..]
",
        )
        .run();
}

#[cargo_test]
fn publish_allowed() {
    registry::init();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                cargo-features = ["test-dummy-unstable"]

                [package]
                name = "a"
                version = "0.0.1"
                authors = []
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("publish --token sekrit")
        .masquerade_as_nightly_cargo()
        .run();
}

#[cargo_test]
fn wrong_position() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"
                cargo-features = ["test-dummy-unstable"]
            "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("check")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: failed to parse manifest at [..]

Caused by:
  cargo-features = [\"test-dummy-unstable\"] was found in the wrong location, it \
  should be set at the top of Cargo.toml before any tables
",
        )
        .run();
}

#[cargo_test]
fn z_stabilized() {
    let p = project().file("src/lib.rs", "").build();

    p.cargo("check -Z cache-messages")
        .masquerade_as_nightly_cargo()
        .with_stderr(
            "\
warning: flag `-Z cache-messages` has been stabilized in the 1.40 release, \
  and is no longer necessary
  Message caching is now always enabled.

[CHECKING] foo [..]
[FINISHED] [..]
",
        )
        .run();

    p.cargo("check -Z offline")
        .masquerade_as_nightly_cargo()
        .with_status(101)
        .with_stderr(
            "\
error: flag `-Z offline` has been stabilized in the 1.36 release
  Offline mode is now available via the --offline CLI option

",
        )
        .run();
}
<|endoftext|>


<commit_before>use super::gl;
use std::mem;
use std::raw;

pub trait VertexData: Copy {
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy)]
pub enum DataType {
    BYTE = gl::BYTE as isize,
    UNSIGNED_BYTE = gl::UNSIGNED_BYTE as isize,
    SHORT = gl::SHORT as isize,
    UNSIGNED_SHORT = gl::UNSIGNED_SHORT as isize,
    FIXED = gl::FIXED as isize,
    FLOAT = gl::FLOAT as isize
}
pub use self::DataType::*;

pub trait VertexBytes {
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            mem::transmute(raw::Slice::<Self> {
                data: self,
                len: mem::size_of::<Self>()
            })
        }
    }
}

#[macro_export]
macro_rules! vertex_data {
    (struct $name:ident {
        $($field_name:ident: $field_type:ty),*
    }) => {
        mod _glitter_vertex_data {
            #[allow(non_snake_case)]
            pub mod $name {
                #[repr(C)]
                #[derive(Debug, Clone, Copy)]
                pub struct $name {
                    $($field_name: $field_type),*
                }

                impl $crate::VertexData for $name {

                }
            }
        }

        #[allow(unused_imports)]
        use self::_glitter_vertex_data::$name::$name;
    }
}
<commit_msg>Support defining multiple structs in a `vertex_data!` block<commit_after>use super::gl;
use std::mem;
use std::raw;

pub trait VertexData: Copy {
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy)]
pub enum DataType {
    BYTE = gl::BYTE as isize,
    UNSIGNED_BYTE = gl::UNSIGNED_BYTE as isize,
    SHORT = gl::SHORT as isize,
    UNSIGNED_SHORT = gl::UNSIGNED_SHORT as isize,
    FIXED = gl::FIXED as isize,
    FLOAT = gl::FLOAT as isize
}
pub use self::DataType::*;

pub trait VertexBytes {
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            mem::transmute(raw::Slice::<Self> {
                data: self,
                len: mem::size_of::<Self>()
            })
        }
    }
}

#[macro_export]
macro_rules! vertex_data {
    ($(
        struct $name:ident {
            $($field_name:ident: $field_type:ty),*
        }
    )+) => {
        mod _glitter_vertex_data {
            $(
                #[allow(non_snake_case)]
                pub mod $name {
                    #[repr(C)]
                    #[derive(Debug, Clone, Copy)]
                    pub struct $name {
                        $($field_name: $field_type),*
                    }

                    impl $crate::VertexData for $name {

                    }
                }
            )+
        }

        $(
            #[allow(unused_imports)]
            use self::_glitter_vertex_data::$name::$name;
        )+
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate serde_json;
extern crate mimir;

use mimir::Members;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    ::launch_and_assert(osm2mimir,
                        vec!["--input=./tests/fixtures/three_cities.osm.pbf".into(),
                             "--import-way".into(),
                             "--import-admin".into(),
                             "--level=8".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);
    // Test: Import of Admin
    let res: Vec<_> = es_wrapper.search_and_filter("label:Livry-sur-Seine", |_| true).collect();
    assert_eq!(res.len(), 4);
    assert!(res.iter().any(|r| r.is_admin()));

    // Test: search for "Rue des Près"
    let res: Vec<_> = es_wrapper.search_and_filter("label:Rue des Près", |_| true).collect();
    assert!(res.len() != 0);
    assert!(res[0].is_street());
    // The first hit should be "Rue des Près"
    assert!(res[0].label() == "Rue des Près (Livry-sur-Seine)");

    // And there should be only ONE "Rue des Près"
    assert_eq!(res.iter().filter(|place| place.is_street() && place.label() == "Rue des Près (Livry-sur-Seine)").count(), 1);

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let place_filter = |place: &mimir::Place| {
        place.is_street() && place.label() == "Rue du Four à Chaux (Livry-sur-Seine)" &&
        place.admins().first().map(|admin| admin.label() == "Livry-sur-Seine").unwrap_or(false)
    };
    //As we merge all ways with same name and of the same admin(level=city_level)
    //Here we have only one way
    let nb = es_wrapper.search_and_filter("label:Rue du Four à Chaux (Livry-sur-Seine)", place_filter).count();
    assert_eq!(nb, 1);

    // Test: Streets having the same label in different cities
    let place_filter = |place: &mimir::Place| {
        place.is_street() && place.label() == "Rue du Port (Melun)"
        && place.admins().first().map(|admin| admin.label() == "Melun").unwrap_or(false)
    };
    let nb = es_wrapper.search_and_filter("label:Rue du Port (Melun)", place_filter).count();
    assert_eq!(nb, 1);
}
<commit_msg>long line<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate serde_json;
extern crate mimir;

use mimir::Members;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    ::launch_and_assert(osm2mimir,
                        vec!["--input=./tests/fixtures/three_cities.osm.pbf".into(),
                             "--import-way".into(),
                             "--import-admin".into(),
                             "--level=8".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);
    // Test: Import of Admin
    let res: Vec<_> = es_wrapper.search_and_filter("label:Livry-sur-Seine", |_| true).collect();
    assert_eq!(res.len(), 4);
    assert!(res.iter().any(|r| r.is_admin()));

    // Test: search for "Rue des Près"
    let res: Vec<_> = es_wrapper.search_and_filter("label:Rue des Près", |_| true).collect();
    assert!(res.len() != 0);
    assert!(res[0].is_street());
    // The first hit should be "Rue des Près"
    assert!(res[0].label() == "Rue des Près (Livry-sur-Seine)");

    // And there should be only ONE "Rue des Près"
    assert_eq!(res.iter().filter(|place| place.is_street() && place.label()
            == "Rue des Près (Livry-sur-Seine)").count(), 1);

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let place_filter = |place: &mimir::Place| {
        place.is_street() && place.label() == "Rue du Four à Chaux (Livry-sur-Seine)" &&
        place.admins().first().map(|admin| admin.label() == "Livry-sur-Seine").unwrap_or(false)
    };
    //As we merge all ways with same name and of the same admin(level=city_level)
    //Here we have only one way
    let nb = es_wrapper.search_and_filter("label:Rue du Four à Chaux (Livry-sur-Seine)",
        place_filter).count();
    assert_eq!(nb, 1);

    // Test: Streets having the same label in different cities
    let place_filter = |place: &mimir::Place| {
        place.is_street() && place.label() == "Rue du Port (Melun)"
        && place.admins().first().map(|admin| admin.label() == "Melun").unwrap_or(false)
    };
    let nb = es_wrapper.search_and_filter("label:Rue du Port (Melun)", place_filter).count();
    assert_eq!(nb, 1);
}
<|endoftext|>


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

use std::io::stdin;

use linefeed::{
    DefaultTerminal,
    Reader,
    ReadResult,
};

use self::InputResult::*;

use command_parser::{
    Command,
    command,
};

use errors as cli;

/// Starting prompt
const DEFAULT_PROMPT: &'static str = "mentat=> ";
/// Prompt when further input is being read
// TODO: Should this actually reflect the current open brace?
const MORE_PROMPT: &'static str = "mentat.> ";

/// Possible results from reading input from `InputReader`
#[derive(Clone, Debug)]
pub enum InputResult {
    /// mentat command as input; (name, rest of line)
    MetaCommand(Command),
    /// An empty line
    Empty,
    /// Needs more input
    More,
    /// End of file reached
    Eof,
}

/// Reads input from `stdin`
pub struct InputReader {
    buffer: String,
    reader: Option<Reader<DefaultTerminal>>,
    in_process_cmd: Option<Command>,
}

impl InputReader {
    /// Constructs a new `InputReader` reading from `stdin`.
    pub fn new() -> InputReader {
        let r = match Reader::new("mentat") {
            Ok(mut r) => {
                r.set_word_break_chars(" \t\n!\"#$%&'(){}*+,-./:;<=>?@[\\]^`");
                Some(r)
            },
            Err(_) => None,
        };

        InputReader{
            buffer: String::new(),
            reader: r,
            in_process_cmd: None,
        }
    }

    /// Returns whether the `InputReader` is reading from a TTY.
    pub fn is_tty(&self) -> bool {
        self.reader.is_some()
    }

    /// Reads a single command, item, or statement from `stdin`.
    /// Returns `More` if further input is required for a complete result.
    /// In this case, the input received so far is buffered internally.
    pub fn read_input(&mut self) -> Result<InputResult, cli::Error> {
        let prompt = if self.in_process_cmd.is_some() { MORE_PROMPT } else { DEFAULT_PROMPT };
        let line = match self.read_line(prompt) {
            Some(s) => s,
            None => return Ok(Eof),
        };

        if !self.buffer.is_empty() {
            self.buffer.push('\n');
        }

        self.buffer.push_str(&line);

        if self.buffer.is_empty() {
            return Ok(Empty);
        }

        // if we have a command in process (i.e. an incomplete query or transaction),
        // then we already know which type of command it is and so we don't need to parse the
        // command again, only the content, which we do later.
        // Therefore, we add the newly read in line to the existing command args.
        // If there is no in process command, we parse the read in line as a new command.
        let cmd = match &self.in_process_cmd {
            &Some(Command::Query(ref args)) => {
                Ok(Command::Query(args.clone() + " " + &line))
            },
            &Some(Command::Transact(ref args)) => {
                Ok(Command::Transact(args.clone() + " " + &line))
            },
            _ => {
                command(&self.buffer)
            },
        };

        match cmd {
            Ok(cmd) => {
                match cmd {
                    Command::Query(_) |
                    Command::Transact(_) |
                    Command::QueryExplain(_) if !cmd.is_complete() => {
                        // A query or transact is complete if it contains a valid EDN.
                        // if the command is not complete, ask for more from the REPL and remember
                        // which type of command we've found here.
                        self.in_process_cmd = Some(cmd);
                        Ok(More)
                    },
                    _ => {
                        let entry = self.buffer.clone();
                        self.buffer.clear();
                        self.add_history(entry);
                        self.in_process_cmd = None;
                        Ok(InputResult::MetaCommand(cmd))
                    }
                }
            },
            Err(e) => {
                let entry = self.buffer.clone();
                self.buffer.clear();
                self.add_history(entry);
                self.in_process_cmd = None;
                Err(e)
            },
        }
    }

    fn read_line(&mut self, prompt: &str) -> Option<String> {
        match self.reader {
            Some(ref mut r) => {
                r.set_prompt(prompt);
                r.read_line().ok().and_then(|line|
                    match line {
                        ReadResult::Input(s) => Some(s),
                        _ => None
                    })

            },
            None => self.read_stdin()
        }
    }

    fn read_stdin(&self) -> Option<String> {
        let mut s = String::new();

        match stdin().read_line(&mut s) {
            Ok(0) | Err(_) => None,
            Ok(_) => Some(s)
        }
    }

    fn add_history(&mut self, line: String) {
        if let Some(ref mut r) = self.reader {
            r.add_history(line);
        }
    }
}
<commit_msg>Add support for Ctrl-C aborting the current command on the CLI (#528) r=rnewman<commit_after>// Copyright 2017 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

use std::io::stdin;

use linefeed::{
    DefaultTerminal,
    Reader,
    ReadResult,
    Signal,
};

use self::InputResult::*;

use command_parser::{
    Command,
    command,
};

use errors as cli;

/// Starting prompt
const DEFAULT_PROMPT: &'static str = "mentat=> ";
/// Prompt when further input is being read
// TODO: Should this actually reflect the current open brace?
const MORE_PROMPT: &'static str = "mentat.> ";

/// Possible results from reading input from `InputReader`
#[derive(Clone, Debug)]
pub enum InputResult {
    /// mentat command as input; (name, rest of line)
    MetaCommand(Command),
    /// An empty line
    Empty,
    /// Needs more input
    More,
    /// End of file reached
    Eof,
}

/// Reads input from `stdin`
pub struct InputReader {
    buffer: String,
    reader: Option<Reader<DefaultTerminal>>,
    in_process_cmd: Option<Command>,
}

enum UserAction {
    // We've received some text that we should interpret as a new command, or
    // as part of the current command.
    TextInput(String),
    // We were interrupted, if we have a current command we should clear it,
    // otherwise we should exit. Currently can only be generated by reading from
    // a terminal (and not by reading from stdin).
    Interrupt,
    // We hit the end of the file, there was an error getting user input, or
    // something else happened that means we should exit.
    Quit,
}

impl InputReader {
    /// Constructs a new `InputReader` reading from `stdin`.
    pub fn new() -> InputReader {
        let r = match Reader::new("mentat") {
            Ok(mut r) => {
                // Handle SIGINT (Ctrl-C)
                r.set_report_signal(Signal::Interrupt, true);
                r.set_word_break_chars(" \t\n!\"#$%&'(){}*+,-./:;<=>?@[\\]^`");
                Some(r)
            },
            Err(_) => None,
        };

        InputReader{
            buffer: String::new(),
            reader: r,
            in_process_cmd: None,
        }
    }

    /// Returns whether the `InputReader` is reading from a TTY.
    pub fn is_tty(&self) -> bool {
        self.reader.is_some()
    }

    /// Reads a single command, item, or statement from `stdin`.
    /// Returns `More` if further input is required for a complete result.
    /// In this case, the input received so far is buffered internally.
    pub fn read_input(&mut self) -> Result<InputResult, cli::Error> {
        let prompt = if self.in_process_cmd.is_some() { MORE_PROMPT } else { DEFAULT_PROMPT };
        let line = match self.read_line(prompt) {
            UserAction::TextInput(s) => s,
            UserAction::Interrupt if self.in_process_cmd.is_some() => {
                self.in_process_cmd = None;
                self.buffer.clear();
                // Move to the next line, so that our next prompt isn't on top
                // of the previous.
                println!();
                String::new()
            },
            _ => return Ok(Eof),
        };

        if !self.buffer.is_empty() {
            self.buffer.push('\n');
        }

        self.buffer.push_str(&line);

        if self.buffer.is_empty() {
            return Ok(Empty);
        }

        // if we have a command in process (i.e. an incomplete query or transaction),
        // then we already know which type of command it is and so we don't need to parse the
        // command again, only the content, which we do later.
        // Therefore, we add the newly read in line to the existing command args.
        // If there is no in process command, we parse the read in line as a new command.
        let cmd = match &self.in_process_cmd {
            &Some(Command::Query(ref args)) => {
                Ok(Command::Query(args.clone() + " " + &line))
            },
            &Some(Command::Transact(ref args)) => {
                Ok(Command::Transact(args.clone() + " " + &line))
            },
            _ => {
                command(&self.buffer)
            },
        };

        match cmd {
            Ok(cmd) => {
                match cmd {
                    Command::Query(_) |
                    Command::Transact(_) |
                    Command::QueryExplain(_) if !cmd.is_complete() => {
                        // A query or transact is complete if it contains a valid EDN.
                        // if the command is not complete, ask for more from the REPL and remember
                        // which type of command we've found here.
                        self.in_process_cmd = Some(cmd);
                        Ok(More)
                    },
                    _ => {
                        let entry = self.buffer.clone();
                        self.buffer.clear();
                        self.add_history(entry);
                        self.in_process_cmd = None;
                        Ok(InputResult::MetaCommand(cmd))
                    }
                }
            },
            Err(e) => {
                let entry = self.buffer.clone();
                self.buffer.clear();
                self.add_history(entry);
                self.in_process_cmd = None;
                Err(e)
            },
        }
    }

    fn read_line(&mut self, prompt: &str) -> UserAction {
        match self.reader {
            Some(ref mut r) => {
                r.set_prompt(prompt);
                r.read_line().ok().map_or(UserAction::Quit, |line|
                    match line {
                        ReadResult::Input(s) => UserAction::TextInput(s),
                        ReadResult::Signal(Signal::Interrupt) =>
                            UserAction::Interrupt,
                        _ => UserAction::Quit,
                    })

            },
            None => self.read_stdin()
        }
    }

    fn read_stdin(&self) -> UserAction {
        let mut s = String::new();

        match stdin().read_line(&mut s) {
            Ok(0) | Err(_) => UserAction::Quit,
            Ok(_) => UserAction::TextInput(s)
        }
    }

    fn add_history(&mut self, line: String) {
        if let Some(ref mut r) = self.reader {
            r.add_history(line);
        }
    }
}
<|endoftext|>


<commit_before>extern crate proc_macro;
extern crate proc_macro2;
extern crate syn;

use crate::proc_macro::TokenStream;
use quote::quote;

fn derive_using_macro(input: TokenStream, macro_name: proc_macro2::TokenStream) -> TokenStream {
    let input: syn::Item = syn::parse(input).expect("Invalid syntax");
    let output = quote!(
        #macro_name ! {
            #input
        }
    );
    output.into()
}

#[proc_macro_derive(GraphQLNewtype)]
pub fn newtype_derive(input: TokenStream) -> TokenStream {
    derive_using_macro(input, quote!(graphql_newtype))
}

#[proc_macro_derive(GraphQLObjectFromUnit)]
pub fn object_from_unit_derive(input: TokenStream) -> TokenStream {
    derive_using_macro(input, quote!(graphql_object_from_unit))
}

#[proc_macro_derive(GraphQLUnionFromEnum)]
pub fn union_from_enum_derive(input: TokenStream) -> TokenStream {
    derive_using_macro(input, quote!(graphql_union_from_enum))
}

#[proc_macro_attribute]
pub fn graphql(_attr: TokenStream, input: TokenStream) -> TokenStream {
    let input: syn::Item = syn::parse(input).expect("Invalid syntax");
    let output = quote!(
        #input

        #[juniper::object]
        #input
    );
    output.into()
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<commit_msg>Allow dead code in `#[juniper_ext::graphql] impl`<commit_after>extern crate proc_macro;
extern crate proc_macro2;
extern crate syn;

use crate::proc_macro::TokenStream;
use quote::quote;

fn derive_using_macro(input: TokenStream, macro_name: proc_macro2::TokenStream) -> TokenStream {
    let input: syn::Item = syn::parse(input).expect("Invalid syntax");
    let output = quote!(
        #macro_name ! {
            #input
        }
    );
    output.into()
}

#[proc_macro_derive(GraphQLNewtype)]
pub fn newtype_derive(input: TokenStream) -> TokenStream {
    derive_using_macro(input, quote!(graphql_newtype))
}

#[proc_macro_derive(GraphQLObjectFromUnit)]
pub fn object_from_unit_derive(input: TokenStream) -> TokenStream {
    derive_using_macro(input, quote!(graphql_object_from_unit))
}

#[proc_macro_derive(GraphQLUnionFromEnum)]
pub fn union_from_enum_derive(input: TokenStream) -> TokenStream {
    derive_using_macro(input, quote!(graphql_union_from_enum))
}

#[proc_macro_attribute]
pub fn graphql(_attr: TokenStream, input: TokenStream) -> TokenStream {
    let input: syn::Item = syn::parse(input).expect("Invalid syntax");
    let output = quote!(
        #[allow(dead_code)]
        #input

        #[juniper::object]
        #input
    );
    output.into()
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<|endoftext|>


<commit_before>/// Doc-test test
/// ```rust
/// assert!(cargo_miri_test::make_true());
/// ```
/// ```rust,no_run
/// assert!(cargo_miri_test::make_true());
/// ```
/// ```rust,compile_fail
/// assert!(cargo_miri_test::make_true() == 5);
/// ```
pub fn make_true() -> bool {
    issue_1567::use_the_dependency();
    issue_1705::use_the_dependency();
    issue_1760::use_the_dependency!();
    issue_1691::use_me()
}
<commit_msg>make sure that we truly do not run no_run doctests<commit_after>/// Doc-test test
/// ```rust
/// assert!(cargo_miri_test::make_true());
/// ```
/// ```rust,no_run
/// assert!(!cargo_miri_test::make_true());
/// ```
/// ```rust,compile_fail
/// assert!(cargo_miri_test::make_true() == 5);
/// ```
pub fn make_true() -> bool {
    issue_1567::use_the_dependency();
    issue_1705::use_the_dependency();
    issue_1760::use_the_dependency!();
    issue_1691::use_me()
}
<|endoftext|>


<commit_before>//! Assertions for array

use ndarray::*;
use std::fmt::Debug;

use super::norm::*;
use super::types::*;

/// check two values are close in terms of the relative torrence
pub fn rclose<A: Scalar>(test: A, truth: A, rtol: A::Real) {
    let dev = (test - truth).abs() / truth.abs();
    if dev > rtol {
        eprintln!("Expected = {}", truth);
        eprintln!("Actual   = {}", test);
        panic!("Too large deviation in relative torrence: {}", dev);
    }
}

/// check two values are close in terms of the absolute torrence
pub fn aclose<A: Scalar>(test: A, truth: A, atol: A::Real) {
    let dev = (test - truth).abs();
    if dev > atol {
        eprintln!("Expected = {}", truth);
        eprintln!("Actual   = {}", test);
        panic!("Too large deviation in absolute torrence: {}", dev);
    }
}

/// check two arrays are close in maximum norm
pub fn close_max<A, S1, S2, D>(test: &ArrayBase<S1, D>, truth: &ArrayBase<S2, D>, atol: A::Real)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
    D::Pattern: PartialEq + Debug,
{
    let tol = (test - truth).norm_max();
    if tol > atol {
        eprintln!("Expected:\n{}", truth);
        eprintln!("Actual:\n{}", test);
        panic!("Too large deviation in maximum norm: {}", tol);
    }
}

/// check two arrays are close in L1 norm
pub fn close_l1<A, S1, S2, D>(test: &ArrayBase<S1, D>, truth: &ArrayBase<S2, D>, rtol: A::Real)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
    D::Pattern: PartialEq + Debug,
{
    let tol = (test - truth).norm_l1() / truth.norm_l1();
    if tol > rtol {
        eprintln!("Expected:\n{}", truth);
        eprintln!("Actual:\n{}", test);
        panic!("Too large deviation in L1-norm: {}", tol);
    }
}

/// check two arrays are close in L2 norm
pub fn close_l2<A, S1, S2, D>(test: &ArrayBase<S1, D>, truth: &ArrayBase<S2, D>, rtol: A::Real)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
    D::Pattern: PartialEq + Debug,
{
    let tol = (test - truth).norm_l2() / truth.norm_l2();
    if tol > rtol {
        eprintln!("Expected:\n{}", truth);
        eprintln!("Actual:\n{}", test);
        panic!("Too large deviation in L2-norm: {}", tol);
    }
}

macro_rules! generate_assert {
    ($assert:ident, $close:path) => {
        #[macro_export]
        macro_rules! $assert {
            ($test: expr,$truth: expr,$tol: expr) => {
                $crate::$close($test, $truth, $tol);
            };
        }
    };
} // generate_assert!

generate_assert!(assert_rclose, rclose);
generate_assert!(assert_aclose, aclose);
generate_assert!(assert_close_max, close_max);
generate_assert!(assert_close_l1, close_l1);
generate_assert!(assert_close_l2, close_l2);
<commit_msg>Add assertion for array sizes<commit_after>//! Assertions for array

use ndarray::*;
use std::fmt::Debug;

use super::norm::*;
use super::types::*;

/// check two values are close in terms of the relative torrence
pub fn rclose<A: Scalar>(test: A, truth: A, rtol: A::Real) {
    let dev = (test - truth).abs() / truth.abs();
    if dev > rtol {
        eprintln!("Expected = {}", truth);
        eprintln!("Actual   = {}", test);
        panic!("Too large deviation in relative torrence: {}", dev);
    }
}

/// check two values are close in terms of the absolute torrence
pub fn aclose<A: Scalar>(test: A, truth: A, atol: A::Real) {
    let dev = (test - truth).abs();
    if dev > atol {
        eprintln!("Expected = {}", truth);
        eprintln!("Actual   = {}", test);
        panic!("Too large deviation in absolute torrence: {}", dev);
    }
}

/// check two arrays are close in maximum norm
pub fn close_max<A, S1, S2, D>(test: &ArrayBase<S1, D>, truth: &ArrayBase<S2, D>, atol: A::Real)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
    D::Pattern: PartialEq + Debug,
{
    assert_eq!(test.dim(), truth.dim());
    let tol = (test - truth).norm_max();
    if tol > atol {
        eprintln!("Expected:\n{}", truth);
        eprintln!("Actual:\n{}", test);
        panic!("Too large deviation in maximum norm: {}", tol);
    }
}

/// check two arrays are close in L1 norm
pub fn close_l1<A, S1, S2, D>(test: &ArrayBase<S1, D>, truth: &ArrayBase<S2, D>, rtol: A::Real)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
    D::Pattern: PartialEq + Debug,
{
    assert_eq!(test.dim(), truth.dim());
    let tol = (test - truth).norm_l1() / truth.norm_l1();
    if tol > rtol {
        eprintln!("Expected:\n{}", truth);
        eprintln!("Actual:\n{}", test);
        panic!("Too large deviation in L1-norm: {}", tol);
    }
}

/// check two arrays are close in L2 norm
pub fn close_l2<A, S1, S2, D>(test: &ArrayBase<S1, D>, truth: &ArrayBase<S2, D>, rtol: A::Real)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
    D::Pattern: PartialEq + Debug,
{
    assert_eq!(test.dim(), truth.dim());
    let tol = (test - truth).norm_l2() / truth.norm_l2();
    if tol > rtol {
        eprintln!("Expected:\n{}", truth);
        eprintln!("Actual:\n{}", test);
        panic!("Too large deviation in L2-norm: {}", tol);
    }
}

macro_rules! generate_assert {
    ($assert:ident, $close:path) => {
        #[macro_export]
        macro_rules! $assert {
            ($test: expr,$truth: expr,$tol: expr) => {
                $crate::$close($test, $truth, $tol);
            };
        }
    };
} // generate_assert!

generate_assert!(assert_rclose, rclose);
generate_assert!(assert_aclose, aclose);
generate_assert!(assert_close_max, close_max);
generate_assert!(assert_close_l1, close_l1);
generate_assert!(assert_close_l2, close_l2);
<|endoftext|>


<commit_before>//! Assertions for array

use ndarray::*;

use super::norm::*;
use super::types::*;

/// check two values are close in terms of the relative torrence
pub fn rclose<A>(test: A, truth: A, rtol: A::Real) -> Result<A::Real, A::Real>
where
    A: Scalar,
{
    let dev = (test - truth).abs() / truth.abs();
    if dev < rtol { Ok(dev) } else { Err(dev) }
}

/// check two values are close in terms of the absolute torrence
pub fn aclose<A>(test: A, truth: A, atol: A::Real) -> Result<A::Real, A::Real>
where
    A: Scalar,
{
    let dev = (test - truth).abs();
    if dev < atol { Ok(dev) } else { Err(dev) }
}

/// check two arrays are close in maximum norm
pub fn close_max<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    atol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_max();
    if tol < atol { Ok(tol) } else { Err(tol) }
}

/// check two arrays are close in L1 norm
pub fn close_l1<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    rtol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_l1() / truth.norm_l1();
    if tol < rtol { Ok(tol) } else { Err(tol) }
}

/// check two arrays are close in L2 norm
pub fn close_l2<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    rtol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_l2() / truth.norm_l2();
    if tol < rtol { Ok(tol) } else { Err(tol) }
}

macro_rules! generate_assert {
    ($assert:ident, $close:path) => {
#[macro_export]
macro_rules! $assert {
    ($test:expr, $truth:expr, $tol:expr) => {
        $close($test, $truth, $tol).unwrap();
    };
    ($test:expr, $truth:expr, $tol:expr; $comment:expr) => {
        $close($test, $truth, $tol).expect($comment);
    };
}
}} // generate_assert!

generate_assert!(assert_rclose, rclose);
generate_assert!(assert_aclose, aclose);
generate_assert!(assert_close_max, close_max);
generate_assert!(assert_close_l1, close_l1);
generate_assert!(assert_close_l2, close_l2);
<commit_msg>Simplify where part<commit_after>//! Assertions for array

use ndarray::*;

use super::norm::*;
use super::types::*;

/// check two values are close in terms of the relative torrence
pub fn rclose<A: Scalar>(test: A, truth: A, rtol: A::Real) -> Result<A::Real, A::Real> {
    let dev = (test - truth).abs() / truth.abs();
    if dev < rtol { Ok(dev) } else { Err(dev) }
}

/// check two values are close in terms of the absolute torrence
pub fn aclose<A: Scalar>(test: A, truth: A, atol: A::Real) -> Result<A::Real, A::Real> {
    let dev = (test - truth).abs();
    if dev < atol { Ok(dev) } else { Err(dev) }
}

/// check two arrays are close in maximum norm
pub fn close_max<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    atol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_max();
    if tol < atol { Ok(tol) } else { Err(tol) }
}

/// check two arrays are close in L1 norm
pub fn close_l1<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    rtol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_l1() / truth.norm_l1();
    if tol < rtol { Ok(tol) } else { Err(tol) }
}

/// check two arrays are close in L2 norm
pub fn close_l2<A, S1, S2, D>(
    test: &ArrayBase<S1, D>,
    truth: &ArrayBase<S2, D>,
    rtol: A::Real,
) -> Result<A::Real, A::Real>
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: Data<Elem = A>,
    D: Dimension,
{
    let tol = (test - truth).norm_l2() / truth.norm_l2();
    if tol < rtol { Ok(tol) } else { Err(tol) }
}

macro_rules! generate_assert {
    ($assert:ident, $close:path) => {
#[macro_export]
macro_rules! $assert {
    ($test:expr, $truth:expr, $tol:expr) => {
        $close($test, $truth, $tol).unwrap();
    };
    ($test:expr, $truth:expr, $tol:expr; $comment:expr) => {
        $close($test, $truth, $tol).expect($comment);
    };
}
}} // generate_assert!

generate_assert!(assert_rclose, rclose);
generate_assert!(assert_aclose, aclose);
generate_assert!(assert_close_max, close_max);
generate_assert!(assert_close_l1, close_l1);
generate_assert!(assert_close_l2, close_l2);
<|endoftext|>