Created
March 30, 2016 15:03
-
-
Save zakarumych/f7f1a17b002c244aaa1148b8d668dfb3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #![feature(unsize)] | |
| use std::iter::Iterator; | |
| use std::marker::Unsize; | |
| use std::fmt::{self, Debug, Display}; | |
| trait Heterogeneous<I: ?Sized> { | |
| fn next(self: Box<Self>) -> Option<(Box<I>, Box<Heterogeneous<I>>)>; | |
| fn count(&self) -> usize; | |
| } | |
| trait HeterogeneousRef<I: ?Sized> { | |
| fn next<'a>(&'a self) -> Option<(&'a I, &'a HeterogeneousRef<I>)>; | |
| fn count(&self) -> usize; | |
| } | |
| trait IterAs: 'static + Sized { | |
| fn iter_as<I: ?Sized>(self) -> HeterogeneousIterator<I> where Self: Heterogeneous<I> { | |
| let hiter: Box<Heterogeneous<I>> = Box::new(self); | |
| HeterogeneousIterator { hiter: Some(hiter) } | |
| } | |
| } | |
| trait IterRefAs: 'static + Sized { | |
| fn iter_ref_as<'a, I: ?Sized>(&'a self) -> HeterogeneousRefIterator<'a, I> where Self: HeterogeneousRef<I> { | |
| HeterogeneousRefIterator { hiter: Some(self) } | |
| } | |
| } | |
| /////////////////////////////////// | |
| // Iterator | |
| struct HeterogeneousIterator<I: ?Sized> { | |
| hiter: Option<Box<Heterogeneous<I>>> | |
| } | |
| impl<I: ?Sized> Iterator for HeterogeneousIterator<I> { | |
| type Item = Box<I>; | |
| fn next(&mut self) -> Option<Box<I>> { | |
| if let Some(hiter) = self.hiter.take() { | |
| if let Some((item, next)) = hiter.next() { | |
| self.hiter = Some(next); | |
| Some(item) | |
| } else { | |
| self.hiter = None; | |
| None | |
| } | |
| } else { | |
| None | |
| } | |
| } | |
| fn size_hint(&self) -> (usize, Option<usize>) { | |
| if let Some(ref hiter) = self.hiter { | |
| (hiter.count(), Some(hiter.count())) | |
| } else { | |
| (0, Some(0)) | |
| } | |
| } | |
| fn count(self) -> usize { | |
| if let Some(ref hiter) = self.hiter { | |
| hiter.count() | |
| } else { | |
| 0 | |
| } | |
| } | |
| } | |
| /////////////////////////////////// | |
| // Iterator ref | |
| struct HeterogeneousRefIterator<'a, I: 'a + ?Sized> { | |
| hiter: Option<&'a HeterogeneousRef<I>> | |
| } | |
| impl<'a, I: ?Sized> Iterator for HeterogeneousRefIterator<'a, I> { | |
| type Item = &'a I; | |
| fn next(&mut self) -> Option<&'a I> { | |
| if let Some(hiter) = self.hiter.take() { | |
| if let Some((item, next)) = hiter.next() { | |
| self.hiter = Some(next); | |
| Some(item) | |
| } else { | |
| self.hiter = None; | |
| None | |
| } | |
| } else { | |
| None | |
| } | |
| } | |
| fn size_hint(&self) -> (usize, Option<usize>) { | |
| if let Some(ref hiter) = self.hiter { | |
| (hiter.count(), Some(hiter.count())) | |
| } else { | |
| (0, Some(0)) | |
| } | |
| } | |
| fn count(self) -> usize { | |
| if let Some(hiter) = self.hiter { | |
| hiter.count() | |
| } else { | |
| 0 | |
| } | |
| } | |
| } | |
| /////////////////////////////////// | |
| // LIST | |
| struct ListEnd; | |
| impl<I: ?Sized> Heterogeneous<I> for ListEnd { | |
| fn next(self: Box<Self>) -> Option<(Box<I>, Box<Heterogeneous<I>>)> { None } | |
| fn count(&self) -> usize { 0 } | |
| } | |
| impl<I: ?Sized> HeterogeneousRef<I> for ListEnd { | |
| fn next<'a>(&'a self) -> Option<(&'a I, &'a HeterogeneousRef<I>)> { None } | |
| fn count(&self) -> usize { 0 } | |
| } | |
| impl IterAs for ListEnd {} | |
| impl IterRefAs for ListEnd {} | |
| struct ListNode<H, T> { | |
| head: H, | |
| tail: T, | |
| } | |
| impl<H: 'static, T: 'static> IterAs for ListNode<H, T> {} | |
| impl<H: 'static, T: 'static> IterRefAs for ListNode<H, T> {} | |
| impl<H, T> ListNode<H, T> { | |
| fn new(head: H, tail: T) -> Self { | |
| ListNode { head: head, tail: tail } | |
| } | |
| fn deconstruct(self) -> (H, T) { | |
| let ListNode{ head, tail } = self; | |
| (head, tail) | |
| } | |
| } | |
| impl<I: ?Sized, H: Unsize<I>, T: 'static + Heterogeneous<I>> Heterogeneous<I> for ListNode<H, T> { | |
| fn next(self: Box<Self>) -> Option<(Box<I>, Box<Heterogeneous<I>>)> { | |
| let (head, tail) = self.deconstruct(); | |
| Some((Box::<H>::new(head), Box::new(tail))) | |
| } | |
| fn count(&self) -> usize { 1 + self.tail.count() } | |
| } | |
| impl<I: ?Sized, H: Unsize<I>, T: 'static + HeterogeneousRef<I>> HeterogeneousRef<I> for ListNode<H, T> { | |
| fn next<'a>(&'a self) -> Option<(&'a I, &'a HeterogeneousRef<I>)> { | |
| Some((&self.head, &self.tail)) | |
| } | |
| fn count(&self) -> usize { 1 + self.tail.count() } | |
| } | |
| macro_rules! hlist { | |
| () => { ListEnd }; | |
| ($head:expr $(, $tail:expr )*) => { | |
| ListNode::new($head, hlist!($($tail),*)) | |
| }; | |
| } | |
| #[derive(Debug)] | |
| struct A; | |
| impl Display for A { fn fmt(&self, fmt: &mut fmt::Formatter ) -> Result<(), fmt::Error> { Debug::fmt(self, fmt) } } | |
| fn main() { | |
| let list = hlist![1, "X", A]; | |
| for i in list.iter_ref_as::<Debug>() { | |
| println!("Debug: {:?}", i); | |
| } | |
| for i in list.iter_ref_as::<Display>() { | |
| println!("Display: {}", i); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment