// Copyright 2016 Mozilla // // Licensed under the Apache License, Version 2.0 (the "License"); you may not use // this file except in compliance with the License. You may obtain a copy of the // License at http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. //! This module defines core types that support the transaction processor. use std::collections::BTreeMap; use std::fmt; use symbols::{ Keyword, PlainSymbol, }; use types::{ Value, ValueAndSpan, }; /// A tempid, either an external tempid given in a transaction (usually as an `Value::Text`), /// or an internal tempid allocated by Mentat itself. #[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub enum TempId { External(String), Internal(i64), } impl TempId { pub fn into_external(self) -> Option { match self { TempId::External(s) => Some(s), TempId::Internal(_) => None, } } } impl fmt::Display for TempId { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self { &TempId::External(ref s) => write!(f, "{}", s), &TempId::Internal(x) => write!(f, "", x), } } } #[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub enum Entid { Entid(i64), Ident(Keyword), } impl Entid { pub fn unreversed(&self) -> Option { match self { &Entid::Entid(_) => None, &Entid::Ident(ref a) => a.unreversed().map(Entid::Ident), } } } #[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub struct LookupRef { pub a: Entid, // In theory we could allow nested lookup-refs. In practice this would require us to process // lookup-refs in multiple phases, like how we resolve tempids, which isn't worth the effort. pub v: Value, // An atom. } /// A "transaction function" that exposes some value determined by the current transaction. The /// prototypical example is the current transaction ID, `(transaction-tx)`. /// /// A natural next step might be to expose the current transaction instant `(transaction-instant)`, /// but that's more difficult: the transaction itself can set the transaction instant (with some /// restrictions), so the transaction function must be late-binding. Right now, that's difficult to /// arrange in the transactor. /// /// In the future, we might accept arguments; for example, perhaps we might expose `(ancestor /// (transaction-tx) n)` to find the n-th ancestor of the current transaction. If we do accept /// arguments, then the special case of `(lookup-ref a v)` should be handled as part of the /// generalization. #[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub struct TxFunction { pub op: PlainSymbol, } pub type MapNotation = BTreeMap; #[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub enum AtomOrLookupRefOrVectorOrMapNotation { Atom(ValueAndSpan), LookupRef(LookupRef), TxFunction(TxFunction), Vector(Vec), MapNotation(MapNotation), } #[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub enum EntidOrLookupRefOrTempId { Entid(Entid), LookupRef(LookupRef), TxFunction(TxFunction), TempId(TempId), } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub enum OpType { Add, Retract, } #[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub enum Entity { // Like [:db/add|:db/retract e a v]. AddOrRetract { op: OpType, e: EntidOrLookupRefOrTempId, a: Entid, v: AtomOrLookupRefOrVectorOrMapNotation, }, // Like {:db/id "tempid" a1 v1 a2 v2}. MapNotation(MapNotation), }