Crates.io | disjoint_impls |
lib.rs | disjoint_impls |
version | 0.8.0 |
source | src |
created_at | 2023-09-23 12:39:35.044691 |
updated_at | 2024-09-18 03:04:42.262414 |
description | Support for mutually disjoint impls |
homepage | |
repository | https://github.com/mversic/disjoint_impls |
max_upload_size | |
id | 981215 |
size | 262,111 |
Crate will be maintained (at least) until this idiom is allowed by the Rust compiler directly
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