multiversion 0.9.0

Easy function multiversioning
Documentation
use multiversion::multiversion;

#[cfg(feature = "std")]
#[test]
fn dispatcher_variable_names_in_parameters() {
    #[multiversion(targets("x86_64+avx", "aarch64+sve"), dispatcher = "indirect")]
    fn add(current_fn: u8, current_ptr: u8) -> u8 {
        current_fn + current_ptr
    }

    assert_eq!(add(10, 20), 30);
    assert_eq!(add(11, 21), 32);
}

#[test]
fn synthesized_parameter_names() {
    #[multiversion(targets("x86_64+avx", "aarch64+sve"))]
    fn add((value,): (u8,), arg_0: u8) -> u8 {
        value + arg_0
    }

    assert_eq!(add((10,), 20), 30);
    assert_eq!(add((11,), 21), 32);
}

#[cfg(feature = "std")]
#[test]
fn atomic_type_names_in_signature() {
    struct Ordering(u8);
    struct AtomicPtr(Ordering);

    #[multiversion(targets("x86_64+avx", "aarch64+sve"), dispatcher = "indirect")]
    fn wrap(value: Ordering) -> AtomicPtr {
        AtomicPtr(value)
    }

    let AtomicPtr(Ordering(value)) = wrap(Ordering(42));
    assert_eq!(value, 42);
}

#[cfg(feature = "std")]
#[test]
fn shadowed_standard_library_paths() {
    mod core {}
    mod std {}

    #[multiversion(targets("x86_64+avx", "aarch64+sve"), dispatcher = "direct")]
    fn direct() -> bool {
        multiversion::target::target_cfg_f!(target_pointer_width = "64")
    }

    #[multiversion(targets("x86_64+avx", "aarch64+sve"), dispatcher = "indirect")]
    fn indirect() -> bool {
        multiversion::target::target_cfg_f!(target_pointer_width = "64")
    }

    assert_eq!(direct(), ::core::cfg!(target_pointer_width = "64"));
    assert_eq!(indirect(), ::core::cfg!(target_pointer_width = "64"));
}

#[test]
fn shadowed_cfg_macro() {
    mod core {}
    #[allow(unused_macros)]
    macro_rules! cfg {
        ($($tokens:tt)*) => {
            compile_error!("resolved the caller's cfg macro")
        };
    }

    #[multiversion(targets("x86_64+avx", "aarch64+sve"), dispatcher = "static")]
    fn selected() -> bool {
        multiversion::target::target_cfg_f!(target_pointer_width = "64")
    }

    assert_eq!(selected(), ::core::cfg!(target_pointer_width = "64"));
}

#[multiversion(targets("x86_64+avx", "aarch64+sve"))]
fn r#type(value: u8) -> u8 {
    value + 1
}

#[multiversion(targets("x86_64+avx+avx2", "aarch64+sve", "x86_64+avx2+avx+avx", "aarch64+sve",))]
fn duplicate_targets(value: u8) -> u8 {
    value + 1
}

#[test]
fn names_and_duplicates() {
    assert_eq!(r#type(41), 42);
    assert_eq!(duplicate_targets(41), 42);
}

#[cfg(target_arch = "x86_64")]
#[test]
fn duplicate_targets_preserve_priority() {
    #[multiversion(targets("x86_64+avx2", "x86_64+avx", "x86_64+avx2"))]
    fn selected_avx2() -> bool {
        multiversion::target::target_cfg_f!(target_feature = "avx2")
    }

    #[cfg(feature = "std")]
    let expected = std::arch::is_x86_feature_detected!("avx2");
    #[cfg(not(feature = "std"))]
    let expected = cfg!(target_feature = "avx2");
    assert_eq!(selected_avx2(), expected);
}