#traits #const #impl #macro #const-fn

macro unconst_trait_impl

Function-like macro that "unconsts" trait implementations

6 releases

0.1.5 Jul 17, 2022
0.1.4 Feb 21, 2022

#24 in #const-fn

30 downloads per month
Used in 2 crates (via zst)

MIT/Apache

68KB
1.5K SLoC

Function-like macro that "unconsts" trait implementations

unconst_trait_impl::unconst_trait_impl turns the Nightly syntax for constant trait implementations into analogous non-const syntax that is accepted on stable toolchain.

The list of features taken into account:

In a vaccum, unconst_trait_impl procedural function-like macro is fairly useless because its call on constant trait implementation yields the same result as writing the non-const implementation in the first place.

However, with cfg_attr and remove_macro_call attributes, unconst_trait_impl macro allows one to conditionally remove the macro call thus providing support for stable toolchain while also providing functionality relying on Nightly features.

Example

#![cfg_attr(feature = "const_trait_impl", feature(const_trait_impl))]
#![cfg_attr(feature = "const_default_impls", feature(const_default_impls))]
#![cfg_attr(feature = "const_fn_trait_bound", feature(const_fn_trait_bound))]

#[cfg(not(all(
    feature = "const_trait_impl",
    feature = "const_default_impls",
    feature = "const_fn_trait_bound"
)))]
use unconst_trait_impl::unconst_trait_impl;
use core::{default::Default, marker::PhantomData};
#[cfg(all(
    feature = "const_trait_impl",
    feature = "const_default_impls",
    feature = "const_fn_trait_bound"
))]
use remove_macro_call::remove_macro_call;

// Since ZST is both Eq and and PartialEq, it has structural match
// https://github.com/rust-lang/rust/issues/63438
#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd, Copy)]
pub struct ZST<T: ?Sized>(PhantomData<T>);

pub trait TraitName {}

#[cfg_attr(
    all(
        feature = "const_trait_impl",
        feature = "const_default_impls",
        feature = "const_fn_trait_bound"
    ),
    remove_macro_call
)]
unconst_trait_impl! {
    impl<T: ?Sized> const TraitName for ZST<T> {}
}

// With `cargo build --features const_trait_impl, const_default_impls, const_fn_trait_bound`
// or with `cargo build --all-features, the code below is expanded as is. Otherwise,
// it gets "unconsted" to be supported by stable toolchain.
#[cfg_attr(
    all(
        feature = "const_trait_impl",
        feature = "const_default_impls",
        feature = "const_fn_trait_bound"
    ),
    remove_macro_call
)]
unconst_trait_impl! {
    impl<T: ~const TraitName + ?Sized> const Default for ZST<T> {
        fn default() -> Self {
            ZST(Default::default())
        }
    }
}

Note: In the real code, the example above could be replaced with a simpler version relying on cfg_aliases crate.

You can learn more about remove_macro_call here:

Known limitations

Currently, type parameters (like T in T: ~const TraitName + ?Sized) get "unconsted" only when

  1. they belong to the trait implementation, i.e. when they are in <..> or in the where clause of the trait implementation;
  2. they belong to the signatures of methods and associated functions;

Other Items in the trait implementation currently don't get "unconsted".

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~1.5MB
~35K SLoC