use self::{mvreg::MvRegValue, orarray::Uid, snapshot::ToValue};
use crate::{
CausalContext, DotStoreJoin, ExtensionType, MvReg, OrArray, OrMap,
dotstores::{DotChange, DotStore, DryJoinOutput},
either::Either,
sentinel::{KeySentinel, Sentinel, TypeSentinel, ValueSentinel, Visit},
};
use std::{fmt, hash::Hash};
pub mod mvreg;
pub mod orarray;
pub mod ormap;
pub mod snapshot;
#[cfg(any(test, feature = "arbitrary"))]
mod test_util;
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
pub struct NoExtensionTypes;
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
pub enum NoExtensionTypesType {}
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
#[cfg_attr(
feature = "serde",
serde(bound = "
Custom: ::serde::Serialize,
for<'dea> Custom: ::serde::Deserialize<'dea>,
<Custom as ExtensionType>::Value: ::serde::Serialize,
for<'deb> <Custom as ExtensionType>::Value: ::serde::Deserialize<'deb>,
")
)]
pub enum Value<Custom>
where
Custom: ExtensionType,
{
Map(OrMap<String, Custom>),
Array(OrArray<Custom>),
Register(MvReg),
Custom(<Custom as ExtensionType>::Value),
}
impl<C> fmt::Debug for Value<C>
where
C: fmt::Debug + ExtensionType,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Map(m) => f.debug_tuple("Value::Map").field(m).finish(),
Value::Array(a) => f.debug_tuple("Value::Array").field(a).finish(),
Value::Register(r) => f.debug_tuple("Value::Register").field(r).finish(),
Value::Custom(c) => f.debug_tuple("Value::Custom").field(c).finish(),
}
}
}
impl<C> Value<C>
where
C: ExtensionType,
{
fn is_bottom(&self) -> bool {
match self {
Value::Map(m) => m.is_bottom(),
Value::Array(a) => a.is_bottom(),
Value::Register(r) => r.is_bottom(),
Value::Custom(c) => c.is_bottom(),
}
}
#[cfg(any(test, feature = "arbitrary"))]
fn dots(&self) -> CausalContext {
match self {
Value::Map(m) => m.dots(),
Value::Array(a) => a.dots(),
Value::Register(r) => r.dots(),
Value::Custom(c) => c.dots(),
}
}
pub fn type_name(&self) -> &'static str {
match self {
Self::Map(_) => "Map",
Self::Array(_) => "Array",
Self::Register(_) => "Register",
Self::Custom(c) => C::type_name(&C::ValueRef::from(c)),
}
}
}
pub enum ValueRef<'a, Custom>
where
Custom: ExtensionType,
Custom::ValueRef<'a>: Copy,
{
Map(&'a OrMap<String, Custom>),
Array(&'a OrArray<Custom>),
Register(&'a MvReg),
Custom(Custom::ValueRef<'a>),
}
impl<C> Clone for ValueRef<'_, C>
where
C: ExtensionType,
{
fn clone(&self) -> Self {
*self
}
}
impl<C> Copy for ValueRef<'_, C> where C: ExtensionType {}
impl<C> PartialEq for ValueRef<'_, C>
where
C: ExtensionType + PartialEq,
for<'doc> C::ValueRef<'doc>: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (*self, *other) {
(ValueRef::Map(m1), ValueRef::Map(m2)) => m1.eq(m2),
(ValueRef::Array(a1), ValueRef::Array(a2)) => a1.eq(a2),
(ValueRef::Register(r1), ValueRef::Register(r2)) => r1.eq(r2),
(ValueRef::Custom(c1), ValueRef::Custom(c2)) => c1.eq(&c2),
_ => false,
}
}
}
macro_rules! impl_partial_eq {
({$($t:ty),+}) => {
$(impl_partial_eq!($t);)+
};
($t:ty) => {
impl<C> PartialEq<$t> for ValueRef<'_, C>
where
C: ExtensionType,
{
fn eq(&self, other: &$t) -> bool {
matches!(*self, ValueRef::Register(r1) if r1 == other)
}
}
};
}
impl_partial_eq!({[u8], &[u8], str, &str, bool, f64, u64, i64});
impl_partial_eq!(i32);
impl<C, const N: usize> PartialEq<&[u8; N]> for ValueRef<'_, C>
where
C: ExtensionType,
{
fn eq(&self, other: &&[u8; N]) -> bool {
matches!(*self, ValueRef::Register(r1) if r1 == other)
}
}
impl<C> fmt::Debug for ValueRef<'_, C>
where
C: fmt::Debug + ExtensionType,
for<'a> C::ValueRef<'a>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ValueRef::Map(m) => f.debug_tuple("ValueRef::Map").field(m).finish(),
ValueRef::Array(a) => f.debug_tuple("ValueRef::Array").field(a).finish(),
ValueRef::Register(r) => f.debug_tuple("ValueRef::Register").field(r).finish(),
ValueRef::Custom(c) => f.debug_tuple("ValueRef::Custom").field(c).finish(),
}
}
}
impl<C> ValueRef<'_, C>
where
C: ExtensionType,
{
pub fn type_name(&self) -> &'static str {
match self {
Self::Map(_) => "Map",
Self::Array(_) => "Array",
Self::Register(_) => "Register",
Self::Custom(c) => C::type_name(c),
}
}
}
impl<C> From<ValueRef<'_, C>> for Value<C>
where
C: ExtensionType + Clone,
{
fn from(val: ValueRef<'_, C>) -> Self {
match val {
ValueRef::Map(m) => Value::Map(m.clone()),
ValueRef::Array(a) => Value::Array(a.clone()),
ValueRef::Register(r) => Value::Register(r.clone()),
ValueRef::Custom(c) => Value::Custom(c.into()),
}
}
}
impl<'a, C> From<&'a Value<C>> for ValueRef<'a, C>
where
C: ExtensionType,
{
fn from(val: &'a Value<C>) -> Self {
match val {
Value::Map(m) => ValueRef::Map(m),
Value::Array(a) => ValueRef::Array(a),
Value::Register(r) => ValueRef::Register(r),
Value::Custom(c) => ValueRef::Custom(c.into()),
}
}
}
impl<'a, C> From<&'a OrMap<String, C>> for ValueRef<'a, C>
where
C: ExtensionType,
{
fn from(value: &'a OrMap<String, C>) -> Self {
Self::Map(value)
}
}
impl<'a, C> From<&'a OrArray<C>> for ValueRef<'a, C>
where
C: ExtensionType,
{
fn from(value: &'a OrArray<C>) -> Self {
Self::Array(value)
}
}
impl<'a, C> From<&'a MvReg> for ValueRef<'a, C>
where
C: ExtensionType,
{
fn from(value: &'a MvReg) -> Self {
Self::Register(value)
}
}
impl<'a, C> ValueRef<'a, C>
where
C: ExtensionType,
{
pub fn custom(value: impl Into<C::ValueRef<'a>>) -> Self {
Self::Custom(value.into())
}
}
impl<C> From<OrMap<String, C>> for Value<C>
where
C: ExtensionType,
{
fn from(value: OrMap<String, C>) -> Self {
Self::Map(value)
}
}
impl<C> From<OrArray<C>> for Value<C>
where
C: ExtensionType,
{
fn from(value: OrArray<C>) -> Self {
Self::Array(value)
}
}
impl<C> From<MvReg> for Value<C>
where
C: ExtensionType,
{
fn from(value: MvReg) -> Self {
Self::Register(value)
}
}
impl<C> Value<C>
where
C: ExtensionType,
{
pub fn custom(value: impl Into<C::Value>) -> Self {
Self::Custom(value.into())
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum ValueType<C> {
Map,
Array,
Register,
Custom(C),
}
impl<C> From<ValueRef<'_, C>> for ValueType<C::ValueKind>
where
C: ExtensionType,
{
fn from(value: ValueRef<'_, C>) -> Self {
match value {
ValueRef::Map(_) => Self::Map,
ValueRef::Array(_) => Self::Array,
ValueRef::Register(_) => Self::Register,
ValueRef::Custom(c) => Self::Custom(c.into()),
}
}
}
#[derive(Clone, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
pub struct TypeVariantValue<Custom> {
pub map: OrMap<String, Custom>,
pub array: OrArray<Custom>,
pub reg: MvReg,
#[cfg_attr(feature = "serde", serde(flatten))]
pub custom: Custom,
}
impl<C> fmt::Debug for TypeVariantValue<C>
where
C: ExtensionType + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match (
self.map.is_bottom(),
self.array.is_bottom(),
self.reg.is_bottom(),
self.custom.is_bottom(),
) {
(false, true, true, true) => self.map.fmt(f),
(true, false, true, true) => self.array.fmt(f),
(true, true, false, true) => self.reg.fmt(f),
(true, true, true, false) => self.custom.fmt(f),
_ => {
let mut w = f.debug_struct("TypeVariantValue");
if !self.map.is_bottom() {
w.field("map", &self.map);
}
if !self.array.is_bottom() {
w.field("array", &self.array);
}
if !self.reg.is_bottom() {
w.field("reg", &self.reg);
}
if !self.custom.is_bottom() {
w.field("custom", &self.custom);
}
w.finish_non_exhaustive()
}
}
}
}
impl<C> TypeVariantValue<C> {
pub fn coerce_to_value_ref(&self) -> ValueRef<'_, C>
where
C: ExtensionType,
{
if !self.custom.is_bottom() {
ValueRef::Custom(self.custom.coerce_to_value_ref())
} else if !self.map.is_bottom() {
ValueRef::Map(&self.map)
} else if !self.array.is_bottom() {
ValueRef::Array(&self.array)
} else if !self.reg.is_bottom() {
ValueRef::Register(&self.reg)
} else {
panic!("attempt to coerce empty TypeVariantValue to ValueRef");
}
}
}
impl<C> DotStore for TypeVariantValue<C>
where
C: ExtensionType,
{
fn add_dots_to(&self, other: &mut CausalContext) {
self.map.add_dots_to(other);
self.array.add_dots_to(other);
self.reg.add_dots_to(other);
self.custom.add_dots_to(other);
}
fn is_bottom(&self) -> bool {
self.map.is_bottom()
&& self.array.is_bottom()
&& self.reg.is_bottom()
&& self.custom.is_bottom()
}
fn subset_for_inflation_from(&self, frontier: &CausalContext) -> Self {
Self {
map: self.map.subset_for_inflation_from(frontier),
array: self.array.subset_for_inflation_from(frontier),
reg: self.reg.subset_for_inflation_from(frontier),
custom: self.custom.subset_for_inflation_from(frontier),
}
}
}
impl<C, S> DotStoreJoin<S> for TypeVariantValue<C>
where
S: Visit<String>
+ Visit<Uid>
+ KeySentinel
+ ValueSentinel<MvRegValue>
+ TypeSentinel<C::ValueKind>,
C: ExtensionType + DotStoreJoin<S> + Clone + PartialEq + fmt::Debug,
{
fn join(
ds1: (Self, &CausalContext),
ds2: (Self, &CausalContext),
on_dot_change: &mut dyn FnMut(DotChange),
sentinel: &mut S,
) -> Result<Self, S::Error>
where
Self: Sized,
S: Sentinel,
{
let (m1, cc1) = ds1;
let (m2, cc2) = ds2;
let types_before = [
!m1.map.is_bottom(),
!m1.array.is_bottom(),
!m1.reg.is_bottom(),
];
let map = OrMap::join((m1.map, cc1), (m2.map, cc2), on_dot_change, sentinel)?;
let array = OrArray::join((m1.array, cc1), (m2.array, cc2), on_dot_change, sentinel)?;
let reg = MvReg::join((m1.reg, cc1), (m2.reg, cc2), on_dot_change, sentinel)?;
let custom = C::join((m1.custom, cc1), (m2.custom, cc2), on_dot_change, sentinel)?;
let types_after = [!map.is_bottom(), !array.is_bottom(), !reg.is_bottom()];
for (ty, (before, after)) in [ValueType::Map, ValueType::Array, ValueType::Register]
.into_iter()
.zip(types_before.into_iter().zip(types_after))
{
match (before, after) {
(true, false) => sentinel.unset_type(ty)?,
(false, true) => sentinel.set_type(ty)?,
_ => (),
}
}
Ok(TypeVariantValue {
map,
array,
reg,
custom,
})
}
fn dry_join(
ds1: (&Self, &CausalContext),
ds2: (&Self, &CausalContext),
sentinel: &mut S,
) -> Result<DryJoinOutput, S::Error>
where
Self: Sized,
S: Sentinel,
{
let (m1, cc1) = ds1;
let (m2, cc2) = ds2;
let types_before = [
!m1.map.is_bottom(),
!m1.array.is_bottom(),
!m1.reg.is_bottom(),
];
let map = OrMap::dry_join((&m1.map, cc1), (&m2.map, cc2), sentinel)?;
let array = OrArray::dry_join((&m1.array, cc1), (&m2.array, cc2), sentinel)?;
let reg = MvReg::dry_join((&m1.reg, cc1), (&m2.reg, cc2), sentinel)?;
let custom = C::dry_join((&m1.custom, cc1), (&m2.custom, cc2), sentinel)?;
let types_after = [!map.is_bottom(), !array.is_bottom(), !reg.is_bottom()];
for (ty, (before, after)) in [ValueType::Map, ValueType::Array, ValueType::Register]
.into_iter()
.zip(types_before.into_iter().zip(types_after))
{
match (before, after) {
(true, false) => sentinel.unset_type(ty)?,
(false, true) => sentinel.set_type(ty)?,
_ => (),
}
}
let result_is_non_bottom = types_after.iter().any(|x| *x) || !custom.is_bottom();
Ok(DryJoinOutput::new(!result_is_non_bottom))
}
}
impl<C> From<Value<C>> for TypeVariantValue<C>
where
C: ExtensionType,
{
fn from(value: Value<C>) -> Self {
match value {
Value::Map(m) => TypeVariantValue {
map: m,
array: Default::default(),
reg: Default::default(),
custom: Default::default(),
},
Value::Array(a) => TypeVariantValue {
map: Default::default(),
array: a,
reg: Default::default(),
custom: Default::default(),
},
Value::Register(r) => TypeVariantValue {
map: Default::default(),
array: Default::default(),
reg: r,
custom: Default::default(),
},
Value::Custom(c) => TypeVariantValue {
map: Default::default(),
array: Default::default(),
reg: Default::default(),
custom: c.into(),
},
}
}
}
impl DotStore for NoExtensionTypes {
fn add_dots_to(&self, _: &mut CausalContext) {}
fn is_bottom(&self) -> bool {
true
}
fn subset_for_inflation_from(&self, _: &CausalContext) -> Self {
Self
}
}
impl DotStore for NoExtensionTypesType {
fn add_dots_to(&self, _: &mut CausalContext) {
match *self {}
}
fn is_bottom(&self) -> bool {
match *self {}
}
fn subset_for_inflation_from(&self, _: &CausalContext) -> Self {
match *self {}
}
}
impl DotStore for () {
fn add_dots_to(&self, _: &mut CausalContext) {}
fn is_bottom(&self) -> bool {
true
}
fn subset_for_inflation_from(&self, _: &CausalContext) -> Self {}
}
impl<S> DotStoreJoin<S> for NoExtensionTypes {
fn join(
_: (Self, &CausalContext),
_: (Self, &CausalContext),
_: &mut dyn FnMut(DotChange),
_: &mut S,
) -> Result<Self, <S>::Error>
where
Self: Sized,
S: Sentinel,
{
Ok(Self)
}
fn dry_join(
_ds1: (&Self, &CausalContext),
_ds2: (&Self, &CausalContext),
_sentinel: &mut S,
) -> Result<DryJoinOutput, S::Error>
where
Self: Sized,
S: Sentinel,
{
Ok(DryJoinOutput::bottom())
}
}
#[cfg(feature = "json")]
impl From<&'_ NoExtensionTypes> for serde_json::Value {
fn from(_: &'_ NoExtensionTypes) -> Self {
serde_json::Value::Null
}
}
#[cfg(feature = "json")]
impl From<NoExtensionTypes> for serde_json::Value {
fn from(_: NoExtensionTypes) -> Self {
serde_json::Value::Null
}
}
impl From<NoExtensionTypesType> for NoExtensionTypes {
fn from(v: NoExtensionTypesType) -> Self {
match v {}
}
}
impl From<&Self> for NoExtensionTypesType {
fn from(v: &Self) -> Self {
match *v {}
}
}
impl From<NoExtensionTypes> for () {
fn from(_: NoExtensionTypes) -> Self {
Self::default()
}
}
impl ToValue for NoExtensionTypesType {
type Values = ();
type Value = ();
type LeafValue = ();
fn values(self) -> Self::Values {
match self {}
}
fn value(self) -> Result<Self::Value, Box<snapshot::SingleValueError<Self::LeafValue>>> {
match self {}
}
}
impl ExtensionType for NoExtensionTypes {
type ValueKind = NoExtensionTypesType;
type Value = NoExtensionTypesType;
type ValueRef<'doc> = NoExtensionTypesType;
fn coerce_to_value_ref(&self) -> Self::ValueRef<'_> {
panic!("NoExtensionTypes is always bottom, and cannot be coerced into a ValueRef");
}
fn type_name(value: &Self::ValueRef<'_>) -> &'static str {
match *value {}
}
fn bottom() -> Self {
Self
}
}