partiql_value/
variant.rs

1use crate::boxed_variant::{
2    BoxedVariant, BoxedVariantError, BoxedVariantResult, BoxedVariantTypeTag,
3    BoxedVariantValueIntoIterator, BoxedVariantValueIter, DynBoxedVariant,
4};
5use crate::datum::{
6    Datum, DatumCategory, DatumCategoryOwned, DatumCategoryRef, DatumLower, DatumLowerResult,
7    DatumValue,
8};
9
10use crate::{Comparable, EqualityValue, NullSortedValue, NullableEq, Value};
11use delegate::delegate;
12use partiql_common::pretty::{pretty_surrounded_doc, PrettyDoc};
13use pretty::{DocAllocator, DocBuilder};
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16
17use std::borrow::Cow;
18use std::cmp::Ordering;
19use std::fmt::Debug;
20use std::hash::Hash;
21
22use thiserror::Error;
23
24#[derive(Clone, Debug)]
25#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26pub struct Variant {
27    variant: DynBoxedVariant,
28}
29
30impl Variant {
31    pub fn new<B: Into<Vec<u8>>>(
32        contents: B,
33        type_tag: BoxedVariantTypeTag,
34    ) -> BoxedVariantResult<Self> {
35        let variant = Unparsed::new(contents, type_tag)?.parse()?;
36        Ok(Self { variant })
37    }
38
39    pub fn type_tag(&self) -> BoxedVariantTypeTag {
40        self.variant.type_tag()
41    }
42
43    pub fn dyn_variant(&self) -> &DynBoxedVariant {
44        &self.variant
45    }
46}
47
48impl<T> From<T> for Variant
49where
50    T: BoxedVariant + 'static,
51{
52    fn from(variant: T) -> Self {
53        let variant = Box::new(variant) as DynBoxedVariant;
54        Self { variant }
55    }
56}
57
58impl From<DynBoxedVariant> for Variant {
59    fn from(variant: DynBoxedVariant) -> Self {
60        Self { variant }
61    }
62}
63
64impl DatumValue<Value> for Variant {}
65
66impl DatumLower<Value> for Variant {
67    fn into_lower(self) -> DatumLowerResult<Value> {
68        self.variant.into_lower_boxed()
69    }
70
71    fn into_lower_boxed(self: Box<Self>) -> DatumLowerResult<Value> {
72        self.into_lower()
73    }
74
75    fn lower(&self) -> DatumLowerResult<Cow<'_, Value>> {
76        self.variant.lower()
77    }
78}
79
80impl<'a> DatumCategory<'a> for Variant {
81    fn category(&'a self) -> DatumCategoryRef<'a> {
82        self.variant.category()
83    }
84
85    fn into_category(self) -> DatumCategoryOwned {
86        self.variant.into_category()
87    }
88}
89
90#[derive(Debug, Clone)]
91pub struct Unparsed {
92    contents: Vec<u8>,
93    type_tag: BoxedVariantTypeTag,
94}
95
96impl Unparsed {
97    pub fn new<B: Into<Vec<u8>>>(
98        contents: B,
99        type_tag: BoxedVariantTypeTag,
100    ) -> BoxedVariantResult<Self> {
101        Ok(Unparsed {
102            contents: contents.into(),
103            type_tag,
104        })
105    }
106}
107
108#[derive(Error, Debug)]
109pub enum VariantError {
110    #[error("Latent Type Error for Boxed Document {0}")]
111    LatentTypeError(BoxedVariantError, BoxedVariantTypeTag),
112}
113
114pub type VariantResult<T> = Result<T, VariantError>;
115
116impl Unparsed {
117    fn parse(self) -> VariantResult<DynBoxedVariant> {
118        let Self { contents, type_tag } = self;
119        match type_tag.construct(contents) {
120            Ok(doc) => Ok(doc),
121            Err(err) => Err(VariantError::LatentTypeError(err, type_tag.clone())),
122        }
123    }
124}
125
126#[allow(dead_code)]
127pub struct VariantIter<'a>(BoxedVariantValueIter<'a>);
128
129impl IntoIterator for Variant {
130    type Item = BoxedVariantResult<Variant>;
131    type IntoIter = VariantIntoIterator;
132
133    fn into_iter(self) -> VariantIntoIterator {
134        let iter = self.variant.into_dyn_iter().expect("into_dyn_iter");
135        VariantIntoIterator(iter)
136    }
137}
138
139pub struct VariantIntoIterator(BoxedVariantValueIntoIterator);
140
141impl Iterator for VariantIntoIterator {
142    type Item = BoxedVariantResult<Variant>;
143
144    #[inline]
145    fn next(&mut self) -> Option<Self::Item> {
146        self.0.next().map(|res| res.map(Variant::from))
147    }
148
149    #[inline]
150    fn size_hint(&self) -> (usize, Option<usize>) {
151        self.0.size_hint()
152    }
153}
154
155impl Datum<Value> for Variant {
156    delegate! {
157        to self.variant {
158            fn is_null(&self) -> bool;
159            fn is_missing(&self) -> bool;
160            fn is_absent(&self) -> bool;
161            fn is_present(&self) -> bool;
162            fn is_sequence(&self) -> bool;
163            fn is_ordered(&self) -> bool;
164        }
165    }
166}
167
168impl PartialOrd<Self> for Variant {
169    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
170        Some(self.cmp(other))
171    }
172}
173
174impl Ord for Variant {
175    fn cmp(&self, other: &Self) -> Ordering {
176        let l = &self.variant;
177        let r = &other.variant;
178        l.type_tag().cmp(&r.type_tag()).then_with(|| l.cmp(r))
179    }
180}
181
182impl PartialEq<Self> for Variant {
183    fn eq(&self, other: &Self) -> bool {
184        let lty = self.variant.type_tag();
185        let rty = other.variant.type_tag();
186        lty.eq(&rty) && self.variant.eq(&other.variant)
187    }
188}
189
190impl Eq for Variant {}
191
192impl Hash for Variant {
193    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
194        self.variant.type_tag().name().hash(state);
195        self.variant.hash(state);
196    }
197}
198
199impl<const NULLS_EQUAL: bool, const NAN_EQUAL: bool> NullableEq
200    for EqualityValue<'_, NULLS_EQUAL, NAN_EQUAL, Variant>
201{
202    #[inline(always)]
203    fn eq(&self, other: &Self) -> Value {
204        let l = &self.0.variant;
205        let r = &other.0.variant;
206        let lty = l.type_tag();
207        let rty = r.type_tag();
208
209        let res = lty == rty && lty.value_eq_param(l, r, NULLS_EQUAL, NAN_EQUAL);
210        Value::Boolean(res)
211    }
212
213    #[inline(always)]
214    fn eqg(&self, rhs: &Self) -> Value {
215        let wrap = EqualityValue::<'_, true, { NAN_EQUAL }, _>;
216        NullableEq::eq(&wrap(self.0), &wrap(rhs.0))
217    }
218}
219
220impl PrettyDoc for Variant {
221    fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
222    where
223        D: DocAllocator<'b, A>,
224        D::Doc: Clone,
225        A: Clone,
226    {
227        let doc = self.variant.pretty_doc(arena);
228
229        pretty_surrounded_doc(doc, "`", "`", arena)
230        // TODO eventually support suffixing quoted documents with `::<type>`
231        //let ty = self.variant.type_tag().name();
232        //.append(arena.text("::"))
233        //.append(arena.text(ty))
234    }
235}
236
237impl Comparable for Variant {
238    fn is_comparable_to(&self, rhs: &Self) -> bool {
239        self.variant.type_tag().name() == rhs.variant.type_tag().name()
240    }
241}
242
243impl<const NULLS_FIRST: bool> Ord for NullSortedValue<'_, NULLS_FIRST, Variant> {
244    fn cmp(&self, other: &Self) -> Ordering {
245        let wrap = NullSortedValue::<{ NULLS_FIRST }, _>;
246
247        let l = self.0.lower().expect("lower");
248        let l = wrap(l.as_ref());
249        let r = other.0.lower().expect("lower");
250        let r = wrap(r.as_ref());
251
252        l.cmp(&r)
253    }
254}