use batch_impl::{batch_impl, batch_impl_only, batch_preprocess_test, batch_trait};
use std::collections::HashMap;
use std::rc::Rc;
#[batch_impl(usize, isize)]
trait Numeric {}
#[test]
fn basic_numeric() {
fn check<T: Numeric>(_: &T) {}
check(&0usize);
check(&0isize);
}
#[batch_impl(<T> Vec<T>)]
trait Collection {}
#[test]
fn generic_vec() {
fn check<T: Collection>(_: &T) {}
check(&vec![1, 2, 3]);
check(&vec!["a", "b"]);
}
#[batch_impl(
[usize { fn name() -> &'static str { "usize" } },
isize { fn name() -> &'static str { "isize" } }]
{ fn zero() -> Self { 0 } }
)]
trait Zero {
fn zero() -> Self;
fn name() -> &'static str;
}
#[test]
fn shared_independent_body() {
assert_eq!(usize::zero(), 0);
assert_eq!(isize::zero(), 0);
assert_eq!(<usize as Zero>::name(), "usize");
assert_eq!(<isize as Zero>::name(), "isize");
}
#[batch_impl([&, Box, Rc]^u32)]
trait RefOrOwnedEmpty {}
#[test]
fn caret_prefix_list() {
fn check<T: RefOrOwnedEmpty>(_: &T) {}
let v: u32 = 5;
check(&(&v));
check(&Box::new(v));
check(&Rc::new(v));
}
#[batch_impl(()^3)]
trait Tuple3 {}
#[test]
fn tuple_pow_basic() {
fn check<T: Tuple3>(_: &T) {}
check(&(1u8, 2u16, 3u32));
}
#[batch_impl(()^1)]
trait Tuple1 {}
#[batch_impl(()^2)]
trait Tuple2 {}
#[batch_impl(()^3)]
trait Tuple3R {}
#[test]
fn tuple_range_pow() {
fn t1<T: Tuple1>(_: &T) {}
fn t2<T: Tuple2>(_: &T) {}
fn t3<T: Tuple3R>(_: &T) {}
t1(&(1u8,));
t2(&(1u8, 2u16));
t3(&(1u8, 2u16, 3u32));
}
#[batch_impl(<T> Iter<Item=T> Vec<T> {
fn count(&self) -> usize { self.len() }
})]
trait Iter {
type Item;
fn count(&self) -> usize;
}
#[test]
fn assoc_type_binding() {
assert_eq!(vec![1, 2, 3].count(), 3);
}
#[batch_impl(usize, Box<u32>)]
unsafe trait UnsafeAll {}
#[test]
fn unsafe_trait_impls() {
fn check<T: UnsafeAll>(_: &T) {}
check(&0usize);
check(&Box::new(0u32));
}
#[batch_impl(unsafe^usize, isize)]
unsafe trait PartialUnsafe {}
#[test]
fn partial_unsafe() {
fn check<T: PartialUnsafe>(_: &T) {}
check(&0usize);
check(&0isize);
}
#[batch_impl(fn^(i32, u32))]
trait FnSimple {}
#[batch_impl(fn(i32, u32)-String)]
trait FnWithReturn {}
#[test]
fn fn_types() {
fn check_simple<T: FnSimple>(_: &T) {}
fn check_ret<T: FnWithReturn>(_: &T) {}
let f: fn(i32, u32) = |_, _| {};
check_simple(&f);
let fr: fn(i32, u32) -> String = |_, _| String::new();
check_ret(&fr);
}
#[batch_impl(#[allow(dead_code)]^usize, isize)]
trait AttrSimple {}
#[test]
fn attr_support() {
fn check<T: AttrSimple>(_: &T) {}
check(&0usize);
check(&0isize);
}
#[batch_impl(
(i32, String),
&str,
Box<dyn std::fmt::Display>,
fn(i32) -> bool,
dyn Fn() + Send + Sync
)]
trait ComplexMarker {}
#[test]
fn complex_passthrough() {
fn check<T: ComplexMarker + ?Sized>(_: &T) {}
check(&(1i32, String::from("x")));
check(&"hi");
let bd: Box<dyn std::fmt::Display> = Box::new(1i32);
check(&bd);
let ft: fn(i32) -> bool = |_| true;
check(&ft);
fn _dyn_check<T: ComplexMarker + ?Sized>() {}
_dyn_check::<dyn Fn() + Send + Sync>();
}
#[batch_impl(
usize #to_str{"usize"},
isize #to_str{"isize"}
)]
trait IdentToString {
fn to_str(&self) -> &'static str;
}
#[test]
fn directive_single_name() {
assert_eq!(0usize.to_str(), "usize");
assert_eq!(0isize.to_str(), "isize");
}
#[batch_impl(usize #fill(name, kind){"u"})]
trait Describable {
fn name(&self) -> &'static str;
fn kind(&self) -> &'static str;
}
#[test]
fn directive_fill() {
assert_eq!(0usize.name(), "u");
assert_eq!(0usize.kind(), "u");
}
#[batch_impl(
Vec<u32> #d_len{self.len()},
Box^Vec^u32 #delegate(d_len){**self}
)]
trait MyLen {
fn d_len(&self) -> usize;
}
#[test]
fn directive_delegate() {
let v: Vec<u32> = vec![1, 2, 3];
assert_eq!(v.d_len(), 3);
let b: Box<Vec<u32>> = Box::new(vec![1, 2, 3, 4]);
assert_eq!(b.d_len(), 4);
}
trait BTNumeric {}
trait BTMap {}
batch_trait!(
BTNumeric: u8, u16, u32, u64;
BTMap: HashMap<i32, i32>
);
#[test]
fn batch_trait_macro_basic() {
fn check_num<T: BTNumeric>(_: &T) {}
fn check_map<T: BTMap>(_: &T) {}
check_num(&0u8);
check_num(&0u16);
check_num(&0u32);
check_num(&0u64);
check_map(&HashMap::<i32, i32>::new());
}
trait PairSegment {}
batch_trait!(
PairSegment: usize, isize;
unsafe YieldUnsafe: u32
);
#[allow(dead_code)] unsafe trait YieldUnsafe {}
#[test]
fn batch_trait_multi_segment_unsafe() {
fn check_pair<T: PairSegment>(_: &T) {}
check_pair(&0usize);
check_pair(&0isize);
}
trait DropDefOnly {
fn m(&self) -> u32;
}
#[batch_impl_only(usize #m{42})]
trait DropDefOnly {
fn m(&self) -> u32;
}
#[test]
fn batch_impl_only_drops_trait() {
assert_eq!(0usize.m(), 42);
}
#[batch_impl(HashMap-u32-String)]
trait DashMapGen {}
#[test]
fn dash_op() {
fn check<T: DashMapGen>(_: &T) {}
check(&HashMap::<u32, String>::new());
}
#[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;
}
#[test]
fn nested_generic_list() {
let v: Vec<i32> = vec![1, 2, 3];
assert_eq!(v.describe(), "len=3");
let m: HashMap<i32, String> = HashMap::from([(1, String::from("a"))]);
assert_eq!(m.describe(), "len=1");
}
#[batch_impl(<T: Clone> Sortable<T> Vec<T> where{ T: Ord } {
fn is_sorted(&self) -> bool {
self.windows(2).all(|w| w[0] <= w[1])
}
})]
trait Sortable<T> {
fn is_sorted(&self) -> bool;
}
#[test]
fn dsl_where_clause() {
let v: Vec<i32> = vec![1, 2, 3];
assert!(v.is_sorted());
let v: Vec<i32> = vec![3, 1, 2];
assert!(!v.is_sorted());
}
#[batch_impl(
<T> Singleton<T> Vec<T> where{ T: Clone + Default }
{ fn only(&self) -> T { self.first().cloned().unwrap_or_default() } }
)]
trait Singleton<T> {
fn only(&self) -> T;
}
#[test]
fn suffix_where_clause() {
let v: Vec<i32> = vec![42];
assert_eq!(v.only(), 42);
let v: Vec<String> = vec![];
assert_eq!(v.only(), String::new());
}
trait PairAB<A, B> {
fn pair(&self) -> (A, B);
}
#[batch_impl_only(
<A> <B> PairAB<A, B> (A, B) where{ A: Clone, B: Clone }
{ fn pair(&self) -> (A, B) { (self.0.clone(), self.1.clone()) } }
)]
trait PairAB<A, B> {
fn pair(&self) -> (A, B);
}
#[test]
fn nested_generics_merge() {
let p = (1u32, String::from("x"));
assert_eq!(p.pair(), (1u32, String::from("x")));
}
#[batch_impl(
<T> WrapOrd<T> [Box, Rc]^Vec<T> where{ T: Ord }
{ fn is_sorted(&self) -> bool { self.windows(2).all(|w| w[0] <= w[1]) } }
)]
trait WrapOrd<T> {
fn is_sorted(&self) -> bool;
}
#[test]
fn where_with_list_modifier() {
use std::rc::Rc;
assert!(WrapOrd::<i32>::is_sorted(&Box::new(vec![1, 2, 3])));
assert!(!WrapOrd::<i32>::is_sorted(&Rc::new(vec![3, 1, 2])));
}
#[batch_impl(
<A> <B> PairComma<A, B> (A, B)
where A: Clone, B: Clone #both{ (self.0.clone(), self.1.clone()) }
)]
trait PairComma<A, B> {
fn both(&self) -> (A, B);
}
#[test]
fn where_bare_comma_predicates() {
let p = (1u32, String::from("x"));
assert_eq!(PairComma::both(&p), (1u32, String::from("x")));
}
macro_rules! m {
() => {
u32
};
}
#[batch_impl(
<T> FnRet<T> Vec<T> where T: Fn(u32) -> m!{}
{ fn ret_is_ok(&self) -> bool { true } }
)]
trait FnRet<T> {
fn ret_is_ok(&self) -> bool;
}
#[test]
fn where_macro_body_excluded() {
let v: Vec<fn(u32) -> u32> = vec![|x| x + 1];
assert!(v.ret_is_ok());
}
#[batch_impl(
<T> MultiOrd<T> Vec<T> where T: Ord where T: Clone {}
)]
trait MultiOrd<T> {}
#[test]
fn where_bare_multi_clause() {
fn check<T: MultiOrd<i32>>() {}
check::<Vec<i32>>();
}
#[batch_impl(usize #batch_preprocess_test(add,inc){*self+1})]
trait AddInc {
fn add(&self) -> Self;
fn inc(&self) -> Self;
}
#[test]
fn open_extension_fn_like_macro() {
assert_eq!(5usize.add(), 6);
assert_eq!(5usize.inc(), 6);
}
#[batch_impl(unsafe fn(u32) -> u32)]
trait UnsafeFnMarker {}
#[batch_impl(unsafe fn^(u32, i32))]
trait UnsafeFnPow {}
#[batch_impl(unsafe fn^(u32, i32) - i64)]
trait UnsafeFnRet {}
#[test]
fn unsafe_fn_type() {
fn check<T: UnsafeFnMarker>(_: &T) {}
let f: unsafe fn(u32) -> u32 = |x| x;
check(&f);
fn check_pow<T: UnsafeFnPow>(_: &T) {}
let g: unsafe fn(u32, i32) = |_, _| {};
check_pow(&g);
fn check_ret<T: UnsafeFnRet>(_: &T) {}
let h: unsafe fn(u32, i32) -> i64 = |a, b| a as i64 + b as i64;
check_ret(&h);
}
#[batch_impl(usize #fill(#all,-skip_me){0})]
trait ExceptInline {
fn keep_me(&self) -> u32;
fn skip_me(&self) -> u32 {
999
}
const VALUE: u32;
}
#[batch_impl(isize #fill(#all,-#all_methods){1})]
trait MarkMinus {
fn m(&self) -> u32 {
7
}
const C: u32;
}
#[batch_impl(u32 #fill(a, -b){2})]
trait ListMinus {
fn a(&self) -> u32;
fn b(&self) -> u32 {
8
}
}
#[test]
fn directive_minus_exclude() {
assert_eq!(1usize.keep_me(), 0);
assert_eq!(1usize.skip_me(), 999);
assert_eq!(<usize as ExceptInline>::VALUE, 0);
assert_eq!(<isize as MarkMinus>::C, 1);
assert_eq!(0isize.m(), 7);
let u = 3u32;
assert_eq!(u.a(), 2);
assert_eq!(u.b(), 8);
}
#[rustfmt::skip]
#[batch_impl(usize, isize,)]
trait TrailingCommaOk {}
#[batch_impl(())]
trait EmptyTupleOk {}
#[batch_impl(usize, isize)]
trait NoTrailingIssue {}
#[test]
fn strictness_legal_forms() {
fn check<T: TrailingCommaOk>() {}
check::<usize>();
check::<isize>();
fn check2<T: EmptyTupleOk>() {}
check2::<()>();
fn check3<T: NoTrailingIssue>() {}
check3::<isize>();
}
#[batch_impl(<T> Cloned<T> Vec<T> {
fn get(&self) -> T {
self[0].clone()
}
})]
trait Cloned<T: Clone> {
fn get(&self) -> T;
}
trait SupA {}
trait SupB: SupA {}
struct SupS;
impl SupA for SupS {}
impl SupB for SupS {}
#[batch_impl(<T: SupB> Inherit<T> ())]
trait Inherit<T: SupA> {}
#[batch_impl(<'a, T> Lifetime<'a, T> ())]
trait Lifetime<'a, T: 'a> {}
#[batch_impl(<'b, T: 'b> LifetimeRenamed<'b, T> ())]
trait LifetimeRenamed<'a, T: 'a> {}
#[batch_impl(<T> StaticT<T> ())]
trait StaticT<T: 'static> {}
#[batch_impl(<'a, T> Mix<'a, T> ())]
trait Mix<'a, T: Clone + 'a> {}
#[batch_impl(<T: SupB, U> PartialBound<T, U> ())]
trait PartialBound<T: SupA, U: SupA> {}
#[batch_impl(<T, U: SupB> PartialBound2<T, U> ())]
trait PartialBound2<T: SupA, U: SupA> {}
impl SupA for i32 {}
#[test]
fn trait_bound_inherit() {
let v: Vec<i32> = vec![42];
assert_eq!(v.get(), 42);
fn check<T: Inherit<SupS>>() {}
check::<()>();
fn check2<T: Lifetime<'static, ()>>() {}
check2::<()>();
fn check2r<T: LifetimeRenamed<'static, ()>>() {}
check2r::<()>();
fn check3<T: StaticT<()>>() {}
check3::<()>();
fn check4<T: Mix<'static, ()>>() {}
check4::<()>();
fn check_p<T: PartialBound<SupS, i32>>() {}
check_p::<()>();
fn check_p2<T: PartialBound2<i32, SupS>>() {}
check_p2::<()>();
}
#[batch_impl(EmptyGenA<> ())]
trait EmptyGenA<T: Clone> {}
#[batch_impl(EmptyGenB<> ())]
trait EmptyGenB<'a, T: 'a> {}
#[batch_impl(EmptyGenC<> Vec<T>)]
trait EmptyGenC<T> {}
#[batch_impl(AssocGen<Item=T> ())]
trait AssocGen<T: Clone> {
type Item;
}
#[batch_impl(AssocGen2<First=T, Second=U> ())]
trait AssocGen2<'a, T: Clone + 'a, U: Ord> {
type First;
type Second;
}
#[test]
fn empty_trait_generics() {
fn check_a<T: EmptyGenA<i32>>() {}
check_a::<()>();
fn check_b<T: EmptyGenB<'static, ()>>() {}
check_b::<()>();
fn check_c<T: EmptyGenC<i32>>() {}
check_c::<Vec<i32>>();
fn check_d<T: AssocGen<i32, Item = i32>>() {}
check_d::<()>();
fn check_e<T: AssocGen2<'static, i32, u32, First = i32, Second = u32>>() {}
check_e::<()>();
}