#disjoint #associated #impl #exclusive #implementation

macro disjoint_impls

Support for a variety of mutually disjoint implementations

8 releases (breaking)

new 0.7.1 May 20, 2024
0.7.0 Jan 23, 2024
0.6.0 Jan 8, 2024
0.5.0 Nov 23, 2023
0.1.0 Sep 23, 2023

#191 in Procedural macros

Download history 19/week @ 2024-02-08 70/week @ 2024-02-15 78/week @ 2024-02-22 54/week @ 2024-02-29 104/week @ 2024-03-07 66/week @ 2024-03-14 78/week @ 2024-03-21 107/week @ 2024-03-28 107/week @ 2024-04-04 63/week @ 2024-04-11 70/week @ 2024-04-18 111/week @ 2024-04-25 28/week @ 2024-05-02 87/week @ 2024-05-09 162/week @ 2024-05-16

394 downloads per month

Apache-2.0

64KB
1.5K SLoC

License: Apache 2.0 Crates.io

Crate will be maintained (at least) until this idiom is allowed by the Rust compiler directly

Description

This library enables you to write certain types of disjoint impls that Rust compiler doesn't (yet?) allow. Namely, disjoint impls where a type is bounded by an associated type. One would expect the following syntax to compile without the need to invoke disjoint_impls!, but it doesn't:

use disjoint_impls::disjoint_impls;

pub trait Dispatch {
    type Group;
}

pub enum GroupA {}
impl Dispatch for String {
    type Group = GroupA;
}

pub enum GroupB {}
impl Dispatch for i32 {
    type Group = GroupB;
}

// Basic example
disjoint_impls! {
    pub trait BasicKita {
        const BASIC_NAME: &'static str;

        fn basic_name() -> &'static str {
            "Default blanket"
        }
    }

    impl<T: Dispatch<Group = GroupA>> BasicKita for T {
        const BASIC_NAME: &'static str = "Blanket A";
    }
    impl<U: Dispatch<Group = GroupB>> BasicKita for U {
        const BASIC_NAME: &'static str = "Blanket B";

        fn basic_name() -> &'static str {
            "Blanket B"
        }
    }
}

// Complex example
disjoint_impls! {
    pub trait ComplexKita {
        const COMPLEX_NAME: &'static str;
    }

    impl<T: Dispatch<Group = GroupA>, U: Dispatch<Group = GroupA>> ComplexKita for (T, U) {
        const COMPLEX_NAME: &'static str = "Blanket AA";
    }
    impl<U, T> ComplexKita for (U, T)
    where
        U: Dispatch<Group = GroupA>,
        T: Dispatch<Group = GroupB>
    {
        const COMPLEX_NAME: &'static str = "Blanket AB";
    }
    impl<T: Dispatch<Group = GroupB>, U: Dispatch> ComplexKita for (T, U) {
        const COMPLEX_NAME: &'static str = "Blanket B*";
    }

    impl<T: Dispatch<Group = GroupA>> ComplexKita for T {
        const COMPLEX_NAME: &'static str = "Blanket A";
    }
    impl<U: Dispatch<Group = GroupB>> ComplexKita for U {
        const COMPLEX_NAME: &'static str = "Blanket B";
    }
}

fn main() {
    assert_eq!("Blanket A", String::BASIC_NAME);
    assert_eq!("Blanket B", i32::BASIC_NAME);

    assert_eq!("Default blanket", String::basic_name());
    assert_eq!("Blanket B", i32::basic_name());

    assert_eq!("Blanket A", String::COMPLEX_NAME);
    assert_eq!("Blanket B", i32::COMPLEX_NAME);

    assert_eq!("Blanket AA", <(String, String)>::COMPLEX_NAME);
    assert_eq!("Blanket AB", <(String, i32)>::COMPLEX_NAME);
    assert_eq!("Blanket B*", <(i32, String)>::COMPLEX_NAME);
}

Other much more complex examples can be found in tests

Dependencies

~325–780KB
~18K SLoC