Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add boxed variant comparisons #542

Merged
merged 2 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extension/partiql-extension-ion/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ unicase = "2.7"
rust_decimal = { version = "1.36.0", default-features = false, features = ["std"] }
rust_decimal_macros = "1.36"
ion-rs_old = { version = "0.18", package = "ion-rs" }
ion-rs = { version = "1.0.0-rc.10", features = ["experimental"] }
ion-rs = { version = "1.0.0-rc.11", features = ["experimental"] }

time = { version = "0.3", features = ["macros"] }
once_cell = "1"
Expand Down
166 changes: 124 additions & 42 deletions extension/partiql-extension-ion/src/boxed_ion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
Sequence,
};
use partiql_value::boxed_variant::{
BoxedVariant, BoxedVariantResult, BoxedVariantType, BoxedVariantValueIntoIterator,
BoxedVariant, BoxedVariantResult, BoxedVariantType, BoxedVariantTypeTag,
BoxedVariantValueIntoIterator, DynBoxedVariant,
};
use partiql_value::datum::{
Datum, DatumCategoryOwned, DatumCategoryRef, DatumLower, DatumLowerResult, DatumSeqOwned,
Expand All @@ -15,8 +16,10 @@
use peekmore::{PeekMore, PeekMoreIterator};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::any::Any;
use std::borrow::Cow;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::DerefMut;
Expand All @@ -26,15 +29,42 @@
#[derive(Default, Debug, Copy, Clone)]
pub struct BoxedIonType {}
impl BoxedVariantType for BoxedIonType {
type Doc = BoxedIon;

fn construct(&self, bytes: Vec<u8>) -> BoxedVariantResult<Self::Doc> {
BoxedIon::parse(bytes, BoxedIonStreamType::SingleTLV).map_err(Into::into)
fn construct(&self, bytes: Vec<u8>) -> BoxedVariantResult<DynBoxedVariant> {
BoxedIon::parse(bytes, BoxedIonStreamType::SingleTLV)
.map_err(Into::into)
.map(|b| Box::new(b) as DynBoxedVariant)
}

fn name(&self) -> &'static str {
"ion"
}

fn value_eq(&self, l: &DynBoxedVariant, r: &DynBoxedVariant) -> bool {
let (l, r) = get_values(l, r);

l.eq(r)
}

fn value_cmp(&self, l: &DynBoxedVariant, r: &DynBoxedVariant) -> Ordering {
let (l, r) = get_values(l, r);

l.cmp(r)
}
}

#[inline]
fn get_value(l: &DynBoxedVariant) -> &BoxedIon {
l.as_any().downcast_ref::<BoxedIon>().expect("IonValue")
}

#[inline]
fn get_values<'a, 'b>(
l: &'a DynBoxedVariant,
r: &'b DynBoxedVariant,
) -> (&'a BoxedIon, &'b BoxedIon) {
debug_assert_eq!(*l.type_tag(), *r.type_tag());

(get_value(l), get_value(r))
}

/// Errors in boxed Ion.
Expand Down Expand Up @@ -79,7 +109,7 @@
}
}

pub type IonContextPtr = Rc<RefCell<IonContext>>;

Check warning on line 112 in extension/partiql-extension-ion/src/boxed_ion.rs

View workflow job for this annotation

GitHub Actions / clippy

type `boxed_ion::IonContext` is more private than the item `boxed_ion::IonContextPtr`

warning: type `boxed_ion::IonContext` is more private than the item `boxed_ion::IonContextPtr` --> extension/partiql-extension-ion/src/boxed_ion.rs:112:1 | 112 | pub type IonContextPtr = Rc<RefCell<IonContext>>; | ^^^^^^^^^^^^^^^^^^^^^^ type alias `boxed_ion::IonContextPtr` is reachable at visibility `pub` | note: but type `boxed_ion::IonContext` is only usable at visibility `pub(self)` --> extension/partiql-extension-ion/src/boxed_ion.rs:96:1 | 96 | struct IonContext { | ^^^^^^^^^^^^^^^^^ = note: `#[warn(private_interfaces)]` on by default

// TODO [EMBDOC] does this serialization work?
#[derive(Clone)]
Expand All @@ -90,7 +120,7 @@

#[cfg(feature = "serde")]
impl Serialize for BoxedIon {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>

Check warning on line 123 in extension/partiql-extension-ion/src/boxed_ion.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `serializer`

warning: unused variable: `serializer` --> extension/partiql-extension-ion/src/boxed_ion.rs:123:28 | 123 | fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> | ^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_serializer` | = note: `#[warn(unused_variables)]` on by default
where
S: Serializer,
{
Expand All @@ -100,7 +130,7 @@

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for BoxedIon {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>

Check warning on line 133 in extension/partiql-extension-ion/src/boxed_ion.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `deserializer`

warning: unused variable: `deserializer` --> extension/partiql-extension-ion/src/boxed_ion.rs:133:23 | 133 | fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> | ^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_deserializer`
where
D: Deserializer<'de>,
{
Expand All @@ -116,6 +146,14 @@

#[cfg_attr(feature = "serde", typetag::serde)]
impl BoxedVariant for BoxedIon {
fn type_tag(&self) -> BoxedVariantTypeTag {
Box::new(BoxedIonType {})
}

fn as_any(&self) -> &dyn Any {
self
}

fn into_dyn_iter(self: Box<Self>) -> BoxedVariantResult<BoxedVariantValueIntoIterator> {
let iter = self.try_into_iter()?;

Expand All @@ -127,13 +165,19 @@
match &self.doc {
BoxedIonValue::Stream() => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
BoxedIonValue::Sequence(_) => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
BoxedIonValue::Value(elt) => match elt.ion_type() {
IonType::List => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
IonType::SExp => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
IonType::Null => DatumCategoryRef::Null,
IonType::Struct => DatumCategoryRef::Tuple(DatumTupleRef::Dynamic(self)),
_ => DatumCategoryRef::Scalar(DatumValueRef::Lower(self)),
},
BoxedIonValue::Value(elt) => {
if elt.is_null() {
DatumCategoryRef::Null
} else {
match elt.ion_type() {
IonType::List => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
IonType::SExp => DatumCategoryRef::Sequence(DatumSeqRef::Dynamic(self)),
IonType::Null => DatumCategoryRef::Null,
IonType::Struct => DatumCategoryRef::Tuple(DatumTupleRef::Dynamic(self)),
_ => DatumCategoryRef::Scalar(DatumValueRef::Lower(self)),
}
}
}
}
}

Expand All @@ -143,44 +187,70 @@
BoxedIonValue::Sequence(_) => {
DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self))
}
BoxedIonValue::Value(elt) => match elt.ion_type() {
IonType::List => DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self)),
IonType::SExp => DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self)),
IonType::Null => DatumCategoryOwned::Null,
IonType::Struct => DatumCategoryOwned::Tuple(DatumTupleOwned::Dynamic(self)),
_ => DatumCategoryOwned::Scalar(DatumValueOwned::Value(self.into_value())),
},
BoxedIonValue::Value(elt) => {
if elt.is_null() {
DatumCategoryOwned::Null
} else {
match elt.ion_type() {
IonType::List => DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self)),
IonType::SExp => DatumCategoryOwned::Sequence(DatumSeqOwned::Dynamic(self)),
IonType::Null => DatumCategoryOwned::Null,
IonType::Struct => {
DatumCategoryOwned::Tuple(DatumTupleOwned::Dynamic(self))
}
_ => DatumCategoryOwned::Scalar(DatumValueOwned::Value(self.into_value())),
}
}
}
}
}
}

impl PartialEq<Self> for BoxedIon {
fn eq(&self, other: &Self) -> bool {
self.doc.eq(&other.doc)
}
}

impl Eq for BoxedIon {}

impl PartialOrd for BoxedIon {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for BoxedIon {
fn cmp(&self, other: &Self) -> Ordering {
// TODO lowering just to compare is costly... Either find a better way, or lift this out of the extension
self.lower().unwrap().cmp(&other.lower().unwrap())
}
}

impl DatumLower<Value> for BoxedIon {
fn into_lower(self) -> DatumLowerResult<Value> {
let Self { ctx, doc } = self;
match doc {
let pval = match doc {
BoxedIonValue::Stream() => todo!("into_lower stream"),
BoxedIonValue::Sequence(_) => todo!("into_lower seq"),
BoxedIonValue::Value(elt) => {
let pval = elt.into_partiql_value()?;
Ok(match pval {
PartiqlValueTarget::Atom(val) => val,
PartiqlValueTarget::List(l) => {
let vals = l.into_iter().map(|elt| Self::new_value(elt, ctx.clone()));
List::from_iter(vals).into()
}
PartiqlValueTarget::Bag(b) => {
let vals = b.into_iter().map(|elt| Self::new_value(elt, ctx.clone()));
Bag::from_iter(vals).into()
}
PartiqlValueTarget::Struct(s) => {
let vals = s
.into_iter()
.map(|(key, elt)| (key, Self::new_value(elt, ctx.clone())));
Tuple::from_iter(vals).into()
}
})
BoxedIonValue::Sequence(seq) => seq.into_partiql_value()?,
BoxedIonValue::Value(elt) => elt.into_partiql_value()?,
};
Ok(match pval {
PartiqlValueTarget::Atom(val) => val,
PartiqlValueTarget::List(l) => {
let vals = l.into_iter().map(|elt| Self::new_value(elt, ctx.clone()));
List::from_iter(vals).into()
}
}
PartiqlValueTarget::Bag(b) => {
let vals = b.into_iter().map(|elt| Self::new_value(elt, ctx.clone()));
Bag::from_iter(vals).into()
}
PartiqlValueTarget::Struct(s) => {
let vals = s
.into_iter()
.map(|(key, elt)| (key, Self::new_value(elt, ctx.clone())));
Tuple::from_iter(vals).into()
}
})
}

fn into_lower_boxed(self: Box<Self>) -> DatumLowerResult<Value> {
Expand Down Expand Up @@ -307,7 +377,7 @@
}

impl OwnedTupleView<Value> for BoxedIon {
fn take_val(self, k: &BindingsName<'_>) -> Option<Value> {
fn take_val(self, _k: &BindingsName<'_>) -> Option<Value> {
todo!()
}

Expand Down Expand Up @@ -355,13 +425,13 @@
Value::from(Variant::from(self))
}

pub fn new(doc: impl Into<BoxedIonValue>, ctx: IonContextPtr) -> Self {

Check warning on line 428 in extension/partiql-extension-ion/src/boxed_ion.rs

View workflow job for this annotation

GitHub Actions / clippy

type `boxed_ion::IonContext` is more private than the item `boxed_ion::BoxedIon::new`

warning: type `boxed_ion::IonContext` is more private than the item `boxed_ion::BoxedIon::new` --> extension/partiql-extension-ion/src/boxed_ion.rs:428:5 | 428 | pub fn new(doc: impl Into<BoxedIonValue>, ctx: IonContextPtr) -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `boxed_ion::BoxedIon::new` is reachable at visibility `pub` | note: but type `boxed_ion::IonContext` is only usable at visibility `pub(self)` --> extension/partiql-extension-ion/src/boxed_ion.rs:96:1 | 96 | struct IonContext { | ^^^^^^^^^^^^^^^^^

Check warning on line 428 in extension/partiql-extension-ion/src/boxed_ion.rs

View workflow job for this annotation

GitHub Actions / clippy

type `boxed_ion::BoxedIonValue` is more private than the item `boxed_ion::BoxedIon::new`

warning: type `boxed_ion::BoxedIonValue` is more private than the item `boxed_ion::BoxedIon::new` --> extension/partiql-extension-ion/src/boxed_ion.rs:428:5 | 428 | pub fn new(doc: impl Into<BoxedIonValue>, ctx: IonContextPtr) -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `boxed_ion::BoxedIon::new` is reachable at visibility `pub` | note: but type `boxed_ion::BoxedIonValue` is only usable at visibility `pub(self)` --> extension/partiql-extension-ion/src/boxed_ion.rs:528:1 | 528 | enum BoxedIonValue { | ^^^^^^^^^^^^^^^^^^ = note: `#[warn(private_bounds)]` on by default
Self {
ctx,
doc: doc.into(),
}
}
pub fn new_value(doc: impl Into<BoxedIonValue>, ctx: IonContextPtr) -> Value {

Check warning on line 434 in extension/partiql-extension-ion/src/boxed_ion.rs

View workflow job for this annotation

GitHub Actions / clippy

type `boxed_ion::IonContext` is more private than the item `boxed_ion::BoxedIon::new_value`

warning: type `boxed_ion::IonContext` is more private than the item `boxed_ion::BoxedIon::new_value` --> extension/partiql-extension-ion/src/boxed_ion.rs:434:5 | 434 | pub fn new_value(doc: impl Into<BoxedIonValue>, ctx: IonContextPtr) -> Value { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `boxed_ion::BoxedIon::new_value` is reachable at visibility `pub` | note: but type `boxed_ion::IonContext` is only usable at visibility `pub(self)` --> extension/partiql-extension-ion/src/boxed_ion.rs:96:1 | 96 | struct IonContext { | ^^^^^^^^^^^^^^^^^

Check warning on line 434 in extension/partiql-extension-ion/src/boxed_ion.rs

View workflow job for this annotation

GitHub Actions / clippy

type `boxed_ion::BoxedIonValue` is more private than the item `boxed_ion::BoxedIon::new_value`

warning: type `boxed_ion::BoxedIonValue` is more private than the item `boxed_ion::BoxedIon::new_value` --> extension/partiql-extension-ion/src/boxed_ion.rs:434:5 | 434 | pub fn new_value(doc: impl Into<BoxedIonValue>, ctx: IonContextPtr) -> Value { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `boxed_ion::BoxedIon::new_value` is reachable at visibility `pub` | note: but type `boxed_ion::BoxedIonValue` is only usable at visibility `pub(self)` --> extension/partiql-extension-ion/src/boxed_ion.rs:528:1 | 528 | enum BoxedIonValue { | ^^^^^^^^^^^^^^^^^^
Self::new(doc, ctx).into_value()
}

Expand All @@ -376,7 +446,7 @@
self.child(child).into_value()
}

pub fn parse(data: Vec<u8>, expected: BoxedIonStreamType) -> IonResult<Self> {

Check warning on line 449 in extension/partiql-extension-ion/src/boxed_ion.rs

View workflow job for this annotation

GitHub Actions / clippy

type `boxed_ion::BoxedIonStreamType` is more private than the item `boxed_ion::BoxedIon::parse`

warning: type `boxed_ion::BoxedIonStreamType` is more private than the item `boxed_ion::BoxedIon::parse` --> extension/partiql-extension-ion/src/boxed_ion.rs:449:5 | 449 | pub fn parse(data: Vec<u8>, expected: BoxedIonStreamType) -> IonResult<Self> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `boxed_ion::BoxedIon::parse` is reachable at visibility `pub` | note: but type `boxed_ion::BoxedIonStreamType` is only usable at visibility `pub(self)` --> extension/partiql-extension-ion/src/boxed_ion.rs:521:1 | 521 | enum BoxedIonStreamType { | ^^^^^^^^^^^^^^^^^^^^^^^
let mut ctx = IonContext::new_ptr(data)?;
let doc = Self::init_doc(&mut ctx, expected);
Ok(Self::new(doc, ctx))
Expand Down Expand Up @@ -461,6 +531,18 @@
Sequence(Sequence),
}

impl PartialEq<Self> for BoxedIonValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(BoxedIonValue::Value(l), BoxedIonValue::Value(r)) => l == r,
(BoxedIonValue::Sequence(l), BoxedIonValue::Sequence(r)) => l == r,
_ => false,
}
}
}

impl Eq for BoxedIonValue {}

impl From<Element> for BoxedIonValue {
fn from(value: Element) -> Self {
BoxedIonValue::Value(value)
Expand Down
2 changes: 2 additions & 0 deletions extension/partiql-extension-ion/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub enum Encoding {
PartiqlEncodedAsIon,
}

pub(crate) const BOXED_ION_ANNOT: &str = "$ion";

pub(crate) const BAG_ANNOT: &str = "$bag";
pub(crate) const TIME_ANNOT: &str = "$time";
pub(crate) const DATE_ANNOT: &str = "$date";
Expand Down
Loading
Loading