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
use std::{any::TypeId, collections::HashMap, fmt::Debug};
use crate::schema::{
collection::{self, Collection},
view, Schema, Serialized, View,
};
#[derive(Default, Debug)]
pub struct Schematic {
collections: HashMap<TypeId, collection::Id>,
views: HashMap<TypeId, Box<dyn view::Serialized>>,
views_by_name: HashMap<String, TypeId>,
views_by_collection: HashMap<collection::Id, Vec<TypeId>>,
}
impl Schematic {
pub fn define_collection<C: Collection + 'static>(&mut self) {
self.collections.insert(TypeId::of::<C>(), C::id());
C::define_views(self)
}
pub fn define_view<V: View + 'static>(&mut self, view: V) {
let name = view.name();
let collection = view.collection();
self.views.insert(TypeId::of::<V>(), Box::new(view));
self.views_by_name
.insert(name.to_string(), TypeId::of::<V>());
let views = self
.views_by_collection
.entry(collection)
.or_insert_with(Vec::new);
views.push(TypeId::of::<V>());
}
#[must_use]
pub fn contains<C: Collection + 'static>(&self) -> bool {
self.collections.contains_key(&TypeId::of::<C>())
}
#[must_use]
pub fn view_by_name(&self, name: &str) -> Option<&'_ dyn view::Serialized> {
self.views_by_name
.get(name)
.and_then(|type_id| self.views.get(type_id))
.map(AsRef::as_ref)
}
#[must_use]
pub fn view<V: View + 'static>(&self) -> Option<&'_ dyn view::Serialized> {
self.views.get(&TypeId::of::<V>()).map(AsRef::as_ref)
}
pub fn views(&self) -> impl Iterator<Item = &'_ dyn view::Serialized> {
self.views.values().map(AsRef::as_ref)
}
#[must_use]
pub fn views_in_collection(
&self,
collection: &collection::Id,
) -> Option<Vec<&'_ dyn view::Serialized>> {
self.views_by_collection.get(collection).map(|view_ids| {
view_ids
.iter()
.filter_map(|id| self.views.get(id).map(AsRef::as_ref))
.collect()
})
}
}
impl<T> Schema for T
where
T: Collection + 'static,
{
fn define_collections(collections: &mut Schematic) {
collections.define_collection::<Self>();
}
}
#[test]
fn schema_tests() {
use crate::test_util::{Basic, BasicCount, BasicSchema};
let mut schema = Schematic::default();
BasicSchema::define_collections(&mut schema);
assert_eq!(schema.collections.len(), 1);
assert_eq!(schema.collections[&TypeId::of::<Basic>()], Basic::id());
assert_eq!(schema.views.len(), 3);
assert_eq!(
schema.views[&TypeId::of::<BasicCount>()].name(),
View::name(&BasicCount)
);
}