1use crate::{DomainId, FieldName};
2use sim_kernel::{ContentId, Datum, Symbol};
3use std::fmt;
4
5pub trait ToRelationDatum {
7 fn to_datum(&self) -> Datum;
9 fn card_datum(&self) -> Datum {
11 self.to_datum()
12 }
13 fn lisp_datum(&self) -> Datum {
15 self.to_datum()
16 }
17}
18
19#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct RelationId(ContentId);
22impl RelationId {
23 pub fn of(value: &impl ToRelationDatum) -> Result<Self, sim_kernel::Error> {
25 Ok(Self(value.to_datum().content_id()?))
26 }
27 pub const fn content_id(&self) -> &ContentId {
29 &self.0
30 }
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct Cell {
36 domain: DomainId,
37 value: Option<Datum>,
38}
39impl Cell {
40 pub const fn new(domain: DomainId, value: Option<Datum>) -> Self {
42 Self { domain, value }
43 }
44 pub const fn null(domain: DomainId) -> Self {
46 Self::new(domain, None)
47 }
48 pub const fn domain(&self) -> &DomainId {
50 &self.domain
51 }
52 pub const fn value(&self) -> Option<&Datum> {
54 self.value.as_ref()
55 }
56}
57
58#[derive(Clone, Debug, PartialEq, Eq)]
60pub struct FieldType {
61 pub name: FieldName,
63 pub domain: DomainId,
65 pub nullable: bool,
67}
68#[derive(Clone, Debug, PartialEq, Eq)]
70pub struct RowType(Vec<FieldType>);
71#[derive(Clone, Debug, PartialEq, Eq)]
73pub enum RowError {
74 DuplicateField(FieldName),
76 Arity {
78 expected: usize,
80 actual: usize,
82 },
83 Domain {
85 index: usize,
87 },
88 Null {
90 index: usize,
92 },
93}
94impl fmt::Display for RowError {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 write!(f, "{self:?}")
97 }
98}
99impl std::error::Error for RowError {}
100impl RowType {
101 pub fn new(fields: impl IntoIterator<Item = FieldType>) -> Result<Self, RowError> {
103 let fields: Vec<_> = fields.into_iter().collect();
104 for (i, v) in fields.iter().enumerate() {
105 if fields[..i].iter().any(|x| x.name == v.name) {
106 return Err(RowError::DuplicateField(v.name.clone()));
107 }
108 }
109 Ok(Self(fields))
110 }
111 pub fn fields(&self) -> &[FieldType] {
113 &self.0
114 }
115}
116#[derive(Clone, Debug, PartialEq, Eq)]
118pub struct Row {
119 row_type: RowType,
120 cells: Vec<Cell>,
121}
122impl Row {
123 pub fn new(row_type: RowType, cells: impl IntoIterator<Item = Cell>) -> Result<Self, RowError> {
125 let cells: Vec<_> = cells.into_iter().collect();
126 if cells.len() != row_type.0.len() {
127 return Err(RowError::Arity {
128 expected: row_type.0.len(),
129 actual: cells.len(),
130 });
131 }
132 for (i, (field, cell)) in row_type.0.iter().zip(&cells).enumerate() {
133 if field.domain != cell.domain {
134 return Err(RowError::Domain { index: i });
135 }
136 if !field.nullable && cell.value.is_none() {
137 return Err(RowError::Null { index: i });
138 }
139 }
140 Ok(Self { row_type, cells })
141 }
142 pub const fn row_type(&self) -> &RowType {
144 &self.row_type
145 }
146 pub fn cells(&self) -> &[Cell] {
148 &self.cells
149 }
150}
151
152impl ToRelationDatum for Cell {
153 fn to_datum(&self) -> Datum {
154 Datum::Node {
155 tag: Symbol::qualified("relation", "cell"),
156 fields: vec![
157 (
158 Symbol::new("domain"),
159 Datum::Symbol(self.domain.symbol().clone()),
160 ),
161 (
162 Symbol::new("value"),
163 self.value.clone().unwrap_or(Datum::Nil),
164 ),
165 ],
166 }
167 }
168}
169impl ToRelationDatum for FieldType {
170 fn to_datum(&self) -> Datum {
171 Datum::Node {
172 tag: Symbol::qualified("relation", "field-type"),
173 fields: vec![
174 (
175 Symbol::new("name"),
176 Datum::Symbol(self.name.symbol().clone()),
177 ),
178 (
179 Symbol::new("domain"),
180 Datum::Symbol(self.domain.symbol().clone()),
181 ),
182 (Symbol::new("nullable"), Datum::Bool(self.nullable)),
183 ],
184 }
185 }
186}
187impl ToRelationDatum for RowType {
188 fn to_datum(&self) -> Datum {
189 Datum::Node {
190 tag: Symbol::qualified("relation", "row-type"),
191 fields: vec![(
192 Symbol::new("fields"),
193 Datum::Vector(self.0.iter().map(ToRelationDatum::to_datum).collect()),
194 )],
195 }
196 }
197}
198impl ToRelationDatum for Row {
199 fn to_datum(&self) -> Datum {
200 Datum::Node {
201 tag: Symbol::qualified("relation", "row"),
202 fields: vec![
203 (Symbol::new("type"), self.row_type.to_datum()),
204 (
205 Symbol::new("cells"),
206 Datum::Vector(self.cells.iter().map(ToRelationDatum::to_datum).collect()),
207 ),
208 ],
209 }
210 }
211}