1#![cfg_attr(test, feature(specialization))]
2
3#[macro_export]
108#[doc(hidden)]
109macro_rules! specialize {
110 (
111 trait fn $trait_id:ident :: $trait_fn_id:ident
112 $($unparsed:tt)*
113 ) => {
114 specialize! {
115 @parse_fn_bounds
116 $trait_id $trait_fn_id
117 $($unparsed)*
118 }
119 };
120 (@parse_fn_bounds $trait_id:ident $trait_fn_id:ident (
121 $($trait_fn_args:tt)*
122 )
123 $($unparsed:tt)*
124 ) => {
125 specialize! {
126 @parse_fn_ty
127 $trait_id $trait_fn_id () ($($trait_fn_args)*)
128 $($unparsed)*
129 }
130 };
131 (@parse_fn_bounds $trait_id:ident $trait_fn_id:ident [
132 $($trait_fn_bounds:tt)+
133 ] (
134 $($trait_fn_args:tt)*
135 )
136
137 $($unparsed:tt)*
138 ) => {
139 specialize! {
140 @parse_fn_ty
141 $trait_id $trait_fn_id ($($trait_fn_bounds)+) ($($trait_fn_args)*)
142 $($unparsed)*
143 }
144 };
145 (@parse_fn_ty $trait_id:ident $trait_fn_id:ident $trait_fn_bounds:tt $trait_fn_args:tt
146 ;
147 $($unparsed:tt)*
148 ) => {
149 specialize! {
150 @parse_impl
151 $trait_id
152 ($trait_fn_id (()) $trait_fn_bounds () $trait_fn_args)
153 $($unparsed)*
154 }
155 };
156 (@parse_fn_ty $trait_id:ident $trait_fn_id:ident $trait_fn_bounds:tt $trait_fn_args:tt
157 -> $trait_fn_ty:ty;
158 $($unparsed:tt)*
159 ) => {
160 specialize! {
161 @parse_impl
162 $trait_id
163 ($trait_fn_id ($trait_fn_ty) $trait_fn_bounds () $trait_fn_args)
164 $($unparsed)*
165 }
166 };
167 (@parse_fn_ty $trait_id:ident $trait_fn_id:ident $trait_fn_bounds:tt $trait_fn_args:tt
168 -> $trait_fn_ty:ty where [$($trait_fn_where:tt)+];
169 $($unparsed:tt)*
170 ) => {
171 specialize! {
172 @parse_impl
173 $trait_id
174 ($trait_fn_id ($trait_fn_ty) $trait_fn_bounds (where $($trait_fn_where)+) $trait_fn_args)
175 $($unparsed)*
176 }
177 };
178 (@parse_fn_ty $trait_id:ident $trait_fn_id:ident $trait_fn_bounds:tt $trait_fn_args:tt
179 where [$($trait_fn_where:tt)+];
180 $($unparsed:tt)*
181 ) => {
182 specialize! {
183 @parse_impl
184 $trait_id
185 ($trait_fn_id (()) $trait_fn_bounds (where $($trait_fn_where)+) $trait_fn_args)
186 $($unparsed)*
187 }
188 };
189
190 (@parse_impl $trait_id:ident $trait_fn:tt
191 match impl[
192 $($trait_impl_bounds:tt)*
193 ] for $trait_impl_id:ident where [
194 $($trait_impl_where:tt)+
195 ] {
196 $($unparsed:tt)*
197 }
198 ) => {
199 specialize! {
200 @parse
201 ($trait_id $trait_impl_id ($($trait_impl_bounds)*) (, $($trait_impl_where)+))
202 $trait_fn
203 ()
204 ($($unparsed)*)
205 }
206 };
207 (@parse_impl $trait_id:ident $trait_fn:tt
208 match impl[
209 $($trait_impl_bounds:tt)*
210 ] for $trait_impl_id:ident {
211 $($unparsed:tt)*
212 }
213 ) => {
214 specialize! {
215 @parse
216 ($trait_id $trait_impl_id ($($trait_impl_bounds)*) ())
217 $trait_fn
218 ()
219 ($($unparsed)*)
220 }
221 };
222 (@parse
225 $trait_impl:tt
226 $trait_fn:tt
227 ($($clauses:tt)*)
228 (
229 where [
230 $($clause_where:tt)*
231 ] => $clause_expr:expr,
232 $($unparsed:tt)*
233 )
234 ) => {
235 specialize! { @parse
236 $trait_impl
237 $trait_fn
238 ($($clauses)*
239 (() ($($clause_where)*) $clause_expr)
240 )
241 ($($unparsed)*)
242 }
243 };
244 (@parse
245 $trait_impl:tt
246 $trait_fn:tt
247 ($($clauses:tt)*)
248 (
249 impl [
250 $($clause_bounds:tt)*
251 ] where [
252 $($clause_where:tt)*
253 ] => $clause_expr:expr,
254 $($unparsed:tt)*
255 )
256 ) => {
257 specialize! { @parse
258 $trait_impl
259 $trait_fn
260 ($($clauses)*
261 (($($clause_bounds)*) ($($clause_where)*) $clause_expr)
262 )
263 ($($unparsed)*)
264 }
265 };
266 (@parse
268 $trait_impl:tt
269 $trait_fn:tt
270 ($($clauses:tt)*)
271 (
272 _ => $clause_expr:expr $(,)*
273 )
274 ) => {
275 specialize! { @parse
276 $trait_impl
277 $trait_fn
278 ($($clauses)*
279 (() (u8: Copy) $clause_expr)
280 )
281 ()
282 }
283 };
284 (@parse
286 $trait_impl:tt
287 $trait_fn:tt
288 $clauses:tt
289 ()
290 ) => {
291 specialize! { @itemize
292 $trait_impl
293 $trait_fn
294 ()
295 $clauses
296 }
297 };
298 (@itemize
300 ($trait_id:ident $trait_impl_id:ident ($($trait_impl_bounds:tt)*) ($($trait_impl_where:tt)*))
301 ($trait_fn_id:ident ($trait_fn_ty:ty) ($($trait_fn_bounds:tt)*) ($($trait_fn_where:tt)*) ($($trait_fn_args:tt)*))
302 ($($items:tt)*)
303 ((($($clause_bounds:tt)*) ($($clause_where:tt)*) $clause_expr:expr) $($clauses:tt)*)
304 ) => {
305 specialize! { @itemize
306 ($trait_id $trait_impl_id ($($trait_impl_bounds)*) ($($trait_impl_where)*))
307 ($trait_fn_id ($trait_fn_ty) ($($trait_fn_bounds)*) ($($trait_fn_where)*) ($($trait_fn_args)*))
308 ($($items)*
309 impl<$($trait_impl_bounds)*, $($clause_bounds)*> $trait_id for $trait_impl_id where $($clause_where)* $($trait_impl_where)* {
310 default fn $trait_fn_id<
311 $($trait_fn_bounds)*
312 >($($trait_fn_args)*) -> $trait_fn_ty
313 $($trait_fn_where)* {
314 $clause_expr
315 }
316 }
317 )
318 ($($clauses)*)
319 }
320 };
321 (@itemize
323 $trait_impl:tt
324 $trait_fn:tt
325 ($($items:tt)*)
326 ()
327 ) => {
328 specialize! { @trait
329 $trait_impl
330 $trait_fn
331 }
332
333 specialize! { @items $($items)* }
334 };
335 (@trait
336 ($trait_id:ident $trait_impl_id:ident ($($trait_impl_bounds:tt)*) ($($trait_impl_where:tt)*))
337 ($trait_fn_id:ident ($trait_fn_ty:ty) ($($trait_fn_bounds:tt)*) ($($trait_fn_where:tt)*) ($($trait_fn_args:tt)*))
338 ) => {
339 specialize! { @items
340 trait $trait_id {
341 fn $trait_fn_id<
342 $($trait_fn_bounds)*
343 >($($trait_fn_args)*) -> $trait_fn_ty
344 $($trait_fn_where)*;
345 }
346 }
347 };
348 (@items $($i:item)*) => { $($i)* };
381 (@drop $($tt:tt)*) => { };
383}
384
385#[macro_export]
386#[doc(hidden)]
387macro_rules! constrain {
388 (ref mut [$value_id:tt : $($bounds:tt)*] = $default_ty:ty) => {
389 {
390 constrain! { @trait __ConstrainBounds__ ($($bounds)*) ($default_ty) }
391
392 constrain! { @expr __ConstrainBounds__::as_mut($value_id) }
393 }
394 };
395 (ref [$value_id:tt : $($bounds:tt)*] = $default_ty:ty) => {
396 {
397 constrain! { @trait __ConstrainBounds__ ($($bounds)*) ($default_ty) }
398
399 constrain! { @expr __ConstrainBounds__::as_ref($value_id) }
400 }
401 };
402 (ref [$value_id:tt : $($bounds:tt)*] = $default_ty:ty) => {
403 {
404 constrain! { @trait __ConstrainBounds__ ($($bounds)*) ($default_ty) }
405
406 constrain! { @expr __ConstrainBounds__::as_ref($value_id) }
407 }
408 };
409 (type [$value_id:tt : $($bounds:tt)*]) => {
410 {
411 constrain! { @trait __ConstrainBounds__ ($($bounds)*) }
412
413 constrain! { @expr <$value_id as __ConstrainBounds__>::is() }
414 }
415 };
416 ([$value_id:tt : $($bounds:tt)*] = $default_ty:ty) => {
417 {
418 constrain! { @trait __ConstrainBounds__ ($($bounds)*) ($default_ty) }
419
420 constrain! { @expr __ConstrainBounds__::move_($value_id) }
421 }
422 };
423 (ref mut $value_id:tt as $ty:ty) => {
424 {
425 constrain! { @trait_concrete __ConstrainEq__ ($ty) }
426
427 constrain! { @expr __ConstrainEq__::as_mut($value_id) }
428 }
429 };
430 (ref $value_id:tt as $ty:ty) => {
431 {
432 constrain! { @trait_concrete __ConstrainEq__ ($ty) }
433
434 constrain! { @expr __ConstrainEq__::as_ref($value_id) }
435 }
436 };
437 (type $ty:ty as $ty_eq:ty) => {
438 {
439 constrain! { @trait_concrete __ConstrainEq__ ($ty_eq) }
440
441 constrain! { @expr <$ty as __ConstrainEq__>::is() }
442 }
443 };
444 ($value_id:tt as $ty:ty) => {
445 {
446 constrain! { @trait_concrete __ConstrainEq__ ($ty) }
447
448 constrain! { @expr __ConstrainEq__::move_($value_id) }
449 }
450 };
451 (@trait_concrete $trait_id:ident ($ty:ty)) => {
452 trait $trait_id {
453 fn is() -> bool;
454 fn move_(self) -> Option<$ty> where Self: Sized, $ty: Sized;
455 fn as_ref(&self) -> Option<&$ty>;
456 fn as_mut(&mut self) -> Option<&mut $ty>;
457 }
458
459 impl<T: ?Sized> $trait_id for T {
460 #[inline(always)]
461 default fn is() -> bool { false }
462 #[inline(always)]
463 default fn move_(self) -> Option<$ty> where Self: Sized, $ty: Sized { None }
464 #[inline(always)]
465 default fn as_ref(&self) -> Option<&$ty> { None }
466 #[inline(always)]
467 default fn as_mut(&mut self) -> Option<&mut $ty> { None }
468 }
469
470 impl $trait_id for $ty {
471 #[inline(always)]
472 default fn is() -> bool { true }
473 #[inline(always)]
474 fn move_(self) -> Option<$ty> where Self: Sized, $ty: Sized { Some(self) }
475 #[inline(always)]
476 fn as_ref(&self) -> Option<&$ty> { Some(self) }
477 #[inline(always)]
478 fn as_mut(&mut self) -> Option<&mut $ty> { Some(self) }
479 }
480 };
481 (@trait $trait_id:ident ($($bounds:tt)*) ($default_ty:ty)) => {
482 constrain! { @items
483 trait $trait_id {
484 type Out: ?Sized + $($bounds)*;
485
486 fn is() -> bool;
487 fn move_(self) -> Option<Self::Out> where Self: Sized, Self::Out: Sized;
488 fn as_ref(&self) -> Option<&Self::Out>;
489 fn as_mut(&mut self) -> Option<&mut Self::Out>;
490 }
491
492 impl<T: ?Sized + $($bounds)*> $trait_id for T {
493 type Out = T;
494
495 #[inline(always)]
496 fn is() -> bool { true }
497 #[inline(always)]
498 fn move_(self) -> Option<Self::Out> where Self: Sized, Self::Out: Sized { Some(self) }
499 #[inline(always)]
500 fn as_ref(&self) -> Option<&Self::Out> { Some(self) }
501 #[inline(always)]
502 fn as_mut(&mut self) -> Option<&mut Self::Out> { Some(self) }
503 }
504 }
505
506 impl<T: ?Sized> $trait_id for T {
507 default type Out = $default_ty;
508
509 #[inline(always)]
510 default fn is() -> bool { false }
511 #[inline(always)]
512 default fn move_(self) -> Option<Self::Out> where Self: Sized, Self::Out: Sized { None }
513 #[inline(always)]
514 default fn as_ref(&self) -> Option<&Self::Out> { None }
515 #[inline(always)]
516 default fn as_mut(&mut self) -> Option<&mut Self::Out> { None }
517 }
518 };
519 (@trait $trait_id:ident ($($bounds:tt)*)) => {
520 constrain! { @items
521 trait $trait_id {
522 fn is() -> bool;
523 }
524
525 impl<T: ?Sized + $($bounds)*> $trait_id for T {
526 #[inline(always)]
527 fn is() -> bool { true }
528 }
529 }
530
531 impl<T: ?Sized> $trait_id for T {
532 #[inline(always)]
533 default fn is() -> bool { false }
534 }
535 };
536 (@items $($i:item)*) => { $($i)* };
537 (@expr $i:expr) => { $i };
538}
539
540#[cfg(test)]
541mod test {
542 #[test]
543 fn by_type() {
544 fn is_default<T: ?Sized>() -> bool {
545 specialize! {
546 trait fn IsDefault::is_default() -> bool;
547
548 match impl[T: ?Sized] for T {
549 where [T: Default + Default, T: Default] => true,
551 where [T: Default + Copy] => true,
552 where [T: Default + Copy + ::std::ops::Deref, T::Target: Copy] => true,
553 _ => false,
554 }
555 }
556
557 T::is_default()
558 }
559
560 assert_eq!(true, is_default::<()>());
561 assert_eq!(false, is_default::<[()]>());
562 assert_eq!(false, is_default::<&'static ()>());
563 }
564
565 #[test]
566 fn by_value() {
567 fn is_default<T: ?Sized>(t: &T) -> bool {
568 specialize! {
569 trait fn IsDefault::is_default(&self, true_: bool) -> bool;
570
571 match impl[T: ?Sized] for T {
572 where [T: Default] => true && true_,
573 where [T: Default + PartialEq] => *self == <Self as Default>::default() && true_,
574 _ => false && true_,
575 }
576 }
577
578 t.is_default(true)
579 }
580
581 assert_eq!(true, is_default(&()));
582 assert_eq!(true, is_default(&0u8));
583 assert_eq!(false, is_default(&1u8));
584 assert_eq!(false, is_default(&[()][..]));
585 }
586
587 #[test]
588 fn fn_bounds() {
589 use std::io::{self, Write, sink};
590 use std::fmt::Display;
591
592 fn write_test<T: ?Sized>(v: &T) -> io::Result<()> {
593 specialize! {
594 trait fn WriteTest::write_test[W: Write](&self, mut w: W) -> io::Result<()>;
595
596 match impl[T: ?Sized] for T {
597 where [T: Display] => writeln!(w, "{}", self),
598 _ => Err(io::Error::new(io::ErrorKind::Other, "unimplemented")),
599 }
600 }
601
602 v.write_test(sink())
603 }
604
605 assert!(write_test(&0u8).is_ok());
606 assert!(write_test(&()).is_err());
607 }
608
609 #[test]
610 fn constrain_ref() {
611 use std::fmt::Display;
612
613 fn is_display<T: ?Sized>(t: &T) -> bool {
614 if let Some(display) = constrain!(ref [t: Display] = u8) {
615 println!("{}", display);
616 true
617 } else {
618 false
619 }
620 }
621
622 assert_eq!(is_display(&()), false);
623 assert_eq!(is_display(&0u32), true);
624 }
625
626 #[test]
627 fn constrain_mut() {
628 use std::io::{Write, Stdout, sink};
629
630 fn try_write<T: ?Sized>(t: &mut T) -> bool {
631 if let Some(write) = constrain!(ref mut [t: Write] = Stdout) {
632 writeln!(write, "hello!").is_ok()
633 } else {
634 false
635 }
636 }
637
638 assert_eq!(try_write(&mut ()), false);
639 assert_eq!(try_write(&mut sink()), true);
640 }
641
642 #[test]
643 fn constrain_eq() {
644 fn is_bool<T: ?Sized>() -> bool {
645 constrain!(type T as bool)
646 }
647
648 assert!(is_bool::<bool>());
649 assert!(!is_bool::<&bool>());
650 assert!(!is_bool::<u8>());
651 assert!(constrain!(type bool as bool));
652 }
653
654 #[test]
655 fn constrain_eq_value() {
656 fn is_bool<T: ?Sized>(v: &T) -> bool {
657 constrain!(ref v as bool).is_some()
658 }
659
660 assert!(is_bool(&true));
661 assert!(!is_bool(&0u8));
662 }
663}