Expand description
§type-mapper
A Rust procedural macro crate for powerful type-level pattern matching and transformation. This crate is particularly useful for macro authors who need to perform complex type manipulations at compile time.
§Features
- Type pattern matching with wildcards
- Lifetime handling and manipulation
- Recursive type transformations
- Support for generic type parameters
- Path-aware type matching
§Limitations
The macro matches on token patterns rather than full types. It performs no validation of generic parameters or type identity.
For example, you cannot tell whether a type named Ordering was imported from
std::cmd::Ordering or std::sync::atomic::Ordering.
§Usage
Add this to your Cargo.toml:
[dependencies]
type-mapper = "0.x.y"§Examples
§Type Declaration
The map_types! macro can be used in a type position:
use type_mapper::map_types;
/// This is an unlikely usage, but macros will generate code like this:
static X: map_types!(
match Vec<Option<u8>> {
Vec<_T> => recurse!(_T),
Option<_T> => recurse!(_T),
_T => _T,
}
) = 1_u8;It’s mostly useful when writing macros that need to transform types:
use type_mapper::map_types;
use static_assertions::assert_type_eq_all;
macro_rules! with_static_lifetime {
($ty:ty) => {
map_types!(
match $ty {
&'_ _T => &'static recurse!(_T),
_T<'_, _U> => _T<'static, recurse!(_U)>,
_T<'_, _U, _V> => _T<'static, recurse!(_U), recurse!(_V)>,
_T => _T,
}
)
}
}
trait MyTrait<T> {
/// Our type
type Type;
/// Our type but with static lifetimes
type Static;
}
macro_rules! define_trait_for {
($lt:lifetime $name:ident $ty:ty) => {
impl <$lt> MyTrait<$ty> for $name where $name: $lt {
type Type = $ty;
type Static = with_static_lifetime!($ty);
}
}
}
struct MyStruct{}
define_trait_for!('a MyStruct (u8, u8));
define_trait_for!('a MyStruct (&'a u8, &'a u8));
assert_type_eq_all!(<MyStruct as MyTrait<(u8, u8)>>::Type, (u8, u8));
assert_type_eq_all!(<MyStruct as MyTrait<(u8, u8)>>::Static, (u8, u8));
// This doesn't compile because we can't test against that missing lifetime
// assert_type_eq_all!(<MyStruct as MyTrait<(&'a u8, &'a u8)>>::Type, (&'static u8, &'static u8));
assert_type_eq_all!(<MyStruct as MyTrait<(&'static u8, &'static u8)>>::Static, (&'static u8, &'static u8));§Basic Type Matching
The crate provides a assert_type_matches! and assert_type_not_matches! macros for testing type matches.
use type_mapper::{assert_type_matches, assert_type_not_matches, map_types};
// Simple type matching
assert_type_matches!(Vec<u8>, Vec<u8>);
assert_type_matches!(Vec<u8>, Vec);
assert_type_matches!(Vec<u8>, _T <u8>);
assert_type_matches!(Vec<u8>, Vec<_>);
// Wildcard matching
assert_type_matches!(u8, _);
assert_type_matches!(u8, _T);
assert_type_matches!(u8, _T<>);
assert_type_not_matches!(u8, _T<_U>);
// Type mismatch
assert_type_not_matches!(Vec<u8>, Vec<u16>);
assert_type_not_matches!(u8, u16);
assert_type_not_matches!(std::sync::MutexGuard<'a, u8>, std::sync::MutexGuard<'_>);§Lifetime Handling
use type_mapper::map_types;
use static_assertions::assert_type_eq_all;
/// Make a slice type static.
macro_rules! make_slice_static {
($ty:ty) => {
map_types!(
match $ty {
&'_ [_T] => &'static [_T],
}
)
}
}
assert_type_eq_all!(make_slice_static!(&'a [u8]), &'static [u8]);
assert_type_eq_all!(make_slice_static!(&'static [u8]), &'static [u8]);
§Recursive Type Matching
Using the internal recurse! macro, you can match on types recursively.
use type_mapper::map_types;
use static_assertions::assert_type_eq_all;
/// Unwrap an Option type recursively.
macro_rules! unwrap_option {
($ty:ty) => {
map_types!(
match $ty {
Option<_T> => recurse!(_T),
_T => _T,
}
)
}
}
assert_type_eq_all!(unwrap_option!(Option<u8>), u8);
assert_type_eq_all!(unwrap_option!(Option<Option<u8>>), u8);
assert_type_eq_all!(unwrap_option!(Option<Option<Option<u8>>>), u8);§Pattern Matching Syntax
The crate supports several pattern matching features:
_- Wildcard for any type_T- Named wildcard that can be referenced in the result_T<T>- Generic type matching_T<>- Generic type matching with no generics (WARNING: rustfmt may eat the<>if you don’t use#[rustfmt::skip])'_- Wildcard lifetime (will also match no lifetime in a reference)'_A- Named wildcard lifetime (will also match no lifetime in a reference)'a- Named lifetime matchingrecurse!(_T)- Recursive type transformation
§Use Cases
This crate is particularly useful for:
- Macro authors who need to transform types
- Creating type-level DSLs
- Implementing complex type-level logic
- Generic type manipulation
- Lifetime manipulation in macros
§License
MIT License
Macros§
- assert_
type_ matches - assert_
type_ not_ matches - map_
types - Matches something like this:
- recurse