use batch_impl::{batch_impl, batch_trait};
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
#[batch_impl(usize, isize)]
trait Numeric {}
fn check_numeric<T: Numeric>(_: &T) {}
fn test_basic() {
check_numeric(&0usize);
check_numeric(&0isize);
println!(" 1. basic: OK");
}
#[batch_impl(<T> Vec<T>)]
trait Collection {}
fn check_collection<T: Collection>(_: &T) {}
fn test_generic() {
check_collection(&vec![1, 2, 3]);
check_collection(&vec!["a", "b"]);
println!(" 2. generic: OK");
}
#[batch_impl(<T> FromValue<T> i32{
fn wrap(_val: T) -> Self {
0
}
})]
trait FromValue<T> {
fn wrap(val: T) -> Self;
}
fn test_trait_with_generic() {
let x: i32 = FromValue::<String>::wrap(String::from("ignored"));
assert_eq!(x, 0);
println!(" 3. trait with generic: OK");
}
#[batch_impl(
isize{
fn is_zero(&self) -> bool { *self == 0 }
fn describe(&self) -> String { format!("isize({})", self) }
},
f64{
fn is_zero(&self) -> bool { *self == 0.0 }
fn describe(&self) -> String { format!("f64({})", self) }
}
)]
trait Inspect {
fn is_zero(&self) -> bool;
fn describe(&self) -> String;
}
fn test_custom_body() {
assert!(0isize.is_zero());
assert!(!42isize.is_zero());
assert_eq!(42isize.describe(), "isize(42)");
assert!(0.0f64.is_zero());
assert!(!3.14f64.is_zero());
assert_eq!(3.14f64.describe(), "f64(3.14)");
println!(" 4. custom body: OK");
}
#[batch_impl(<T> [Vec<T>, HashMap<usize, T>]{
fn count(&self) -> usize { self.len() }
})]
trait Count {
fn count(&self) -> usize;
}
fn test_generic_list() {
let v: Vec<char> = vec!['a', 'b', 'c'];
assert_eq!(v.count(), 3);
let mut m = HashMap::<usize, bool>::new();
m.insert(0, true);
m.insert(1, false);
assert_eq!(m.count(), 2);
println!(" 5. generic list: OK");
}
#[batch_impl([usize, isize, f32]{
fn tag(&self) -> &'static str { "number" }
})]
trait Tagged {
fn tag(&self) -> &'static str;
}
fn test_multi_custom() {
assert_eq!(0usize.tag(), "number");
assert_eq!(0isize.tag(), "number");
assert_eq!(0f32.tag(), "number");
println!(" 6. multi custom: OK");
}
struct Alpha;
struct Beta;
struct Gamma;
#[batch_impl(<T> Pair<T> [Alpha, Beta, Gamma]{
fn pair(self, other: T) -> (Self, T) where Self: Sized {
(self, other)
}
})]
trait Pair<T> {
fn pair(self, other: T) -> (Self, T)
where
Self: Sized;
}
fn test_trait_generic_list() {
let a = Alpha.pair(42i32);
let b = Beta.pair("hello");
let c = Gamma.pair(3.14f64);
assert_eq!(a.1, 42i32);
assert_eq!(b.1, "hello");
assert_eq!(c.1, 3.14f64);
println!(" 7. trait generic list: OK");
}
#[batch_impl([isize])]
trait SliceMarker {}
fn test_slice_type() {
fn _check<T: SliceMarker + ?Sized>(_: &T) {}
let arr: [isize; 3] = [1, 2, 3];
_check(&arr[..]);
println!(" 8. slice type: OK");
}
#[batch_impl(<T> Describe<T> [Vec<T>, <U> HashMap<T, U>]{
fn describe(&self) -> String { format!("len={}", self.len()) }
})]
trait Describe<T> {
fn describe(&self) -> String;
}
fn test_nested() {
let v: Vec<char> = vec!['a', 'b', 'c'];
assert_eq!(v.describe(), "len=3");
let mut m = HashMap::<char, bool>::new();
m.insert('x', true);
m.insert('y', false);
assert_eq!(m.describe(), "len=2");
println!(" 9. nested: OK");
}
#[batch_impl(
usize{
fn id(&self) -> usize { *self }
},
String{
fn id(&self) -> usize { self.len() }
}
)]
trait Identifiable {
fn id(&self) -> usize;
}
fn test_multi_specs_with_body() {
assert_eq!(42usize.id(), 42);
assert_eq!(String::from("hello").id(), 5);
println!(" 10. multi specs with body: OK");
}
#[batch_impl(
(i32, String),
&str,
Box<dyn std::fmt::Display>,
fn(i32) -> bool
)]
trait ComplexMarker {}
fn test_complex_types() {
fn _check<T: ComplexMarker>() {}
_check::<(i32, String)>();
_check::<&str>();
_check::<Box<dyn std::fmt::Display>>();
_check::<fn(i32) -> bool>();
println!(" 11. complex types: OK");
}
#[batch_impl(<T> Vec<Vec<T>>)]
trait NestedGeneric {}
fn test_nested_angle_brackets() {
fn _check<T: NestedGeneric>() {}
_check::<Vec<Vec<i32>>>();
_check::<Vec<Vec<String>>>();
println!(" 12. nested angle brackets (Vec<Vec<T>>): OK");
}
#[batch_impl(<K, V> std::collections::HashMap<K, V>)]
trait PathType {}
fn test_path_type() {
fn _check<T: PathType>() {}
_check::<std::collections::HashMap<i32, String>>();
println!(" 13. path type (std::collections::HashMap<K,V>): OK");
}
struct SameNameStruct;
#[batch_impl(SameNameStruct)]
trait SameNameTrait {}
fn test_trait_name_as_target() {
fn _check<T: SameNameTrait>() {}
_check::<SameNameStruct>();
println!(" 14. plain ident never confused as trait_params: OK");
}
#[batch_impl(<T, U> MultiParam<T, U> (T, U){
fn first(&self) -> &T { &self.0 }
fn second(&self) -> &U { &self.1 }
})]
trait MultiParam<T, U> {
fn first(&self) -> &T;
fn second(&self) -> &U;
}
fn test_multi_trait_params() {
let pair: (i32, String) = (42, String::from("hi"));
assert_eq!(pair.first(), &42i32);
assert_eq!(pair.second(), &String::from("hi"));
println!(" 15. multi trait params <T,U> Trait<T,U> (T,U): OK");
}
#[batch_impl([[u8, u16], [i32, i64]]{
fn label(&self) -> &'static str { "integer" }
})]
trait IntLabel {
fn label(&self) -> &'static str;
}
fn test_nested_bracket_list() {
assert_eq!(0u8.label(), "integer");
assert_eq!(0u16.label(), "integer");
assert_eq!(0i32.label(), "integer");
assert_eq!(0i64.label(), "integer");
println!(" 16. nested list [[u8,u16],[i32,i64]]: OK");
}
#[batch_impl(
[u8]{
fn len_bytes(&self) -> usize { self.len() }
}
)]
trait ByteSlice {
fn len_bytes(&self) -> usize;
}
fn test_slice_with_body() {
let arr: [u8; 4] = [1, 2, 3, 4];
assert_eq!(arr.len_bytes(), 4);
println!(" 17. slice [u8] with custom body: OK");
}
struct PlainStruct;
#[batch_impl(PlainStruct)]
trait PlainTrait {}
fn test_plain_ident() {
fn _check<T: PlainTrait>() {}
_check::<PlainStruct>();
println!(" 18. plain ident as target (no confusion): OK");
}
#[batch_impl(dyn std::fmt::Display + Send + Sync)]
trait DynMarker {}
fn test_dyn_trait_object() {
fn _check<T: DynMarker + ?Sized>() {}
_check::<dyn std::fmt::Display + Send + Sync>();
println!(" 19. dyn trait object (with +): OK");
}
#[batch_impl(<T> UnwrapBox<T> Box<T>{
fn unwrap_box(self) -> T { *self }
})]
trait UnwrapBox<T> {
fn unwrap_box(self) -> T;
}
fn test_box_generic() {
let b: Box<i32> = Box::new(42);
assert_eq!(b.unwrap_box(), 42);
println!(" 20. Box<T> with trait generic and body: OK");
}
#[batch_impl(<T> WrapperTrait<Vec<T>> Vec<T>{
fn inner(self) -> Vec<T> { self }
})]
trait WrapperTrait<C> {
fn inner(self) -> C;
}
fn test_complex_trait_generic() {
let v: Vec<i32> = vec![1, 2, 3];
assert_eq!(v.inner(), vec![1, 2, 3]);
println!(" 21. complex trait generic (Vec<T>): OK");
}
#[batch_impl(<K, V> MapTrait<Vec<K>, Vec<V>> HashMap<K, V>)]
trait MapTrait<A, B> {}
fn test_multi_complex_trait_generic() {
fn _check<T: MapTrait<Vec<i32>, Vec<String>>>() {}
_check::<HashMap<i32, String>>();
println!(" 22. multi complex trait generic: OK");
}
#[batch_impl(<T: Clone + std::fmt::Debug> DescribeClone<T> Vec<T>{
fn describe_clone(&self) -> Vec<T> where T: Clone {
self.clone()
}
})]
trait DescribeClone<T> {
fn describe_clone(&self) -> Vec<T>;
}
fn test_type_bound() {
let v: Vec<i32> = vec![1, 2, 3];
assert_eq!(v.describe_clone(), vec![1, 2, 3]);
println!(" 23. type bound <T: Clone + Debug>: OK");
}
#[batch_impl(<const N: usize> ConstGeneric<N> [i32; N]{
fn len_const(&self) -> usize { N }
fn first(&self) -> i32 { self[0] }
})]
trait ConstGeneric<const N: usize> {
fn len_const(&self) -> usize;
fn first(&self) -> i32;
}
fn test_const_generic() {
let arr: [i32; 5] = [10, 20, 30, 40, 50];
assert_eq!(arr.len_const(), 5);
assert_eq!(arr.first(), 10);
println!(" 24. const generic <const N: usize>: OK");
}
#[batch_impl(<T: Clone, const N: usize> MixedGeneric<T, N> [T; N]{
fn repeat_inner(&self) -> Vec<T> {
std::iter::repeat(self[0].clone()).take(N).collect()
}
})]
trait MixedGeneric<T, const N: usize> {
fn repeat_inner(&self) -> Vec<T>;
}
fn test_mixed_generics() {
let arr: [String; 3] = [String::from("hi"), String::from("hi"), String::from("hi")];
assert_eq!(arr.repeat_inner().len(), 3);
println!(" 25. mixed <T: Clone, const N: usize>: OK");
}
#[batch_impl(<'a, T: 'a> LifetimeTrait<'a, T> &'a T)]
trait LifetimeTrait<'a, T> {}
fn test_lifetime_generic() {
fn _check<'a, T: 'a>()
where
&'a T: LifetimeTrait<'a, T>,
{
}
_check::<'static, i32>();
println!(" 26. lifetime generic <'a, T: 'a>: OK");
}
#[batch_impl(self^u32, &^u32)]
trait RefMarker {}
fn test_caret_basic() {
fn _check<T: RefMarker>() {}
_check::<u32>();
_check::<&u32>();
println!(" 27. caret: self^T, &^T: OK");
}
#[batch_impl(Box^u32, Vec^isize)]
trait ContainerMarker {}
fn test_caret_container() {
fn _check<T: ContainerMarker>() {}
_check::<Box<u32>>();
_check::<Vec<isize>>();
println!(" 28. caret: Box^u32, Vec^isize: OK");
}
#[batch_impl([&, self]^u32)]
trait RefOrOwned {}
fn test_caret_prefix_list() {
fn _check<T: RefOrOwned>() {}
_check::<u32>();
_check::<&u32>();
println!(" 29. caret: [&, self]^T: OK");
}
#[batch_impl(&^i32, &^i64)]
trait RefOnce {}
#[batch_impl(&mut^i32, &mut^i64)]
trait RefMutOnce {}
fn test_caret_cartesian() {
fn _check_ref<T: RefOnce>() {}
fn _check_mut<T: RefMutOnce>() {}
_check_ref::<&i32>();
_check_ref::<&i64>();
_check_mut::<&mut i32>();
_check_mut::<&mut i64>();
println!(" 30. caret: &^[i32,i64] + &mut^[i32,i64]: OK");
}
use std::collections::HashMap as MapType;
#[batch_impl(MapType^<u32, i32>)]
trait MapMarker {}
fn test_caret_multi_arg() {
fn _check<T: MapMarker>() {}
_check::<MapType<u32, i32>>();
println!(" 31. caret: HashMap^<K,V>: OK");
}
#[batch_impl(MapType^<u32, i32>, MapType^<u64, i64>)]
trait MultiMap {}
fn test_caret_multi_map_list() {
fn _check<T: MultiMap>() {}
_check::<MapType<u32, i32>>();
_check::<MapType<u64, i64>>();
println!(" 32. caret: HashMap^<K,V> × 2: OK");
}
#[batch_impl([[&, self]^u32, [Vec, Box]^u32])]
trait Comprehensive {}
fn test_caret_comprehensive() {
fn _check<T: Comprehensive>() {}
_check::<u32>();
_check::<&u32>();
_check::<Vec<u32>>();
_check::<Box<u32>>();
println!(" 33. caret: comprehensive: OK");
}
#[batch_impl(Box^Box^isize)]
trait NestedBox {}
fn test_nested_caret() {
fn _check<T: NestedBox>() {}
_check::<Box<Box<isize>>>();
println!(" 34. nested caret Box^Box^T: OK");
}
#[batch_impl(Box^[Box^isize])]
trait NestedSlice {}
fn test_caret_through_bracket() {
fn _check<T: NestedSlice>() {}
_check::<Box<[Box<isize>]>>();
println!(" 35. caret through [] Box^[Box^T]: OK");
}
#[batch_impl(()^3)]
trait GenTuple {}
fn test_tuple_gen() {
fn _t<T: GenTuple>() {}
_t::<(i32, i32, i32)>();
println!(" 36. tuple gen ()^3 = (A,B,C): OK");
}
#[batch_impl((u32,)^3)]
trait RepTuple {}
fn test_tuple_repeat() {
fn _t<T: RepTuple>() {}
_t::<(u32, u32, u32)>();
println!(" 37. tuple repeat (u32,)^3 = (u32,u32,u32): OK");
}
#[batch_impl(()^2)]
trait RangeTuple {}
fn test_tuple_range() {
fn _t<T: RangeTuple>() {}
_t::<(i32, String)>();
println!(" 38. tuple ()^2 = (A,B): OK");
}
#[batch_impl(()^3)]
trait RangeIncTuple {}
fn test_tuple_range_inclusive() {
fn _t<T: RangeIncTuple>() {}
_t::<(i32, String, u8)>();
println!(" 39. tuple ()^3 = (A,B,C): OK");
}
#[batch_impl((<Clone>)^3)]
trait BoundTuple {}
fn test_tuple_bound() {
fn _t<T: BoundTuple>() {}
_t::<(i32, i32, i32)>();
_t::<(String, String, String)>();
println!(" 40. tuple bound (<Clone>)^3 = (A:Clone,B:Clone,C:Clone): OK");
}
#[batch_impl(()^u32)]
trait AppendTupleEmpty {}
fn test_tuple_append_empty() {
fn _t<T: AppendTupleEmpty>() {}
_t::<(u32,)>();
println!(" 41. tuple append ()^u32 = (u32,): OK");
}
#[batch_impl((i32,)^u32)]
trait AppendTupleOne {}
fn test_tuple_append_one() {
fn _t<T: AppendTupleOne>() {}
_t::<(i32, u32)>();
println!(" 42. tuple append (i32,)^u32 = (i32,u32): OK");
}
#[batch_impl((i32,)^Box^u32)]
trait AppendTupleBox {}
fn test_tuple_append_box() {
fn _t<T: AppendTupleBox>() {}
_t::<(i32, Box<u32>)>();
println!(" 43. tuple append (i32,)^Box^u32 = (i32,Box<u32>): OK");
}
#[batch_impl([&,Vec]^[[(),(isize,)]^[Box,Rc,Arc]^[u8,i8,f32,f64,i16,u16]])]
trait ComplexNest {}
fn test_complex_nest() {
fn _check<T: ComplexNest + ?Sized>() {}
_check::<&(Box<u8>,)>();
_check::<&(Arc<f64>,)>();
_check::<Vec<(Box<u8>,)>>();
_check::<Vec<(Arc<f64>,)>>();
_check::<&(isize, Box<u8>)>();
_check::<&(isize, Arc<f64>)>();
_check::<Vec<(isize, Box<u8>)>>();
_check::<Vec<(isize, Arc<f64>)>>();
println!(" 44. complex nest: OK");
}
#[batch_impl((u32,i32)^3)]
trait CartesianSimple {}
fn test_cartesian_simple() {
fn _t<T: CartesianSimple>() {}
_t::<(u32, u32, u32)>();
_t::<(u32, u32, i32)>();
_t::<(u32, i32, u32)>();
_t::<(u32, i32, i32)>();
_t::<(i32, u32, u32)>();
_t::<(i32, u32, i32)>();
_t::<(i32, i32, u32)>();
_t::<(i32, i32, i32)>();
println!(" 44. cartesian (u32,i32)^3 = 8 combos: OK");
}
#[batch_impl((<Clone>,String)^2)]
trait CartesianBound {}
fn test_cartesian_bound() {
fn _t<T: CartesianBound>() {}
_t::<(String, String)>();
_t::<(i32, String)>();
_t::<(String, i32)>();
_t::<(i32, i32)>();
println!(" 45. cartesian bound (<Clone>,String)^2 = 4 combos: OK");
}
#[batch_impl(()-[usize,isize]-[u32,i32])]
trait DashSimple {}
fn test_dash_simple() {
fn _t<T: DashSimple>() {}
_t::<(usize, u32)>();
_t::<(usize, i32)>();
_t::<(isize, u32)>();
_t::<(isize, i32)>();
println!(" 46. dash ()-[usize,isize]-[u32,i32]: OK");
}
#[batch_impl(()-[usize,isize]-[u32,i32]-[u64,i64])]
trait Dash3D {}
fn test_dash_3d() {
fn _t<T: Dash3D>() {}
_t::<(usize, u32, u64)>();
_t::<(isize, i32, i64)>();
_t::<(usize, i32, u64)>();
println!(" 47. dash 3D: OK");
}
#[batch_impl(()-[usize,isize]-[u32,i32]-[u64,i64])]
trait DashFull {}
fn test_dash_full() {
fn _t<T: DashFull>() {}
_t::<(usize, u32, u64)>();
_t::<(isize, i32, i64)>();
_t::<(usize, i32, u64)>();
_t::<(isize, u32, i64)>();
println!(" 48. dash full: OK");
}
#[batch_impl(()-[Box^u32, Vec^isize])]
trait DashCaret {}
fn test_dash_caret() {
fn _t<T: DashCaret>() {}
_t::<(Box<u32>,)>();
_t::<(Vec<isize>,)>();
println!(" 49. dash with ^ expansion: OK");
}
#[batch_impl(unsafe^usize, unsafe^Box<u32>, isize)]
unsafe trait UnsafePartial {}
fn test_unsafe_partial() {
fn _t<T: UnsafePartial>() {}
_t::<usize>();
_t::<Box<u32>>();
_t::<isize>();
println!(" 50. unsafe^T per-spec: OK");
}
#[batch_impl(usize, Box<u32>)]
unsafe trait UnsafeAll {
fn do_something(&self) {}
}
fn test_unsafe_all() {
42usize.do_something();
Box::new(42u32).do_something();
println!(" 51. unsafe trait auto-detect: OK");
}
unsafe trait UnsafeBatch {
fn batch_fn(&self) {}
}
batch_trait!(
unsafe UnsafeBatch: usize, isize
);
fn test_unsafe_batch() {
42usize.batch_fn();
0isize.batch_fn();
println!(" 52. batch_trait! unsafe: OK");
}
trait CmpBase {}
#[batch_impl(usize)]
trait CmpAttrBase {}
batch_trait!(CmpBase: usize);
fn test_cmp_basic() {
fn _a<T: CmpAttrBase>() {}
fn _b<T: CmpBase>() {}
_a::<usize>();
_b::<usize>();
println!(" cmp 1. basic: OK");
}
trait CmpGeneric {}
#[batch_impl(<T> Vec<T>)]
trait CmpAttrGeneric {}
batch_trait!(CmpGeneric: <T> Vec<T>);
fn test_cmp_generic() {
fn _a<T: CmpAttrGeneric>() {}
fn _b<T: CmpGeneric>() {}
_a::<Vec<i32>>();
_b::<Vec<i32>>();
println!(" cmp 2. generic: OK");
}
trait CmpTraitGen<T> {
fn wrap(val: T) -> Self;
}
#[batch_impl(<T> CmpAttrTraitGen<T> i32 { fn wrap(_val: T) -> Self { 0 } })]
trait CmpAttrTraitGen<T> {
fn wrap(val: T) -> Self;
}
batch_trait!(CmpTraitGen: <T> CmpTraitGen<T> i32 { fn wrap(_val: T) -> Self { 0 } });
fn test_cmp_trait_generic() {
let _: i32 = CmpAttrTraitGen::<String>::wrap(String::new());
let _: i32 = CmpTraitGen::<String>::wrap(String::new());
println!(" cmp 3. trait generic + body: OK");
}
trait CmpList {
fn tag(&self) -> &'static str;
}
#[batch_impl([u8, u16] { fn tag(&self) -> &'static str { "cmp" } })]
trait CmpAttrList {
fn tag(&self) -> &'static str;
}
batch_trait!(CmpList: [u8, u16] { fn tag(&self) -> &'static str { "cmp" } });
fn test_cmp_list() {
assert_eq!(CmpAttrList::tag(&0u8), "cmp");
assert_eq!(CmpList::tag(&0u16), "cmp");
println!(" cmp 4. list: OK");
}
trait CmpCaret {}
#[batch_impl(&^u32)]
trait CmpAttrCaret {}
batch_trait!(CmpCaret: &^u32);
fn test_cmp_caret() {
fn _a<T: CmpAttrCaret>() {}
fn _b<T: CmpCaret>() {}
_a::<&u32>();
_b::<&u32>();
println!(" cmp 5. caret: OK");
}
trait CmpNestedCaret {}
#[batch_impl(Box^Box^isize)]
trait CmpAttrNestedCaret {}
batch_trait!(CmpNestedCaret: Box^Box^isize);
fn test_cmp_nested_caret() {
fn _a<T: CmpAttrNestedCaret>() {}
fn _b<T: CmpNestedCaret>() {}
_a::<Box<Box<isize>>>();
_b::<Box<Box<isize>>>();
println!(" cmp 6. nested caret: OK");
}
trait CmpCaretBracket {}
#[batch_impl(Box^[Box^isize])]
trait CmpAttrCaretBracket {}
batch_trait!(CmpCaretBracket: Box^[Box^isize]);
fn test_cmp_caret_bracket() {
fn _a<T: CmpAttrCaretBracket>() {}
fn _b<T: CmpCaretBracket>() {}
_a::<Box<[Box<isize>]>>();
_b::<Box<[Box<isize>]>>();
println!(" cmp 7. caret through []: OK");
}
trait CmpConst<const N: usize> {
fn val() -> usize {
N
}
}
#[batch_impl(<const N: usize> CmpAttrConst<N> [i32; N])]
trait CmpAttrConst<const N: usize> {
fn val() -> usize {
N
}
}
batch_trait!(CmpConst: <const N: usize> CmpConst<N> [i32; N]);
fn test_cmp_const() {
let _a = <[i32; 5] as CmpAttrConst<5>>::val();
let _b = <[i32; 5] as CmpConst<5>>::val();
assert_eq!(_a, 5);
assert_eq!(_b, 5);
println!(" cmp 8. const generic: OK");
}
#[allow(dead_code)]
trait CmpLifetime<'a, T> {}
#[batch_impl(<'a, T: 'a> CmpAttrLifetime<'a, T> &'a T)]
#[allow(dead_code)]
trait CmpAttrLifetime<'a, T> {}
batch_trait!(CmpLifetime: <'a, T: 'a> CmpLifetime<'a, T> &'a T);
fn test_cmp_lifetime() {
fn _a<'a, T: 'a>()
where
&'a T: CmpAttrLifetime<'a, T>,
{
}
fn _b<'a, T: 'a>()
where
&'a T: CmpLifetime<'a, T>,
{
}
println!(" cmp 9. lifetime: OK");
}
mod cmp_mod {
pub trait PathTrait {}
}
trait CmpPath {}
#[batch_impl(u32)]
trait CmpAttrPath {}
batch_trait!(CmpPath: u32; cmp_mod::PathTrait: u32);
fn test_cmp_path() {
fn _a<T: CmpAttrPath>() {}
fn _b<T: CmpPath>() {}
fn _c<T: cmp_mod::PathTrait>() {}
_a::<u32>();
_b::<u32>();
_c::<u32>();
println!(" cmp 10. path trait: OK");
}
trait PlainA {}
trait PlainB {}
trait GenericC<T> {}
mod foo {
pub trait Bar {}
}
batch_trait!(
PlainA: usize, isize;
PlainB: f32;
GenericC: <T> GenericC<T> Vec<T>;
foo::Bar: u32
);
fn test_auto_impls() {
fn _check_a<T: PlainA>() {}
fn _check_b<T: PlainB>() {}
fn _check_c<T: GenericC<i32>>() {}
fn _check_path<T: foo::Bar>() {}
_check_a::<usize>();
_check_a::<isize>();
_check_b::<f32>();
_check_c::<Vec<i32>>();
_check_path::<u32>();
println!(" 38. auto_impls! macro (with path): OK");
}
#[batch_impl(unsafe^Box^u32)]
unsafe trait UnsafeNestedCaret {}
fn test_unsafe_nested_caret() {
fn _t<T: UnsafeNestedCaret>() {}
_t::<Box<u32>>();
println!(" 53. unsafe^Box^u32: OK");
}
#[batch_impl([unsafe^usize, unsafe^isize, u32])]
unsafe trait UnsafeList {}
fn test_unsafe_list() {
fn _t<T: UnsafeList>() {}
_t::<usize>();
_t::<isize>();
_t::<u32>();
println!(" 54. unsafe list: OK");
}
#[batch_impl(unsafe^&^u32)]
unsafe trait UnsafeRef {}
fn test_unsafe_ref() {
fn _t<T: UnsafeRef>() {}
_t::<&u32>();
println!(" 55. unsafe^&^u32: OK");
}
#[batch_impl(unsafe^&mut^u32)]
unsafe trait UnsafeRefMut {}
fn test_unsafe_ref_mut() {
fn _t<T: UnsafeRefMut>() {}
_t::<&mut u32>();
println!(" 56. unsafe^&mut^u32: OK");
}
trait BatchA {}
unsafe trait BatchB {}
trait BatchC {}
batch_trait!(
BatchA: usize, isize;
unsafe BatchB: u32, u64;
BatchC: f32
);
fn test_batch_partial_unsafe() {
fn _a<T: BatchA>() {}
fn _b<T: BatchB>() {}
fn _c<T: BatchC>() {}
_a::<usize>();
_b::<u32>();
_c::<f32>();
println!(" 57. batch_trait! partial unsafe: OK");
}
#[batch_impl(unsafe^[Box, Vec]^u32)]
unsafe trait UnsafeContainerList {}
fn test_unsafe_container_list() {
fn _t<T: UnsafeContainerList>() {}
_t::<Box<u32>>();
_t::<Vec<u32>>();
println!(" 58. unsafe^[Box,Vec]^u32: OK");
}
#[batch_impl(unsafe^()^3)]
unsafe trait UnsafeTupleGen {}
fn test_unsafe_tuple_gen() {
fn _t<T: UnsafeTupleGen>() {}
_t::<(i32, i32, i32)>();
println!(" 59. unsafe^()^3 = (A,B,C): OK");
}
#[batch_impl(unsafe^(u32,)^3)]
unsafe trait UnsafeTupleRepeat {}
fn test_unsafe_tuple_repeat() {
fn _t<T: UnsafeTupleRepeat>() {}
_t::<(u32, u32, u32)>();
println!(" 60. unsafe^(u32,)^3 = (u32,u32,u32): OK");
}
#[batch_impl(unsafe^()^u32)]
unsafe trait UnsafeTupleAppend {}
fn test_unsafe_tuple_append() {
fn _t<T: UnsafeTupleAppend>() {}
_t::<(u32,)>();
println!(" 61. unsafe^()^u32: OK");
}
#[batch_impl(unsafe^(<Clone>)^3)]
unsafe trait UnsafeTupleBound {}
fn test_unsafe_tuple_bound() {
fn _t<T: UnsafeTupleBound>() {}
_t::<(i32, i32, i32)>();
_t::<(String, String, String)>();
println!(" 62. unsafe^(<Clone>)^3 = (A:Clone,B:Clone,C:Clone): OK");
}
#[batch_impl(unsafe^()-[usize, isize]-[u32, i32])]
unsafe trait UnsafeDash {}
fn test_unsafe_dash() {
fn _t<T: UnsafeDash>() {}
_t::<(usize, u32)>();
_t::<(usize, i32)>();
_t::<(isize, u32)>();
_t::<(isize, i32)>();
println!(" 63. unsafe^()-[A,B]-[C,D]: OK");
}
#[batch_impl(<T> unsafe^Vec<T>)]
unsafe trait UnsafeGenericVec {}
fn test_unsafe_generic_vec() {
fn _t<T: UnsafeGenericVec>() {}
_t::<Vec<i32>>();
_t::<Vec<String>>();
println!(" 64. <T> unsafe^Vec<T>: OK");
}
#[batch_impl(<T> UnsafeTraitGen<T> unsafe^i32 {
fn wrap(_val: T) -> Self { 0 }
})]
unsafe trait UnsafeTraitGen<T> {
fn wrap(val: T) -> Self;
}
fn test_unsafe_trait_gen() {
let x: i32 = UnsafeTraitGen::<String>::wrap(String::from("hi"));
assert_eq!(x, 0);
println!(" 65. <T> Trait<T> unsafe^i32: OK");
}
#[batch_impl(fn(i32) -> bool, fn(String, &str) -> usize)]
trait FnMarker {}
fn test_fn_types() {
fn _check<T: FnMarker>() {}
_check::<fn(i32) -> bool>();
_check::<fn(String, &str) -> usize>();
println!(" special 1. fn types: OK");
}
#[batch_impl(
dyn std::fmt::Display,
dyn std::fmt::Debug + Send,
dyn std::fmt::Display + Send + Sync
)]
trait DynMarker2 {}
fn test_dyn_types() {
fn _check<T: DynMarker2 + ?Sized>() {}
_check::<dyn std::fmt::Display>();
_check::<dyn std::fmt::Debug + Send>();
_check::<dyn std::fmt::Display + Send + Sync>();
println!(" special 2. dyn types: OK");
}
#[batch_impl(
(i32,),
(i32, String),
(i32, String, bool),
()
)]
trait TupleMarker {}
fn test_tuple_types() {
fn _check<T: TupleMarker>() {}
_check::<(i32,)>();
_check::<(i32, String)>();
_check::<(i32, String, bool)>();
_check::<()>();
println!(" special 3. tuple types: OK");
}
#[batch_impl(&i32, &mut String, &str, &[u8])]
trait RefMarker2 {}
fn test_ref_types() {
fn _check<T: RefMarker2>() {}
_check::<&i32>();
_check::<&mut String>();
_check::<&str>();
_check::<&[u8]>();
println!(" special 4. ref types: OK");
}
#[batch_impl(*const i32, *mut u8)]
trait PtrMarker {}
fn test_pointer_types() {
fn _check<T: PtrMarker>() {}
_check::<*const i32>();
_check::<*mut u8>();
println!(" special 5. pointer types: OK");
}
#[batch_impl(
Box<dyn std::fmt::Display>,
Vec<fn(i32) -> bool>,
&(dyn std::fmt::Debug + Send),
Option<&mut String>,
*const Vec<u8>,
fn(&str) -> Vec<i32>,
(i32, &dyn std::fmt::Display),
Box<Vec<&str>>
)]
trait NestedSpecialMarker {}
fn test_nested_special_types() {
fn _check<T: NestedSpecialMarker>() {}
_check::<Box<dyn std::fmt::Display>>();
_check::<Vec<fn(i32) -> bool>>();
_check::<&(dyn std::fmt::Debug + Send)>();
_check::<Option<&mut String>>();
_check::<*const Vec<u8>>();
_check::<fn(&str) -> Vec<i32>>();
_check::<(i32, &dyn std::fmt::Display)>();
_check::<Box<Vec<&str>>>();
println!(" special 6. nested special types: OK");
}
#[batch_impl(<K> HashMap<K>^String)]
trait PrefillSingle {}
fn test_prefill_single() {
fn _check<T: PrefillSingle>() {}
_check::<HashMap<String, String>>();
println!(" 66. prefill: HashMap<K>^String = HashMap<K, String>: OK");
}
#[batch_impl(HashMap-u32-String)]
trait DashHashMap {}
fn test_dash_hashmap() {
fn _check<T: DashHashMap>() {}
_check::<HashMap<u32, String>>();
println!(" 67. dash: HashMap-u32-String = HashMap<u32, String>: OK");
}
#[batch_impl(<T> IterAssoc<Item=T> Vec<T> {
fn iter_count(&self) -> usize { self.len() }
})]
trait IterAssoc {
type Item;
fn iter_count(&self) -> usize;
}
fn test_assoc_binding() {
let v = vec![1, 2, 3];
assert_eq!(v.iter_count(), 3);
fn _check<T: IterAssoc<Item = i32>>() {}
_check::<Vec<i32>>();
println!(" 68. assoc: <T> IterAssoc<Item=T> Vec<T>: OK");
}
#[batch_impl(<T, U> PairAssoc<First=T, Second=U> (T, U))]
trait PairAssoc {
type First;
type Second;
}
fn test_assoc_multi_binding() {
fn _check<T: PairAssoc<First = i32, Second = String>>() {}
_check::<(i32, String)>();
println!(" 69. assoc multi: <T,U> PairAssoc<First=T,Second=U> (T,U): OK");
}
#[batch_impl(
[usize { fn name() -> &'static str { "usize" } },
isize { fn name() -> &'static str { "isize" } }]
{ fn zero() -> Self { 0 } }
)]
trait ZeroAssoc {
fn zero() -> Self;
fn name() -> &'static str;
}
fn test_shared_independent_body() {
assert_eq!(usize::zero(), 0);
assert_eq!(isize::zero(), 0);
assert_eq!(usize::name(), "usize");
assert_eq!(isize::name(), "isize");
println!(" 70. shared+independent body: OK");
}
#[batch_impl(
usize { fn describe(&self) -> String { format!("usize: {}", self) } },
String { fn describe(&self) -> String { format!("string: {}", self) } }
)]
trait DescribeAssoc {
fn describe(&self) -> String;
}
fn test_independent_body_only() {
assert_eq!(42usize.describe(), "usize: 42");
assert_eq!(String::from("hi").describe(), "string: hi");
println!(" 71. independent body only: OK");
}
#[batch_impl(
[[usize { fn deep_type_name() -> &'static str { "usize" } },
isize { fn deep_type_name() -> &'static str { "isize" } }]
{ fn deep_is_signed() -> bool { true } },
f32 { fn deep_type_name() -> &'static str { "f32" } fn deep_is_signed() -> bool { false } }]
{ fn deep_zero() -> usize { 0 } }
)]
trait DeepNested {
fn deep_zero() -> usize;
fn deep_is_signed() -> bool;
fn deep_type_name() -> &'static str;
}
fn test_nested_shared_body_3level() {
assert_eq!(usize::deep_zero(), 0);
assert_eq!(isize::deep_zero(), 0);
assert_eq!(f32::deep_zero(), 0);
assert_eq!(usize::deep_is_signed(), true);
assert_eq!(isize::deep_is_signed(), true);
assert_eq!(f32::deep_is_signed(), false);
assert_eq!(usize::deep_type_name(), "usize");
assert_eq!(isize::deep_type_name(), "isize");
assert_eq!(f32::deep_type_name(), "f32");
println!(" 72. 3-level nested shared/independent body: OK");
}
#[batch_impl(
[<T> WrapAssoc<Item=Vec<T>> Vec<T> { fn wrap_count(&self) -> usize { self.len() } },
<K, V> WrapAssoc<Item=HashMap<K, V>> HashMap<K, V> { fn wrap_count(&self) -> usize { self.len() } }]
{ fn wrap_tag() -> &'static str { "container" } }
)]
trait WrapAssoc {
type Item;
fn wrap_count(&self) -> usize;
fn wrap_tag() -> &'static str;
}
fn test_nested_shared_body_with_assoc() {
assert_eq!(vec![1, 2, 3].wrap_count(), 3);
let mut m = std::collections::HashMap::new();
m.insert(1, "a");
assert_eq!(m.wrap_count(), 1);
assert_eq!(Vec::<i32>::wrap_tag(), "container");
assert_eq!(std::collections::HashMap::<i32, i32>::wrap_tag(), "container");
println!(" 73. nested + assoc type: OK");
}
#[batch_impl(
<T: Clone> TupleAssoc<Output=(T, T)> Vec<T> {
fn double_first(&self) -> (T, T) { (self[0].clone(), self[0].clone()) }
},
<K: Clone, V: Clone> TupleAssoc<Output=(K, V)> HashMap<K, V> {
fn double_first(&self) -> (K, V) {
let (k, v) = self.iter().next().unwrap();
(k.clone(), v.clone())
}
}
)]
trait TupleAssoc {
type Output;
fn double_first(&self) -> Self::Output;
}
fn test_complex_assoc_tuple_array() {
let v = vec![1, 2, 3];
let (a, b) = v.double_first();
assert_eq!(a, 1);
assert_eq!(b, 1);
let mut m = std::collections::HashMap::new();
m.insert(10, "hello");
let (k, val) = m.double_first();
assert_eq!(k, 10);
assert_eq!(val, "hello");
println!(" 74. assoc -> tuple: OK");
}
#[batch_impl(
[<T> FullComboA<Item=T> Vec<T> {
fn combo_name() -> &'static str { "vec" }
},
<K, V> FullComboA<Item=(K, V)> HashMap<K, V> {
fn combo_name() -> &'static str { "map" }
}]
{ fn combo_is_container() -> bool { true } }
)]
trait FullComboA {
type Item;
fn combo_name() -> &'static str;
fn combo_is_container() -> bool;
}
#[batch_impl(
<T> FullTupleA<Elements=(T, T)> (T, T) {
fn full_tuple_len() -> usize { 2 }
}
)]
trait FullTupleA {
type Elements;
fn full_tuple_len() -> usize;
}
fn test_complex_all_combined() {
assert_eq!(Vec::<i32>::combo_name(), "vec");
assert_eq!(std::collections::HashMap::<i32, i32>::combo_name(), "map");
assert_eq!(Vec::<i32>::combo_is_container(), true);
assert_eq!(std::collections::HashMap::<i32, i32>::combo_is_container(), true);
assert_eq!(<(i32, i32) as FullTupleA>::full_tuple_len(), 2);
println!(" 75. complex: shared/assoc/generic/tuple: OK");
}
#[batch_impl(<T> UnsafeAssoc<Item=T> Vec<T> {
fn unsafe_len(&self) -> usize { self.len() }
})]
unsafe trait UnsafeAssoc {
type Item;
fn unsafe_len(&self) -> usize;
}
fn test_assoc_unsafe() {
let v = vec![1, 2, 3];
assert_eq!(v.unsafe_len(), 3);
println!(" 76. assoc + unsafe: OK");
}
#[batch_impl(
<T> MultiAssoc<Item=T> Vec<T> {
fn multi_name() -> &'static str { "vec" }
},
<K, V> MultiAssoc<Item=(K, V)> HashMap<K, V> {
fn multi_name() -> &'static str { "hashmap" }
}
)]
trait MultiAssoc {
type Item;
fn multi_name() -> &'static str;
}
fn test_assoc_multi_type() {
assert_eq!(Vec::<i32>::multi_name(), "vec");
assert_eq!(std::collections::HashMap::<i32, i32>::multi_name(), "hashmap");
println!(" 77. assoc + multi type: OK");
}
#[batch_impl(
<T: Clone> BoundAssoc<Item=T> Vec<T> {
fn bound_first(&self) -> T { self[0].clone() }
}
)]
trait BoundAssoc {
type Item;
fn bound_first(&self) -> Self::Item;
}
fn test_assoc_bound() {
let v = vec![1, 2, 3];
assert_eq!(v.bound_first(), 1);
println!(" 78. assoc + generic bound: OK");
}
#[batch_impl(
<T> SharedAssoc<Item=T> Vec<T> {
fn shared_tag() -> &'static str { "shared" }
}
)]
trait SharedAssoc {
type Item;
fn shared_tag() -> &'static str;
}
fn test_assoc_shared() {
assert_eq!(Vec::<i32>::shared_tag(), "shared");
println!(" 79. assoc + shared body: OK");
}
#[batch_impl(<T> CaretAssoc<Item=T> Box^T)]
trait CaretAssoc {
type Item;
}
fn test_assoc_caret() {
fn _check<T: CaretAssoc<Item = i32>>() {}
_check::<Box<i32>>();
println!(" 80. assoc + ^ operator: OK");
}
#[batch_impl(<T> DashAssocA<Item=T> Vec-T)]
trait DashAssocA {
type Item;
}
fn test_assoc_dash() {
fn _check<T: DashAssocA<Item = i32>>() {}
_check::<Vec<i32>>();
println!(" 81. assoc + - operator: OK");
}
#[batch_impl(*const^u32, *const^i32)]
trait ConstPtrMarker {}
fn test_const_ptr() {
fn _check<T: ConstPtrMarker>() {}
_check::<*const u32>();
_check::<*const i32>();
println!(" 82. *const^T = *const T: OK");
}
#[batch_impl(*mut^u32, *mut^i32)]
trait MutPtrMarker {}
fn test_mut_ptr() {
fn _check<T: MutPtrMarker>() {}
_check::<*mut u32>();
_check::<*mut i32>();
println!(" 83. *mut^T = *mut T: OK");
}
#[batch_impl(&^Box^u32)]
trait RefCaretChain {}
fn test_ref_caret_chain() {
fn _check<T: RefCaretChain>() {}
_check::<&Box<u32>>();
println!(" 84. &^Box^u32 = &Box<u32>: OK");
}
#[batch_impl(&mut^Vec^i32)]
trait RefMutCaretChain {}
fn test_refmut_caret_chain() {
fn _check<T: RefMutCaretChain>() {}
_check::<&mut Vec<i32>>();
println!(" 85. &mut^Vec^i32 = &mut Vec<i32>: OK");
}
#[batch_impl(*const^Box^u64)]
trait ConstPtrCaretChain {}
fn test_constptr_caret_chain() {
fn _check<T: ConstPtrCaretChain>() {}
_check::<*const Box<u64>>();
println!(" 86. *const^Box^u64 = *const Box<u64>: OK");
}
#[batch_impl(*mut^Vec^String)]
trait MutPtrCaretChain {}
fn test_mutptr_caret_chain() {
fn _check<T: MutPtrCaretChain>() {}
_check::<*mut Vec<String>>();
println!(" 87. *mut^Vec^String = *mut Vec<String>: OK");
}
#[batch_impl(fn^(i32, u32))]
trait FnSimple {}
fn test_fn_simple() {
fn _check<T: FnSimple>() {}
_check::<fn(i32, u32)>();
println!(" 88. fn^(i32,u32) = fn(i32,u32): OK");
}
#[batch_impl(fn(i32, u32)-String)]
trait FnWithReturn {}
fn test_fn_with_return() {
fn _check<T: FnWithReturn>() {}
_check::<fn(i32, u32) -> String>();
println!(" 89. fn(i32,u32)-String = fn(i32,u32)->String: OK");
}
#[batch_impl(fn-(i32, u32)^2)]
trait FnTupleGen {}
fn test_fn_tuple_gen() {
fn _check<T: FnTupleGen>() {}
_check::<fn(i32, i32)>();
_check::<fn(i32, u32)>();
_check::<fn(u32, i32)>();
_check::<fn(u32, u32)>();
println!(" 90. fn-(i32,u32)^2 = 4 fn types: OK");
}
#[batch_impl(()^1..3)]
trait RangeTupleNew {}
fn test_range_tuple() {
fn _t<T: RangeTupleNew>() {}
_t::<(i32,)>();
_t::<(i32, String)>();
println!(" 91. ()^1..3 = (A,), (A,B): OK");
}
#[batch_impl(#[allow(dead_code)]^usize, isize)]
trait AttrSimple {}
fn test_attr_simple() {
fn _check<T: AttrSimple>() {}
_check::<usize>();
_check::<isize>();
println!(" 92. #[allow(dead_code)]^usize: OK");
}
trait ConsistencyA {}
#[batch_impl(usize, isize)]
trait ConsistencyB {}
batch_trait!(ConsistencyA: usize, isize);
fn test_batch_consistency() {
fn _a<T: ConsistencyA>() {}
fn _b<T: ConsistencyB>() {}
_a::<usize>();
_a::<isize>();
_b::<usize>();
_b::<isize>();
println!(" 93. batch_impl vs batch_trait consistency: OK");
}
#[batch_impl(
[[usize { fn nested_name() -> &'static str { "usize" } },
isize { fn nested_name() -> &'static str { "isize" } }]
{ fn nested_zero() -> Self { 0 } },
[f32 { fn nested_name() -> &'static str { "f32" } },
f64 { fn nested_name() -> &'static str { "f64" } }]
{ fn nested_zero() -> Self { 0.0 } }]
{ fn nested_tag() -> &'static str { "number" } }
)]
trait DeepNestedTest {
fn nested_name() -> &'static str;
fn nested_zero() -> Self;
fn nested_tag() -> &'static str;
}
fn test_deep_nested() {
assert_eq!(usize::nested_name(), "usize");
assert_eq!(isize::nested_name(), "isize");
assert_eq!(f32::nested_name(), "f32");
assert_eq!(f64::nested_name(), "f64");
assert_eq!(usize::nested_zero(), 0);
assert_eq!(f32::nested_zero() as i32, 0);
assert_eq!(usize::nested_tag(), "number");
assert_eq!(f64::nested_tag(), "number");
println!(" 94. deep nested [[A,B],[C,D]]: OK");
}
#[batch_impl(
<T> MultiFeature<Item=T> Vec<T> {
fn feature_name() -> &'static str { "vec" }
},
<K, V> MultiFeature<Item=(K, V)> HashMap<K, V> {
fn feature_name() -> &'static str { "hashmap" }
}
)]
trait MultiFeature {
type Item;
fn feature_name() -> &'static str;
}
fn test_multi_feature() {
assert_eq!(Vec::<i32>::feature_name(), "vec");
assert_eq!(HashMap::<i32, i32>::feature_name(), "hashmap");
println!(" 95. multi-feature parallel: OK");
}
fn main() {
println!("=== auto_impl macro tests ===");
println!("=== auto_impl macro tests ===");
test_basic();
test_generic();
test_trait_with_generic();
test_custom_body();
test_generic_list();
test_multi_custom();
test_trait_generic_list();
test_slice_type();
test_nested();
test_multi_specs_with_body();
test_complex_types();
test_nested_angle_brackets();
test_path_type();
test_trait_name_as_target();
test_multi_trait_params();
test_nested_bracket_list();
test_slice_with_body();
test_plain_ident();
test_dyn_trait_object();
test_box_generic();
test_complex_trait_generic();
test_multi_complex_trait_generic();
test_type_bound();
test_const_generic();
test_mixed_generics();
test_lifetime_generic();
test_caret_basic();
test_caret_container();
test_caret_prefix_list();
test_caret_cartesian();
test_caret_multi_arg();
test_caret_multi_map_list();
test_caret_comprehensive();
test_nested_caret();
test_caret_through_bracket();
test_tuple_gen();
test_tuple_repeat();
test_tuple_range();
test_tuple_range_inclusive();
test_tuple_bound();
test_tuple_append_empty();
test_tuple_append_one();
test_tuple_append_box();
test_complex_nest();
test_cartesian_simple();
test_cartesian_bound();
test_dash_simple();
test_dash_3d();
test_dash_full();
test_dash_caret();
test_unsafe_partial();
test_unsafe_all();
test_unsafe_batch();
test_auto_impls();
test_unsafe_nested_caret();
test_unsafe_list();
test_unsafe_ref();
test_unsafe_ref_mut();
test_batch_partial_unsafe();
test_unsafe_container_list();
test_unsafe_tuple_gen();
test_unsafe_tuple_repeat();
test_unsafe_tuple_append();
test_unsafe_tuple_bound();
test_unsafe_dash();
test_unsafe_generic_vec();
test_unsafe_trait_gen();
test_fn_types();
test_dyn_types();
test_tuple_types();
test_ref_types();
test_pointer_types();
test_nested_special_types();
test_prefill_single();
test_dash_hashmap();
test_assoc_binding();
test_assoc_multi_binding();
test_shared_independent_body();
test_independent_body_only();
test_nested_shared_body_3level();
test_nested_shared_body_with_assoc();
test_complex_assoc_tuple_array();
test_complex_all_combined();
test_assoc_unsafe();
test_assoc_multi_type();
test_assoc_bound();
test_assoc_shared();
test_assoc_caret();
test_assoc_dash();
test_const_ptr();
test_mut_ptr();
test_ref_caret_chain();
test_refmut_caret_chain();
test_constptr_caret_chain();
test_mutptr_caret_chain();
test_fn_simple();
test_fn_with_return();
test_fn_tuple_gen();
test_range_tuple();
test_attr_simple();
test_batch_consistency();
test_deep_nested();
test_multi_feature();
println!("\n--- comparison tests ---");
test_cmp_basic();
test_cmp_generic();
test_cmp_trait_generic();
test_cmp_list();
test_cmp_caret();
test_cmp_nested_caret();
test_cmp_caret_bracket();
test_cmp_const();
test_cmp_lifetime();
test_cmp_path();
println!("\nAll tests passed!");
}