1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
pub mod segment;
pub mod item;

use self::segment::Segment;
use self::item::{Item, ItemState};
use self::item::relation::Relation;

use std::{slice, iter};
use std::borrow::Cow;
use std::ops::BitOr;

use ::syntex_syntax::{ptr, ast};
use ::dot::{Nodes, Edges, Arrow, Style, GraphWalk, Labeller, LabelText, Id};
use ::itertools::Itertools;

#[derive(Debug, Clone)]
pub struct ListItem <'a> {
    parse: Item<'a>,
}

impl <'a> From<Item<'a>> for ListItem <'a> {
    fn from(parse: Item<'a>) -> ListItem <'a> {
        ListItem {
            parse: parse,
        }
    }
}

impl <'a> From<iter::Peekable<slice::Iter<'a, ptr::P<ast::Item>>>> for ListItem <'a> {
    fn from(list: iter::Peekable<slice::Iter<'a, ptr::P<ast::Item>>>) -> ListItem <'a> {
        ListItem::from(Item::from(list))
    }
}

impl <'a>Iterator for ListItem<'a> {
    type Item = ItemState<'a>;

    fn next(&mut self) -> Option<ItemState<'a>> {
        self.parse.by_ref().skip_while(|state| state.is_none()).next()
    }
}

impl<'a> Labeller<'a, ItemState<'a>, Segment<'a>> for ListItem<'a> {
    fn graph_id(&'a self) -> Id<'a> {
        Id::new("ml").unwrap()
    }

    fn node_id(&'a self, state: &ItemState<'a>) -> Id<'a> {
        match state.as_name() {
            Some(name) => Id::new(format!("nd{}", name)).unwrap(),
            _ => unreachable!(),
        }
    }

    fn node_shape(&'a self, _node: &ItemState<'a>) -> Option<LabelText<'a>> {
        Some(LabelText::LabelStr(Cow::from(format!("record"))))
    }

    fn node_label(&'a self, state: &ItemState<'a>) -> LabelText<'a> {
        LabelText::LabelStr(format!("{}", state).into())
    }

    fn edge_end_arrow(&'a self, ref seg: &Segment<'a>) -> Arrow {
        match (
            seg.left.as_arrow(&seg.right),
            seg.right.as_arrow(&seg.left)
        ) {
            (Relation::Association, Relation::Association) => Arrow::none(),
            (edge_left, _) => Arrow::from_arrow(edge_left.as_style()),
        }
    }

    fn edge_style(&'a self, ref seg: &Segment<'a>) -> Style {
        if seg.left.is_realization(&seg.right).bitor(seg.left.is_dependency(&seg.right)) {
            Style::Dashed
        } else {
            Style::None
        }
    }
}

impl<'a> GraphWalk<'a, ItemState<'a>, Segment<'a>> for ListItem<'a> {
    fn nodes(&'a self) -> Nodes<'a, ItemState<'a>> {
        Cow::Owned(self.clone().collect::<Vec<ItemState<'a>>>())
    }
    
    fn edges(&'a self) -> Edges<'a, Segment<'a>> {
        let items = self.clone().collect::<Vec<ItemState<'a>>>();

        Cow::Owned(items.iter()
                        .map(|item| items.iter()
                                         .filter(|rhs| item.ne(rhs))
                                         .filter(|rhs| item.is_relation(rhs))
                                         .map(|rhs| Segment::from((item.clone(), rhs.clone())))
                                         .collect::<Vec<Segment<'a>>>())
                        .collect::<Vec<Vec<Segment<'a>>>>()
                        .concat()
                        .into_iter()
                        .unique()
                        .collect::<Vec<Segment<'a>>>())
    }

    fn source(&self, seg: &Segment<'a>) -> ItemState<'a> { seg.left.clone() }

    fn target(&self, seg: &Segment<'a>) -> ItemState<'a> { seg.right.clone() }
}