partiql_value/
boxed_variant.rs

1use dyn_clone::DynClone;
2use dyn_hash::DynHash;
3use partiql_common::pretty::PrettyDoc;
4use std::any::Any;
5use std::borrow::Cow;
6use std::cmp::Ordering;
7use std::error::Error;
8
9use crate::datum::{Datum, DatumCategoryOwned, DatumCategoryRef, DatumLower};
10use crate::Value;
11use pretty::{DocAllocator, DocBuilder};
12use std::fmt::{Debug, Display};
13
14pub type BoxedVariantError = Box<dyn Error>;
15
16pub type BoxedVariantResult<T> = Result<T, BoxedVariantError>;
17pub type BoxedVariantValueIntoIterator =
18    Box<dyn Iterator<Item = BoxedVariantResult<DynBoxedVariant>>>;
19
20pub type BoxedVariantValueIter<'a> =
21    Box<dyn 'a + Iterator<Item = BoxedVariantResult<&'a DynBoxedVariant>>>;
22
23pub trait DynBoxedVariantTypeFactory {
24    fn to_dyn_type_tag(self) -> BoxedVariantTypeTag;
25}
26
27pub type BoxedVariantTypeTag = Box<dyn BoxedVariantType>;
28pub trait BoxedVariantType: Debug + DynClone {
29    fn construct(&self, bytes: Vec<u8>) -> BoxedVariantResult<DynBoxedVariant>;
30    fn name(&self) -> &'static str;
31
32    fn value_eq(&self, l: &DynBoxedVariant, r: &DynBoxedVariant) -> bool;
33
34    fn value_eq_param(
35        &self,
36        l: &DynBoxedVariant,
37        r: &DynBoxedVariant,
38        nulls_eq: bool,
39        nans_eq: bool,
40    ) -> bool;
41}
42
43dyn_clone::clone_trait_object!(BoxedVariantType);
44
45impl Eq for dyn BoxedVariantType {}
46impl PartialEq for dyn BoxedVariantType {
47    fn eq(&self, other: &Self) -> bool {
48        self.name() == other.name()
49    }
50}
51impl PartialOrd for dyn BoxedVariantType {
52    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
53        Some(self.cmp(other))
54    }
55}
56impl Ord for dyn BoxedVariantType {
57    fn cmp(&self, other: &Self) -> Ordering {
58        self.name().cmp(other.name())
59    }
60}
61
62impl<T> DynBoxedVariantTypeFactory for T
63where
64    T: BoxedVariantType + 'static,
65{
66    fn to_dyn_type_tag(self) -> BoxedVariantTypeTag {
67        Box::new(self)
68    }
69}
70
71pub type DynBoxedVariant = Box<dyn BoxedVariant>;
72#[cfg_attr(feature = "serde", typetag::serde)]
73pub trait BoxedVariant:
74    Display + Debug + DynHash + DynClone + Datum<Value> + DatumLower<Value>
75{
76    fn type_tag(&self) -> BoxedVariantTypeTag;
77
78    fn as_any(&self) -> &dyn Any;
79    fn into_dyn_iter(self: Box<Self>) -> BoxedVariantResult<BoxedVariantValueIntoIterator>;
80
81    fn category(&self) -> DatumCategoryRef<'_>;
82
83    fn into_category(self: Box<Self>) -> DatumCategoryOwned;
84}
85
86dyn_hash::hash_trait_object!(BoxedVariant);
87dyn_clone::clone_trait_object!(BoxedVariant);
88
89impl Eq for DynBoxedVariant {}
90impl PartialEq for DynBoxedVariant {
91    fn eq(&self, other: &Self) -> bool {
92        self.type_tag() == other.type_tag() && self.type_tag().value_eq(self, other)
93    }
94}
95impl PartialOrd for DynBoxedVariant {
96    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
97        Some(self.cmp(other))
98    }
99}
100impl Ord for DynBoxedVariant {
101    fn cmp(&self, other: &Self) -> Ordering {
102        let missing = |_| Cow::Owned(Value::Missing);
103        self.type_tag().cmp(&other.type_tag()).then_with(|| {
104            self.lower()
105                .unwrap_or_else(missing)
106                .cmp(&other.lower().unwrap_or_else(missing))
107        })
108    }
109}
110
111impl PrettyDoc for DynBoxedVariant {
112    fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
113    where
114        D: DocAllocator<'b, A>,
115        D::Doc: Clone,
116        A: Clone,
117    {
118        // todo!("impl PrettyDoc for BoxedVariant")
119        arena.text(format!("{self}"))
120    }
121}