Skip to content

Commit f684ea9

Browse files
authored
Add boxed variant comparisons (#542)
1 parent cc421cf commit f684ea9

File tree

18 files changed

+488
-133
lines changed

18 files changed

+488
-133
lines changed

extension/partiql-extension-ion/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ unicase = "2.7"
3434
rust_decimal = { version = "1.36.0", default-features = false, features = ["std"] }
3535
rust_decimal_macros = "1.36"
3636
ion-rs_old = { version = "0.18", package = "ion-rs" }
37-
ion-rs = { version = "1.0.0-rc.10", features = ["experimental"] }
37+
ion-rs = { version = "1.0.0-rc.11", features = ["experimental"] }
3838

3939
time = { version = "0.3", features = ["macros"] }
4040
once_cell = "1"

extension/partiql-extension-ion/src/boxed_ion.rs

Lines changed: 124 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use ion_rs::{
44
Sequence,
55
};
66
use partiql_value::boxed_variant::{
7-
BoxedVariant, BoxedVariantResult, BoxedVariantType, BoxedVariantValueIntoIterator,
7+
BoxedVariant, BoxedVariantResult, BoxedVariantType, BoxedVariantTypeTag,
8+
BoxedVariantValueIntoIterator, DynBoxedVariant,
89
};
910
use partiql_value::datum::{
1011
Datum, DatumCategoryOwned, DatumCategoryRef, DatumLower, DatumLowerResult, DatumSeqOwned,
@@ -15,8 +16,10 @@ use partiql_value::{Bag, BindingsName, List, Tuple, Value, Variant};
1516
use peekmore::{PeekMore, PeekMoreIterator};
1617
#[cfg(feature = "serde")]
1718
use serde::{Deserialize, Deserializer, Serialize, Serializer};
19+
use std::any::Any;
1820
use std::borrow::Cow;
1921
use std::cell::RefCell;
22+
use std::cmp::Ordering;
2023
use std::fmt::{Debug, Display, Formatter};
2124
use std::hash::{Hash, Hasher};
2225
use std::ops::DerefMut;
@@ -26,15 +29,42 @@ use thiserror::Error;
2629
#[derive(Default, Debug, Copy, Clone)]
2730
pub struct BoxedIonType {}
2831
impl BoxedVariantType for BoxedIonType {
29-
type Doc = BoxedIon;
30-
31-
fn construct(&self, bytes: Vec<u8>) -> BoxedVariantResult<Self::Doc> {
32-
BoxedIon::parse(bytes, BoxedIonStreamType::SingleTLV).map_err(Into::into)
32+
fn construct(&self, bytes: Vec<u8>) -> BoxedVariantResult<DynBoxedVariant> {
33+
BoxedIon::parse(bytes, BoxedIonStreamType::SingleTLV)
34+
.map_err(Into::into)
35+
.map(|b| Box::new(b) as DynBoxedVariant)
3336
}
3437

3538
fn name(&self) -> &'static str {
3639
"ion"
3740
}
41+
42+
fn value_eq(&self, l: &DynBoxedVariant, r: &DynBoxedVariant) -> bool {
43+
let (l, r) = get_values(l, r);
44+
45+
l.eq(r)
46+
}
47+
48+
fn value_cmp(&self, l: &DynBoxedVariant, r: &DynBoxedVariant) -> Ordering {
49+
let (l, r) = get_values(l, r);
50+
51+
l.cmp(r)
52+
}
53+
}
54+
55+
#[inline]
56+
fn get_value(l: &DynBoxedVariant) -> &BoxedIon {
57+
l.as_any().downcast_ref::<BoxedIon>().expect("IonValue")
58+
}
59+
60+
#[inline]
61+
fn get_values<'a, 'b>(
62+
l: &'a DynBoxedVariant,
63+
r: &'b DynBoxedVariant,
64+
) -> (&'a BoxedIon, &'b BoxedIon) {
65+
debug_assert_eq!(*l.type_tag(), *r.type_tag());
66+
67+
(get_value(l), get_value(r))
3868
}
3969

4070
/// Errors in boxed Ion.
@@ -116,6 +146,14 @@ impl Hash for BoxedIon {
116146

117147
#[cfg_attr(feature = "serde", typetag::serde)]
118148
impl BoxedVariant for BoxedIon {
149+
fn type_tag(&self) -> BoxedVariantTypeTag {
150+
Box::new(BoxedIonType {})
151+
}
152+
153+
fn as_any(&self) -> &dyn Any {
154+
self
155+
}
156+
119157
fn into_dyn_iter(self: Box<Self>) -> BoxedVariantResult<BoxedVariantValueIntoIterator> {
120158
let iter = self.try_into_iter()?;
121159

@@ -127,13 +165,19 @@ impl BoxedVariant for BoxedIon {
127165
match &self.doc {
128166
BoxedIonValue::Stream() => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
129167
BoxedIonValue::Sequence(_) => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
130-
BoxedIonValue::Value(elt) => match elt.ion_type() {
131-
IonType::List => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
132-
IonType::SExp => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
133-
IonType::Null => DatumCategoryRef::Null,
134-
IonType::Struct => DatumCategoryRef::Tuple(DatumTupleRef::Dynamic(self)),
135-
_ => DatumCategoryRef::Scalar(DatumValueRef::Lower(self)),
136-
},
168+
BoxedIonValue::Value(elt) => {
169+
if elt.is_null() {
170+
DatumCategoryRef::Null
171+
} else {
172+
match elt.ion_type() {
173+
IonType::List => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
174+
IonType::SExp => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
175+
IonType::Null => DatumCategoryRef::Null,
176+
IonType::Struct => DatumCategoryRef::Tuple(DatumTupleRef::Dynamic(self)),
177+
_ => DatumCategoryRef::Scalar(DatumValueRef::Lower(self)),
178+
}
179+
}
180+
}
137181
}
138182
}
139183

@@ -143,44 +187,70 @@ impl BoxedVariant for BoxedIon {
143187
BoxedIonValue::Sequence(_) => {
144188
DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self))
145189
}
146-
BoxedIonValue::Value(elt) => match elt.ion_type() {
147-
IonType::List => DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self)),
148-
IonType::SExp => DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self)),
149-
IonType::Null => DatumCategoryOwned::Null,
150-
IonType::Struct => DatumCategoryOwned::Tuple(DatumTupleOwned::Dynamic(self)),
151-
_ => DatumCategoryOwned::Scalar(DatumValueOwned::Value(self.into_value())),
152-
},
190+
BoxedIonValue::Value(elt) => {
191+
if elt.is_null() {
192+
DatumCategoryOwned::Null
193+
} else {
194+
match elt.ion_type() {
195+
IonType::List => DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self)),
196+
IonType::SExp => DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self)),
197+
IonType::Null => DatumCategoryOwned::Null,
198+
IonType::Struct => {
199+
DatumCategoryOwned::Tuple(DatumTupleOwned::Dynamic(self))
200+
}
201+
_ => DatumCategoryOwned::Scalar(DatumValueOwned::Value(self.into_value())),
202+
}
203+
}
204+
}
153205
}
154206
}
155207
}
156208

209+
impl PartialEq<Self> for BoxedIon {
210+
fn eq(&self, other: &Self) -> bool {
211+
self.doc.eq(&other.doc)
212+
}
213+
}
214+
215+
impl Eq for BoxedIon {}
216+
217+
impl PartialOrd for BoxedIon {
218+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
219+
Some(self.cmp(other))
220+
}
221+
}
222+
impl Ord for BoxedIon {
223+
fn cmp(&self, other: &Self) -> Ordering {
224+
// TODO lowering just to compare is costly... Either find a better way, or lift this out of the extension
225+
self.lower().unwrap().cmp(&other.lower().unwrap())
226+
}
227+
}
228+
157229
impl DatumLower<Value> for BoxedIon {
158230
fn into_lower(self) -> DatumLowerResult<Value> {
159231
let Self { ctx, doc } = self;
160-
match doc {
232+
let pval = match doc {
161233
BoxedIonValue::Stream() => todo!("into_lower stream"),
162-
BoxedIonValue::Sequence(_) => todo!("into_lower seq"),
163-
BoxedIonValue::Value(elt) => {
164-
let pval = elt.into_partiql_value()?;
165-
Ok(match pval {
166-
PartiqlValueTarget::Atom(val) => val,
167-
PartiqlValueTarget::List(l) => {
168-
let vals = l.into_iter().map(|elt| Self::new_value(elt, ctx.clone()));
169-
List::from_iter(vals).into()
170-
}
171-
PartiqlValueTarget::Bag(b) => {
172-
let vals = b.into_iter().map(|elt| Self::new_value(elt, ctx.clone()));
173-
Bag::from_iter(vals).into()
174-
}
175-
PartiqlValueTarget::Struct(s) => {
176-
let vals = s
177-
.into_iter()
178-
.map(|(key, elt)| (key, Self::new_value(elt, ctx.clone())));
179-
Tuple::from_iter(vals).into()
180-
}
181-
})
234+
BoxedIonValue::Sequence(seq) => seq.into_partiql_value()?,
235+
BoxedIonValue::Value(elt) => elt.into_partiql_value()?,
236+
};
237+
Ok(match pval {
238+
PartiqlValueTarget::Atom(val) => val,
239+
PartiqlValueTarget::List(l) => {
240+
let vals = l.into_iter().map(|elt| Self::new_value(elt, ctx.clone()));
241+
List::from_iter(vals).into()
182242
}
183-
}
243+
PartiqlValueTarget::Bag(b) => {
244+
let vals = b.into_iter().map(|elt| Self::new_value(elt, ctx.clone()));
245+
Bag::from_iter(vals).into()
246+
}
247+
PartiqlValueTarget::Struct(s) => {
248+
let vals = s
249+
.into_iter()
250+
.map(|(key, elt)| (key, Self::new_value(elt, ctx.clone())));
251+
Tuple::from_iter(vals).into()
252+
}
253+
})
184254
}
185255

186256
fn into_lower_boxed(self: Box<Self>) -> DatumLowerResult<Value> {
@@ -307,7 +377,7 @@ impl<'a> RefTupleView<'a, Value> for BoxedIon {
307377
}
308378

309379
impl OwnedTupleView<Value> for BoxedIon {
310-
fn take_val(self, k: &BindingsName<'_>) -> Option<Value> {
380+
fn take_val(self, _k: &BindingsName<'_>) -> Option<Value> {
311381
todo!()
312382
}
313383

@@ -461,6 +531,18 @@ enum BoxedIonValue {
461531
Sequence(Sequence),
462532
}
463533

534+
impl PartialEq<Self> for BoxedIonValue {
535+
fn eq(&self, other: &Self) -> bool {
536+
match (self, other) {
537+
(BoxedIonValue::Value(l), BoxedIonValue::Value(r)) => l == r,
538+
(BoxedIonValue::Sequence(l), BoxedIonValue::Sequence(r)) => l == r,
539+
_ => false,
540+
}
541+
}
542+
}
543+
544+
impl Eq for BoxedIonValue {}
545+
464546
impl From<Element> for BoxedIonValue {
465547
fn from(value: Element) -> Self {
466548
BoxedIonValue::Value(value)

extension/partiql-extension-ion/src/common.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub enum Encoding {
1010
PartiqlEncodedAsIon,
1111
}
1212

13+
pub(crate) const BOXED_ION_ANNOT: &str = "$ion";
14+
1315
pub(crate) const BAG_ANNOT: &str = "$bag";
1416
pub(crate) const TIME_ANNOT: &str = "$time";
1517
pub(crate) const DATE_ANNOT: &str = "$date";

0 commit comments

Comments
 (0)