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
use std::convert::TryFrom;

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ContainerType {
	Graph,
	Id,
	Index,
	Language,
	List,
	Set,
	Type
}

impl<'a> TryFrom<&'a str> for ContainerType {
	type Error = &'a str;

	fn try_from(str: &'a str) -> Result<ContainerType, &'a str> {
		use ContainerType::*;
		match str {
			"@graph" => Ok(Graph),
			"@id" => Ok(Id),
			"@index" => Ok(Index),
			"@language" => Ok(Language),
			"@list" => Ok(List),
			"@set" => Ok(Set),
			"@type" => Ok(Type),
			_ => Err(str)
		}
	}
}

#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Container(Vec<ContainerType>);

impl Container {
	pub fn new() -> Container {
		Container(Vec::new())
	}

	pub fn len(&self) -> usize {
		self.0.len()
	}

	pub fn is_empty(&self) -> bool {
		self.0.is_empty()
	}

	pub fn contains(&self, c: ContainerType) -> bool {
		self.0.contains(&c)
	}

	pub fn add(&mut self, c: ContainerType) -> bool {
		if self.is_empty() {
			self.0.push(c);
			true
		} else if self.contains(c) {
			true
		} else {
			use ContainerType::*;
			let valid = if self.len() == 1 {
				match (self.0.first().unwrap(), c) {
					(Set, Index) => true,
					(Set, Graph) => true,
					(Set, Id) => true,
					(Set, Type) => true,
					(Set, Language) => true,
					(Index, Set) => true,
					(Graph, Set) => true,
					(Id, Set) => true,
					(Type, Set) => true,
					(Language, Set) => true,
					//
					(Graph, Id) => true,
					(Id, Graph) => true,
					(Graph, Index) => true,
					(Index, Graph) => true,
					//
					_ => false
				}
			} else if self.len() == 2 {
				match c {
					Set if self.contains(Graph) && (self.contains(Id) || self.contains(Index)) => true,
					Graph if self.contains(Set) && (self.contains(Id) || self.contains(Index)) => true,
					Id if self.contains(Graph) && self.contains(Set) => true,
					Index if self.contains(Graph) && self.contains(Set) => true,
					_ => false
				}
			} else {
				false
			};

			if valid {
				self.0.push(c);
				true
			} else {
				false
			}
		}
	}
}