Skip to content

Instantly share code, notes, and snippets.

@zakarumych
Created March 30, 2016 15:03
Show Gist options
  • Select an option

  • Save zakarumych/f7f1a17b002c244aaa1148b8d668dfb3 to your computer and use it in GitHub Desktop.

Select an option

Save zakarumych/f7f1a17b002c244aaa1148b8d668dfb3 to your computer and use it in GitHub Desktop.
#![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