Skip to main content

edn/
entities.rs

1// Copyright 2016 Mozilla
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4// this file except in compliance with the License. You may obtain a copy of the
5// License at http://www.apache.org/licenses/LICENSE-2.0
6// Unless required by applicable law or agreed to in writing, software distributed
7// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
8// CONDITIONS OF ANY KIND, either express or implied. See the License for the
9// specific language governing permissions and limitations under the License.
10
11//! This module defines core types that support the transaction processor.
12
13use std::collections::BTreeMap;
14use std::fmt;
15
16use crate::value_rc::ValueRc;
17
18use crate::symbols::{Keyword, PlainSymbol};
19
20use crate::types::ValueAndSpan;
21
22/// `EntityPlace` and `ValuePlace` embed values, either directly (i.e., `ValuePlace::Atom`) or
23/// indirectly (i.e., `EntityPlace::LookupRef`).  In order to maintain the graph of `Into` and
24/// `From` relations, we need to ensure that `{Value,Entity}Place` can't match as a potential value.
25/// (If it does, the `impl Into<T> for T` default conflicts.) This marker trait allows to mark
26/// acceptable values, thereby removing `{Entity,Value}Place` from consideration.
27pub trait TransactableValueMarker {}
28
29/// `ValueAndSpan` is the value type coming out of the entity parser.
30impl TransactableValueMarker for ValueAndSpan {}
31
32/// A tempid, either an external tempid given in a transaction (usually as an `Value::Text`),
33/// or an internal tempid allocated by Mentat itself.
34#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
35pub enum TempId {
36    External(String),
37    Internal(i64),
38}
39
40impl TempId {
41    pub fn into_external(self) -> Option<String> {
42        match self {
43            TempId::External(s) => Some(s),
44            TempId::Internal(_) => None,
45        }
46    }
47}
48
49impl fmt::Display for TempId {
50    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
51        match self {
52            TempId::External(s) => write!(f, "{}", s),
53            &TempId::Internal(x) => write!(f, "<tempid {}>", x),
54        }
55    }
56}
57
58#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
59pub enum EntidOrIdent {
60    Entid(i64),
61    Ident(Keyword),
62}
63
64impl From<i64> for EntidOrIdent {
65    fn from(v: i64) -> Self {
66        EntidOrIdent::Entid(v)
67    }
68}
69
70impl From<Keyword> for EntidOrIdent {
71    fn from(v: Keyword) -> Self {
72        EntidOrIdent::Ident(v)
73    }
74}
75
76impl EntidOrIdent {
77    pub fn unreversed(&self) -> Option<EntidOrIdent> {
78        match self {
79            &EntidOrIdent::Entid(_) => None,
80            EntidOrIdent::Ident(a) => a.unreversed().map(EntidOrIdent::Ident),
81        }
82    }
83}
84
85#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
86pub struct LookupRef<V> {
87    pub a: AttributePlace,
88    // In theory we could allow nested lookup-refs.  In practice this would require us to process
89    // lookup-refs in multiple phases, like how we resolve tempids, which isn't worth the effort.
90    pub v: V, // An atom.
91}
92
93/// A "transaction function" that exposes some value determined by the current transaction.  The
94/// prototypical example is the current transaction ID, `(transaction-tx)`.
95///
96/// A natural next step might be to expose the current transaction instant `(transaction-instant)`,
97/// but that's more difficult: the transaction itself can set the transaction instant (with some
98/// restrictions), so the transaction function must be late-binding.  Right now, that's difficult to
99/// arrange in the transactor.
100///
101/// In the future, we might accept arguments; for example, perhaps we might expose `(ancestor
102/// (transaction-tx) n)` to find the n-th ancestor of the current transaction.  If we do accept
103/// arguments, then the special case of `(lookup-ref a v)` should be handled as part of the
104/// generalization.
105#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
106pub struct TxFunction {
107    pub op: PlainSymbol,
108}
109
110pub type MapNotation<V> = BTreeMap<EntidOrIdent, ValuePlace<V>>;
111
112#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
113pub enum ValuePlace<V> {
114    // We never know at parse-time whether an integer or ident is really an entid, but we will often
115    // know when building entities programmatically.
116    Entid(EntidOrIdent),
117    // We never know at parse-time whether a string is really a tempid, but we will often know when
118    // building entities programmatically.
119    TempId(ValueRc<TempId>),
120    LookupRef(LookupRef<V>),
121    TxFunction(TxFunction),
122    Vector(Vec<ValuePlace<V>>),
123    Atom(V),
124    MapNotation(MapNotation<V>),
125}
126
127impl<V: TransactableValueMarker> From<EntidOrIdent> for ValuePlace<V> {
128    fn from(v: EntidOrIdent) -> Self {
129        ValuePlace::Entid(v)
130    }
131}
132
133impl<V: TransactableValueMarker> From<TempId> for ValuePlace<V> {
134    fn from(v: TempId) -> Self {
135        ValuePlace::TempId(v.into())
136    }
137}
138
139impl<V: TransactableValueMarker> From<ValueRc<TempId>> for ValuePlace<V> {
140    fn from(v: ValueRc<TempId>) -> Self {
141        ValuePlace::TempId(v)
142    }
143}
144
145impl<V: TransactableValueMarker> From<LookupRef<V>> for ValuePlace<V> {
146    fn from(v: LookupRef<V>) -> Self {
147        ValuePlace::LookupRef(v)
148    }
149}
150
151impl<V: TransactableValueMarker> From<TxFunction> for ValuePlace<V> {
152    fn from(v: TxFunction) -> Self {
153        ValuePlace::TxFunction(v)
154    }
155}
156
157impl<V: TransactableValueMarker> From<Vec<ValuePlace<V>>> for ValuePlace<V> {
158    fn from(v: Vec<ValuePlace<V>>) -> Self {
159        ValuePlace::Vector(v)
160    }
161}
162
163impl<V: TransactableValueMarker> From<V> for ValuePlace<V> {
164    fn from(v: V) -> Self {
165        ValuePlace::Atom(v)
166    }
167}
168
169impl<V: TransactableValueMarker> From<MapNotation<V>> for ValuePlace<V> {
170    fn from(v: MapNotation<V>) -> Self {
171        ValuePlace::MapNotation(v)
172    }
173}
174
175#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
176pub enum EntityPlace<V> {
177    Entid(EntidOrIdent),
178    TempId(ValueRc<TempId>),
179    LookupRef(LookupRef<V>),
180    TxFunction(TxFunction),
181}
182
183impl<V, E: Into<EntidOrIdent>> From<E> for EntityPlace<V> {
184    fn from(v: E) -> Self {
185        EntityPlace::Entid(v.into())
186    }
187}
188
189impl<V: TransactableValueMarker> From<TempId> for EntityPlace<V> {
190    fn from(v: TempId) -> Self {
191        EntityPlace::TempId(v.into())
192    }
193}
194
195impl<V: TransactableValueMarker> From<ValueRc<TempId>> for EntityPlace<V> {
196    fn from(v: ValueRc<TempId>) -> Self {
197        EntityPlace::TempId(v)
198    }
199}
200
201impl<V: TransactableValueMarker> From<LookupRef<V>> for EntityPlace<V> {
202    fn from(v: LookupRef<V>) -> Self {
203        EntityPlace::LookupRef(v)
204    }
205}
206
207impl<V: TransactableValueMarker> From<TxFunction> for EntityPlace<V> {
208    fn from(v: TxFunction) -> Self {
209        EntityPlace::TxFunction(v)
210    }
211}
212
213#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
214pub enum AttributePlace {
215    Entid(EntidOrIdent),
216}
217
218impl<A: Into<EntidOrIdent>> From<A> for AttributePlace {
219    fn from(v: A) -> Self {
220        AttributePlace::Entid(v.into())
221    }
222}
223
224#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
225pub enum OpType {
226    Add,
227    Retract,
228}
229
230#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
231pub enum Entity<V> {
232    // Like [:db/add|:db/retract e a v].
233    AddOrRetract {
234        op: OpType,
235        e: EntityPlace<V>,
236        a: AttributePlace,
237        v: ValuePlace<V>,
238    },
239    // Like {:db/id "tempid" a1 v1 a2 v2}.
240    MapNotation(MapNotation<V>),
241}