[][src]Macro syllogism_macro::impl_specialization

impl_specialization!() { /* proc-macro */ }

Procedural macro to allow IsNot-based and Specialize-based specialisation for a number of data-types, allowing handling each other data-type in the generic way.

It expects a number of items, separated by semicolons (;):

  • a number of data types, possibly with type parameters and lifetimes, each preceded with the type keyword (e.g. impl_specialization!(type MyType; type OtherType<T>);),
  • optionally a number of traits without type parameters (usually only one trait), preceded by the trait keyword, (e.g. impl_specialization!(trait MyTrait; type MyType; type OtherType<T>);),
  • optionally a number of macro names (usually one macro), preceded by the macro keyword. These macros are supposed to be macros as defined by the define_compatibility macro in the syllogism crate.

This gives you all you need to use IsNot-based and Specialize-based implementation, with the exception of the implementation of Specialize<Self> for types with type parameters. In other words, the expansion of the macro contains the following:

  • For each pair of distinct data-types D1, D2 in the list of data-types supplied, the expansion contains
This example is not tested
impl IsNot<D2> for D1 {}             // For each pair of distinct data types `D1`, `D2`

impl<P> IsNot<P> for D1
where P: T1 {/* ... */ }             // For each data type `D1` and each treat `T1`

impl Specialize<D2> for D1 {
    // Return Distinction::Generic
}                                    // For each pair of distinct data types `D1`, `D2`
impl Specialize<D1> for D1 {
    // Return Distinction::Special
}                                    // For each data type `D1` that has no type parameters

impl<P> Specialize<P> for D1
where P: T1 {
    // Return Distinction::Generic

m1!(impl trait for D1 {});           // For each data type `D1` and each macro `m1`

Warning

When using types with type parameters, please note that

  • The type parameters must have distinct names. E.g. impl_specialization(type MyType<T>; type OtherType<U>); is ok, but impl_specialization(type MyType<T>; type OtherType<T>); is not ok.
  • For the types with type parameters, the macro does not generate an implementation of Specialize<Self>. E.g. when you write impl_specialization(type MyType<T>; type OtherType);, you should manually write an impl block for impl<T> Specialize<MyType<T>> for MyType<T> { /* ... / }.

Example

use syllogism_macro::impl_specialization;
struct S1 {}
struct S2<'a, T> {
    // ...
}

mod m {
    pub struct S3<U> {
        // ...
    }
}

macro_rules! my_macro {
    // ...
}
trait MyTrait {}

impl_specialization!(
    macro my_macro;
    trait MyTrait;
    type S1;
    type S2<'a, T>;
    type m::S3<U>
);

In this example, the macro invocation expands to something similar to the following (the difference is that in reality, the expansion contains syllogism::IsNot and syllogism::Specialize, I have simplified this somewhat).

use syllogism::{IsNot, Specialize, Distinction};

impl<'a, T> IsNot<S2<'a, T>> for S1 {}
impl<U> IsNot<m::S3<U>> for S1 {}

impl<P> IsNot<P> for S1 where P: MyTrait {}

impl<'a, T> Specialize<S2<'a, T>> for S1 {
    fn specialize(self) -> Distinction<S2<'a, T>, S1> {
        Distinction::Generic(self)
    }
}
impl<U> Specialize<m::S3<U>> for S1 {
    fn specialize(self) -> Distinction<m::S3<U>, S1> {
        Distinction::Generic(self)
    }
}
impl Specialize<S1> for S1 {
    fn specialize(self) -> Distinction<S1, S1> {
        Distinction::Special(self)
    }
}

impl<P> Specialize<P> for S1 where P: MyTrait {
    fn specialize(self) -> Distinction<P, S1> {
        Distinction::Generic(self)
    }
}

my_macro!(impl trait for S1 {});

impl<'a, T> IsNot<S1> for S2<'a, T> {}
impl<'a, T, U> IsNot<m::S3<U>> for S2<'a, T> {}

impl<'a, T, P> IsNot<P> for S2<'a, T> where P: MyTrait {}

impl<'a, T> Specialize<S1> for S2<'a, T> {
    fn specialize(self) -> Distinction<S1, S2<'a, T>> {
        Distinction::Generic(self)
    }
}
impl<'a, T, U> Specialize<m::S3<U>> for S2<'a, T> {
    fn specialize(self) -> Distinction<m::S3<U>, S2<'a, T>> {
        Distinction::Generic(self)
    }
}
// Note: no `impl<'a, T> Specialize<S2<'a, T>> for S2<'a, T> { /* ... */ }`.

impl<'a, P, T> Specialize<P> for S2<'a, T> where P: MyTrait {
    fn specialize(self) -> Distinction<P, S2<'a, T>> {
        Distinction::Generic(self)
    }
}

my_macro!(impl<'a, T> trait for S2<'a, T> {});

impl<U> IsNot<S1> for m::S3<U> {}
impl<'a, U, T> IsNot<S2<'a, T>> for m::S3<U> {}

impl<'a, U, P> IsNot<P> for m::S3<U> where P: MyTrait {}

impl<U> Specialize<S1> for m::S3<U> {
    fn specialize(self) -> Distinction<S1, m::S3<U>> {
        Distinction::Generic(self)
    }
}
impl<'a, T, U> Specialize<S2<'a, T>> for m::S3<U> {
    fn specialize(self) -> Distinction<S2<'a, T>, m::S3<U>> {
        Distinction::Generic(self)
    }
}
// Note: no `impl<U> Specialize<m::S3<U>> for m::S3<U> { /* ... */ }`.

impl<'a, P, U> Specialize<P> for m::S3<U> where P: MyTrait {
    fn specialize(self) -> Distinction<P, m::S3<U>> {
        Distinction::Generic(self)
    }
}

my_macro!(impl<U> trait for m::S3<U> {});

In this way, these types can be used e.g. in the following way:

use syllogism::{IsNot, Specialize, Distinction};
trait GenericTrait<T> {
    fn generic_method(&mut self, by_value: T);
    // ...
}

struct MyStruct {
    // ...
}

impl GenericTrait<S1> for MyStruct {
    // The implementation special for `S1`.
}

impl<T> GenericTrait<T> for MyStruct
where T: syllogism::IsNot<S1> {
    // The generic implementation.
    // This can be used for `S2` and `S3` and types defined in other crates
    // that implement `MyTrait`.
}

struct MyGenericStruct<T> {
    // ...
}

impl<T> GenericTrait<T> for MyGenericStruct<T>
where T: Specialize<S1> {
     fn generic_method(&mut self, by_value: T) {
        match by_value.specialize() {
            Distinction::Special(s) => {
                // `s` has type `S1` and can have a special treatment
            },
            Distinction::Generic(g) => {
                // The generic implementation.
            }
        }
    }
}