mod ion_data_hash;
mod ion_eq;
mod ion_ord;
use std::cmp::Ordering;
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use std::io::Write;
use std::ops::Deref;
use crate::{Encoding, IonResult, ValueWriter, WriteAsIon, WriteConfig};
pub(crate) use ion_data_hash::{ion_data_hash_bool, ion_data_hash_f64, IonDataHash};
pub(crate) use ion_eq::{ion_eq_bool, ion_eq_f64, IonEq};
pub(crate) use ion_ord::{ion_cmp_bool, ion_cmp_f64, IonDataOrd};
#[derive(Debug, Clone)]
pub struct IonData<T>(T);
impl<T: IonEq> IonData<T> {
pub fn eq<R: Deref<Target = T>>(a: R, b: R) -> bool {
T::ion_eq(a.deref(), b.deref())
}
pub fn into_inner(self) -> T {
self.0
}
}
impl<T: IonEq> PartialEq for IonData<T> {
fn eq(&self, other: &Self) -> bool {
self.0.ion_eq(&other.0)
}
}
impl<T: IonEq> Eq for IonData<T> {}
impl<T: IonEq> From<T> for IonData<T> {
fn from(value: T) -> Self {
IonData(value)
}
}
impl<T: IonEq> AsRef<T> for IonData<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T: Display> Display for IonData<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<T: IonEq + IonDataOrd> PartialOrd for IonData<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: IonEq + IonDataOrd> Ord for IonData<T> {
fn cmp(&self, other: &Self) -> Ordering {
IonDataOrd::ion_cmp(&self.0, &other.0)
}
}
impl<T: IonDataHash> Hash for IonData<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
IonDataHash::ion_data_hash(&self.0, state)
}
}
impl<T: WriteAsIon> WriteAsIon for IonData<T> {
fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
self.0.write_as_ion(writer)
}
fn encode_as<E: Encoding, C: Into<WriteConfig<E>>>(&self, config: C) -> IonResult<E::Output>
where
for<'a> &'a Self: WriteAsIon,
{
self.0.encode_as(config)
}
fn encode_to<E: Encoding, C: Into<WriteConfig<E>>, W: Write>(
&self,
config: C,
output: W,
) -> IonResult<W>
where
for<'a> &'a Self: WriteAsIon,
{
self.0.encode_to(config, output)
}
}
#[cfg(test)]
mod tests {
use crate::ion_data::{IonDataHash, IonDataOrd, IonEq};
use crate::lazy::encoding::TextEncoding_1_0;
use crate::{Element, IonData, Symbol, WriteConfig};
use rstest::*;
use std::boxed::Box;
use std::fmt::Debug;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
#[rstest]
#[case::value(|s| Element::read_one(s).unwrap().value().clone().into())]
#[case::symbol(|s| Symbol::from(s).into())]
#[case::element(|s| Element::read_one(s).unwrap().into() )]
#[case::write_as_ion(|s| Element::read_one(Element::read_one(s).unwrap().encode_as(WriteConfig::<TextEncoding_1_0>::default()).unwrap()).unwrap().into() )]
#[case::rc_element(|s| Rc::new(Element::read_one(s).unwrap()).into() )]
#[case::vec_element(|s| Element::read_all(s).unwrap().into() )]
#[case::rc_vec_element(|s| Rc::new(Element::read_all(s).unwrap()).into() )]
#[case::box_pin_rc_vec_box_arc_element(|s| Box::new(Pin::new(Rc::new(vec![Box::new(Arc::new(Element::read_one(s).unwrap()))]))).into() )]
fn can_wrap_data<T: IonEq + IonDataOrd + IonDataHash + Debug>(
#[case] the_fn: impl Fn(&'static str) -> IonData<T>,
) {
let id1: IonData<_> = the_fn("nan");
let id2: IonData<_> = the_fn("nan");
assert_eq!(id1, id2);
let mut h1 = DefaultHasher::default();
let mut h2 = DefaultHasher::default();
id1.hash(&mut h1);
id2.hash(&mut h2);
assert_eq!(h1.finish(), h2.finish());
let id1: IonData<_> = the_fn("1.00");
let id2: IonData<_> = the_fn("1.0");
assert_ne!(id1, id2); assert!(id1 > id2); }
}