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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
use std::{fmt::Debug, hash::Hash};
use crate::{db::StatementRow, schema::datum::Datum, DBResult};
use super::datum::{BorrowedDatum, OwnedDatum, OwnedDatumList};
/// Integral identifier for an entity.
pub trait EntityID:
'static
+ PartialEq
+ Hash
+ PartialOrd
+ Debug
+ Copy
+ OwnedDatum<RefData<'static> = Self>
+ BorrowedDatum<'static, Self>
{
/// The entity that this ID is representing.
type Entity: Entity<ID = Self>;
/// Construct from a raw integer.
///
/// Do not use this unless you are _very_ certain it is what you want.
fn from_raw(id: i64) -> Self;
/// Produces a raw integer from an ID. Of dubious use.
fn into_raw(self) -> i64;
}
// ----------------------------------------------------------------------
// EntityPart and related types
// ----------------------------------------------------------------------
/// A single data field in an Entity, automatically declared and derived as part of `#[derive(Entity)]`.
pub trait EntityPart: Default + Clone + 'static {
/// The type of the data field.
type Datum: OwnedDatum;
/// The type of the struct this field is a member of.
type Entity: Entity;
/// String representing the field name.
fn part_name() -> &'static str;
/// Whether this field has a `#[unique]` attribute or not.
fn unique() -> bool;
/// Documentation comment for this field.
fn desc() -> Option<&'static str>;
/// Accessor function: given an instance of the outer struct, return this field's value in that instance.
fn get_datum(from: &Self::Entity) -> &Self::Datum;
}
/// Visitor for traversing all [`EntityPart`]s in an [`Entity`] or [`EntityPartList`].
pub trait EntityPartVisitor {
/// The [`Entity`] that this visitor will traverse over the parts of.
type Entity: Entity;
/// Visit a part, with no instance information.
fn visit<EP: EntityPart<Entity = Self::Entity>>(&mut self) {}
/// Visit a part, with a datum reference.
fn visit_datum<EP: EntityPart<Entity = Self::Entity>>(
&mut self,
_datum: &EP::Datum,
) -> DBResult<()> {
Ok(())
}
/// Visit a part, with a mutable datum reference.
fn visit_datum_mut<EP: EntityPart<Entity = Self::Entity>>(&mut self, _datum: &mut EP::Datum) {}
}
/// List of EntityParts.
pub trait EntityPartList: 'static {
/// The [`Entity`] that this list represents the parts of.
type Entity: Entity;
/// An [`OwnedDatumList`] type that matches this part list, formed as the `EntityPart::Datum`s of
/// each `EntityPart` in this list.
type DatumList: OwnedDatumList;
// + DatumList<ListTail = <Self::ListTail as EntityPartList>::DatumList>;
/// The first element of this list. If this list is empty, this will be a generic marker type
/// with poisoned values to be easily visible if processed.
type ListHead: EntityPart<
Entity = Self::Entity,
Datum = <Self::DatumList as OwnedDatumList>::ListHead,
>;
/// An [`EntityPartList`] that represents all but the first element of this list.
type ListTail: EntityPartList<
Entity = Self::Entity,
DatumList = <Self::DatumList as OwnedDatumList>::ListTail,
>;
/// Whether the current list is empty. Should be used to control recursion if iterating across
/// the list.
const IS_EMPTY: bool = false;
/// Construct an instance of `Self::DatumList` from a table row.
fn build_datum_list(stmt: &mut StatementRow) -> DBResult<Self::DatumList>;
/// Construct an instance of `Self::DatumList::RefList` from a table row.
fn build_datum_ref_list<'l, 'm>(
stmt: &'l mut StatementRow,
) -> DBResult<<Self::DatumList as OwnedDatumList>::RefList<'m>>
where
'l: 'm;
/// Accept a visitor to iterate across each part in the list, with no datum instances.
fn accept_part_visitor(_: &mut impl EntityPartVisitor<Entity = Self::Entity>);
/// Accept a visitor to iterate across each part in the list, with datum instances provided by
/// a `Self::DatumList` instance.
fn accept_part_visitor_ref(
datum_list: &Self::DatumList,
_: &mut impl EntityPartVisitor<Entity = Self::Entity>,
) -> DBResult<()>;
}
// trait implementations for EntityPartList
mod part_list;
/// A sentinel type representing a zero-length [`EntityPartList`].
pub use part_list::EmptyList;
// ----------------------------------------------------------------------
// Entity and related types
// ----------------------------------------------------------------------
/// Helper for accessing the canonical [`BorrowedDatumList`](super::datum::BorrowedDatumList) type that references an entity's data.
pub type EntityRefDatumList<'l, E> =
<<<E as Entity>::Parts as EntityPartList>::DatumList as OwnedDatumList>::RefList<'l>;
/// A reference 'shell' of an [`Entity`].
pub trait EntityRef<'a>: Clone + Copy {
/// The entity this type represents the data of.
type Entity: Entity;
/// Convert this 'shell' into an owned type.
fn as_entity(&self) -> Self::Entity;
/// Convert this reference type to a [`BorrowedDatumList`](super::datum::BorrowedDatumList) for type-blind data access.
fn as_borrowed_list<'r>(&self) -> EntityRefDatumList<'r, Self::Entity>
where
'a: 'r;
/// Build an entity reference type from a list of borrowed datums.
fn from_borrowed_list<'r>(l: EntityRefDatumList<'r, Self::Entity>) -> Self
where
'r: 'a;
}
/// A single database entity, aka an object type that gets its own table.
pub trait Entity: 'static + std::fmt::Debug {
/// A list of all the [`EntityPart`]s that make up the fields of the struct.
type Parts: EntityPartList<Entity = Self>;
/// A list of the [`EntityPart`]s that make up the list of access keys for the entity. Can be an
/// [`EmptyList`] if no keys are defined.
type Keys: EntityPartList<Entity = Self>;
/// The corresponding [`EntityID`] type for this Entity.
type ID: EntityID<Entity = Self>;
/// The [`EntityPart`] type for `Self::ID`.
type IDPart: EntityPart<Datum = Self::ID, Entity = Self>;
/// A reference version of the current entity, can be cheaply copied.
type ERef<'a>: EntityRef<'a, Entity = Self>;
/// Create a reference 'shell' of the current entity.
fn as_ref(&self) -> Self::ERef<'_>
where
Self: Sized;
/// Construct an instance of this entity from a list of datums that matches each part, in
/// order.
fn build(values: <Self::Parts as EntityPartList>::DatumList) -> Self;
/// A static string used as the database table name for the entity.
fn entity_name() -> &'static str;
/// Accept a visitor to iterate across each part in the entity, with no datum instances.
fn accept_part_visitor(visitor: &mut impl EntityPartVisitor<Entity = Self>);
/// Accept a visitor to iterate across each part in the entity, with datum instances pulled
/// from an instance of `Self`.
fn accept_part_visitor_ref(
&self,
visitor: &mut impl EntityPartVisitor<Entity = Self>,
) -> DBResult<()>;
/// Accept a visitor to iterate across each part in the entity, with mutable datum instances
/// pulled from an instance of `Self`.
fn accept_part_visitor_mut(&mut self, _: &mut impl EntityPartVisitor<Entity = Self>);
}
/// Visitor for traversing all [`Entity`]s in a container type.
pub trait EntityVisitor {
/// Visit a particular entity.
fn visit<E: Entity>(&mut self);
}
// ----------------------------------------------------------------------
// EntityList and related types
// ----------------------------------------------------------------------
/// A list of [`Entity`] types.
pub trait EntityList {
/// The first entity in this list, or a sentinel for an empty list.
type ListHead: Entity;
/// An [`EntityList`] instance containing all entities but the first.
type ListTail: EntityList;
/// For recursion control: is this an empty list?
const IS_EMPTY: bool = false;
/// Accept a visitor to iterate across all entities in this list.
fn accept_visitor<EV: EntityVisitor>(visitor: &mut EV);
}
mod entity_list;