ion_rs/element/
mod.rs

1// Copyright Amazon.com, Inc. or its affiliates.
2
3//! Provides a dynamically typed, materialized representation of an Ion value.
4//!
5//! An [Element](Element) represents an `(annotations, value)` pair, where a `value` is
6//! an Ion `integer`, `float`, `list`, `struct`, etc.
7//!
8//! For reference here are a couple other _value_ style APIs for JSON:
9//! * [`simd_json`'s `Value` API][simd-json-value]
10//! * [`serde_json`'s `Value` API][serde-json-value]
11//!
12//! [simd-json-value]: https://docs.rs/simd-json/latest/simd_json/value/index.html
13//! [serde-json-value]: https://docs.serde.rs/serde_json/value/enum.Value.html
14
15use crate::element::builders::{SequenceBuilder, StructBuilder};
16use crate::element::reader::ElementReader;
17use crate::ion_data::{IonEq, IonOrd};
18use crate::text::text_formatter::IonValueFormatter;
19use crate::{
20    ion_data, BinaryWriterBuilder, Decimal, Int, IonResult, IonType, IonWriter, ReaderBuilder, Str,
21    Symbol, TextWriterBuilder, Timestamp,
22};
23use num_bigint::BigInt;
24use std::cmp::Ordering;
25use std::fmt::{Display, Formatter};
26use std::io;
27
28mod annotations;
29pub mod builders;
30pub mod element_stream_reader;
31pub mod element_stream_writer;
32pub(crate) mod iterators;
33pub mod reader;
34pub mod writer;
35
36// Re-export the Value variant types and traits so they can be accessed directly from this module.
37use crate::element::writer::{ElementWriter, Format, TextKind};
38pub use crate::types::{Blob, Bytes, Clob};
39pub use annotations::{Annotations, IntoAnnotations};
40
41pub use crate::types::{List, SExp, Sequence, Struct};
42
43impl IonEq for Value {
44    fn ion_eq(&self, other: &Self) -> bool {
45        use Value::*;
46        match (self, other) {
47            (Null(this), Null(that)) => this == that,
48            (Bool(this), Bool(that)) => ion_data::ion_eq_bool(this, that),
49            (Int(this), Int(that)) => this.ion_eq(that),
50            (Float(this), Float(that)) => ion_data::ion_eq_f64(this, that),
51            (Decimal(this), Decimal(that)) => this.ion_eq(that),
52            (Timestamp(this), Timestamp(that)) => this.ion_eq(that),
53            (Symbol(this), Symbol(that)) => this.ion_eq(that),
54            (String(this), String(that)) => this.ion_eq(that),
55            (Clob(this), Clob(that)) => this.ion_eq(that),
56            (Blob(this), Blob(that)) => this.ion_eq(that),
57            (List(this), List(that)) => this.ion_eq(that),
58            (SExp(this), SExp(that)) => this.ion_eq(that),
59            (Struct(this), Struct(that)) => this.ion_eq(that),
60            _ => false,
61        }
62    }
63}
64
65impl IonOrd for Value {
66    fn ion_cmp(&self, other: &Self) -> Ordering {
67        use Value::*;
68
69        // First compare Ion types
70        let ord = self.ion_type().ion_cmp(&other.ion_type());
71        if !ord.is_eq() {
72            return ord;
73        }
74
75        macro_rules! compare {
76            ($p:pat => $e:expr) => {
77                match other {
78                    $p => $e,
79                    Null(_) => Ordering::Greater,
80                    _ => unreachable!("We already checked the Ion Type!"),
81                }
82            };
83        }
84
85        match self {
86            Null(_) => {
87                if let Null(_) = other {
88                    Ordering::Equal
89                } else {
90                    Ordering::Less
91                }
92            }
93            Bool(this) => compare!(Bool(that) => ion_data::ion_cmp_bool(this, that)),
94            Int(this) => compare!(Int(that) => this.ion_cmp(that)),
95            Float(this) => compare!(Float(that) => ion_data::ion_cmp_f64(this, that)),
96            Decimal(this) => compare!(Decimal(that) => this.ion_cmp(that)),
97            Timestamp(this) => compare!(Timestamp(that) => this.ion_cmp(that)),
98            Symbol(this) => compare!(Symbol(that) => this.ion_cmp(that)),
99            String(this) => compare!(String(that) => this.ion_cmp(that)),
100            Clob(this) => compare!(Clob(that) => this.ion_cmp(that)),
101            Blob(this) => compare!(Blob(that) => this.ion_cmp(that)),
102            List(this) => compare!(List(that) => this.ion_cmp(that)),
103            SExp(this) => compare!(SExp(that) => this.ion_cmp(that)),
104            Struct(this) => compare!(Struct(that) => this.ion_cmp(that)),
105        }
106    }
107}
108
109/// Variants for all _values_ within an [`Element`].
110#[derive(Debug, Clone, PartialEq)]
111pub enum Value {
112    Null(IonType),
113    Bool(bool),
114    Int(Int),
115    Float(f64),
116    Decimal(Decimal),
117    Timestamp(Timestamp),
118    Symbol(Symbol),
119    String(Str),
120    Clob(Bytes),
121    Blob(Bytes),
122    List(Sequence),
123    SExp(Sequence),
124    Struct(Struct),
125}
126
127impl Value {
128    pub fn ion_type(&self) -> IonType {
129        use Value::*;
130
131        match self {
132            Null(t) => *t,
133            Bool(_) => IonType::Bool,
134            Int(_) => IonType::Int,
135            Float(_) => IonType::Float,
136            Decimal(_) => IonType::Decimal,
137            Timestamp(_) => IonType::Timestamp,
138            Symbol(_) => IonType::Symbol,
139            String(_) => IonType::String,
140            Clob(_) => IonType::Clob,
141            Blob(_) => IonType::Blob,
142            List(_) => IonType::List,
143            SExp(_) => IonType::SExp,
144            Struct(_) => IonType::Struct,
145        }
146    }
147}
148
149impl Display for Value {
150    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
151        let mut ivf = IonValueFormatter { output: f };
152        match &self {
153            Value::Null(ion_type) => ivf.format_null(*ion_type),
154            Value::Bool(bool) => ivf.format_bool(*bool),
155            Value::Int(integer) => ivf.format_integer(integer),
156            Value::Float(float) => ivf.format_float(*float),
157            Value::Decimal(decimal) => ivf.format_decimal(decimal),
158            Value::Timestamp(timestamp) => ivf.format_timestamp(timestamp),
159            Value::Symbol(symbol) => ivf.format_symbol(symbol),
160            Value::String(string) => ivf.format_string(string),
161            Value::Clob(clob) => ivf.format_clob(clob),
162            Value::Blob(blob) => ivf.format_blob(blob),
163            Value::List(sequence) => ivf.format_list(sequence),
164            Value::SExp(sequence) => ivf.format_sexp(sequence),
165            Value::Struct(struct_) => ivf.format_struct(struct_),
166        }
167        .map_err(|_| std::fmt::Error)?;
168
169        Ok(())
170    }
171}
172
173impl From<IonType> for Value {
174    fn from(ion_type: IonType) -> Self {
175        Value::Null(ion_type)
176    }
177}
178
179impl From<i64> for Value {
180    fn from(i64_val: i64) -> Self {
181        Value::Int(Int::I64(i64_val))
182    }
183}
184
185impl From<BigInt> for Value {
186    fn from(big_int_val: BigInt) -> Self {
187        Value::Int(Int::BigInt(big_int_val))
188    }
189}
190
191impl From<Int> for Value {
192    fn from(integer_val: Int) -> Self {
193        Value::Int(integer_val)
194    }
195}
196
197impl From<f64> for Value {
198    fn from(f64_val: f64) -> Self {
199        Value::Float(f64_val)
200    }
201}
202
203impl From<Decimal> for Value {
204    fn from(decimal_val: Decimal) -> Self {
205        Value::Decimal(decimal_val)
206    }
207}
208
209impl From<Timestamp> for Value {
210    fn from(timestamp_val: Timestamp) -> Self {
211        Value::Timestamp(timestamp_val)
212    }
213}
214
215impl From<bool> for Value {
216    fn from(bool_val: bool) -> Self {
217        Value::Bool(bool_val)
218    }
219}
220
221impl From<&str> for Value {
222    fn from(string_val: &str) -> Self {
223        Value::String(string_val.into())
224    }
225}
226
227impl From<String> for Value {
228    fn from(value: String) -> Self {
229        let s: Str = value.into();
230        Value::String(s)
231    }
232}
233
234impl From<Str> for Value {
235    fn from(string_val: Str) -> Self {
236        Value::String(string_val)
237    }
238}
239
240impl From<Symbol> for Value {
241    fn from(sym_val: Symbol) -> Self {
242        Value::Symbol(sym_val)
243    }
244}
245
246impl From<&[u8]> for Value {
247    fn from(value: &[u8]) -> Self {
248        Value::Blob(value.into())
249    }
250}
251
252impl From<Vec<u8>> for Value {
253    fn from(value: Vec<u8>) -> Self {
254        Value::Blob(value.into())
255    }
256}
257
258impl From<Blob> for Value {
259    fn from(blob: Blob) -> Self {
260        let bytes: Bytes = blob.into();
261        Value::Blob(bytes)
262    }
263}
264
265impl From<Clob> for Value {
266    fn from(clob: Clob) -> Self {
267        let bytes: Bytes = clob.into();
268        Value::Clob(bytes)
269    }
270}
271
272impl From<List> for Value {
273    fn from(list: List) -> Self {
274        Value::List(list.into())
275    }
276}
277
278impl From<SExp> for Value {
279    fn from(s_expr: SExp) -> Self {
280        Value::SExp(s_expr.into())
281    }
282}
283
284impl From<Struct> for Value {
285    fn from(struct_val: Struct) -> Self {
286        Value::Struct(struct_val)
287    }
288}
289
290#[cfg(feature = "experimental-streaming")]
291impl From<crate::tokens::ScalarValue> for Value {
292    fn from(value: crate::tokens::ScalarValue) -> Self {
293        use crate::tokens::ScalarValue;
294        match value {
295            ScalarValue::Bool(bool) => Value::Bool(bool),
296            ScalarValue::Int(int) => Value::Int(int),
297            ScalarValue::Float(float) => Value::Float(float),
298            ScalarValue::Decimal(decimal) => Value::Decimal(decimal),
299            ScalarValue::Timestamp(timestamp) => Value::Timestamp(timestamp),
300            ScalarValue::String(text) => Value::String(text),
301            ScalarValue::Symbol(symbol) => Value::Symbol(symbol),
302            ScalarValue::Blob(bytes) => Value::Blob(bytes),
303            ScalarValue::Clob(bytes) => Value::Clob(bytes),
304        }
305    }
306}
307
308/// Allows types that can be converted into an Ion [Value] to also specify annotations, producing
309/// an [Element].
310///
311/// ```
312/// use ion_rs::element::{Element, IntoAnnotatedElement, Value};
313/// use ion_rs::ion_list;
314///
315/// // Explicit conversion of a Rust bool (`true`) into a `Value`...
316/// let boolean_value: Value = true.into();
317/// // and then into an `Element`...
318/// let mut boolean_element: Element = boolean_value.into();
319/// // and then adding annotations to the `Element`.
320/// boolean_element = boolean_element.with_annotations(["foo", "bar"]);
321///
322/// // Much more concise equivalent leveraging the `IntoAnnotatedElement` trait.
323/// let boolean_element = true.with_annotations(["foo", "bar"]);
324/// ```
325pub trait IntoAnnotatedElement: Into<Value> {
326    /// Converts the value into an [Element] with the specified annotations.
327    fn with_annotations<I: IntoAnnotations>(self, annotations: I) -> Element {
328        Element::new(annotations.into_annotations(), self.into())
329    }
330}
331
332impl<V> IntoAnnotatedElement for V where V: Into<Value> {}
333
334impl IonEq for Element {
335    fn ion_eq(&self, other: &Self) -> bool {
336        self.annotations == other.annotations && self.value.ion_eq(&other.value)
337    }
338}
339
340// Ordering is done as follows:
341// 1. Ion type -- It is a logical way to group Ion values, and it is the cheapest comparison
342// 2. Annotations -- the vast majority of Ion values have few annotations, so this should usually be cheap
343// 3. Value -- compared using IonOrd
344impl IonOrd for Element {
345    fn ion_cmp(&self, other: &Self) -> Ordering {
346        let ord = self.ion_type().ion_cmp(&other.ion_type());
347        if !ord.is_eq() {
348            return ord;
349        }
350
351        let a1 = self.annotations();
352        let a2 = other.annotations();
353
354        let ord = a1.ion_cmp(a2);
355        if !ord.is_eq() {
356            return ord;
357        }
358
359        let v1 = self.value();
360        let v2 = other.value();
361        v1.ion_cmp(v2)
362    }
363}
364
365/// An `(annotations, value)` pair representing an Ion value.
366#[derive(Debug, Clone)]
367pub struct Element {
368    annotations: Annotations,
369    value: Value,
370}
371
372impl Element {
373    pub(crate) fn new(annotations: Annotations, value: impl Into<Value>) -> Self {
374        Self {
375            annotations,
376            value: value.into(),
377        }
378    }
379
380    /// Returns a reference to this [Element]'s [Value].
381    ///
382    /// ```
383    /// use ion_rs::element::{Element, Value};
384    /// let element: Element = true.into();
385    /// if let Value::Bool(b) = element.value() {
386    ///     println!("It was a boolean: {b}");
387    /// } else {
388    ///     println!("It was something else.");
389    /// }
390    /// ```
391    pub fn value(&self) -> &Value {
392        &self.value
393    }
394
395    pub fn null(null_type: IonType) -> Element {
396        null_type.into()
397    }
398
399    pub fn boolean(value: bool) -> Element {
400        value.into()
401    }
402
403    pub fn string<I: Into<Str>>(str: I) -> Element {
404        let text: Str = str.into();
405        text.into()
406    }
407
408    pub fn symbol<I: Into<Symbol>>(symbol: I) -> Element {
409        let symbol: Symbol = symbol.into();
410        symbol.into()
411    }
412
413    pub fn integer<I: Into<Int>>(integer: I) -> Element {
414        let integer: Int = integer.into();
415        integer.into()
416    }
417
418    pub fn decimal(decimal: Decimal) -> Element {
419        decimal.into()
420    }
421
422    pub fn timestamp(timestamp: Timestamp) -> Element {
423        timestamp.into()
424    }
425
426    pub fn float(float: f64) -> Element {
427        float.into()
428    }
429
430    pub fn clob<A: AsRef<[u8]>>(bytes: A) -> Element {
431        let bytes: &[u8] = bytes.as_ref();
432        Value::Clob(bytes.into()).into()
433    }
434
435    pub fn blob<A: AsRef<[u8]>>(bytes: A) -> Element {
436        let bytes: &[u8] = bytes.as_ref();
437        Value::Blob(bytes.into()).into()
438    }
439
440    pub fn sequence_builder() -> SequenceBuilder {
441        Sequence::builder()
442    }
443
444    pub fn struct_builder() -> StructBuilder {
445        Struct::builder()
446    }
447
448    pub fn ion_type(&self) -> IonType {
449        self.value.ion_type()
450    }
451
452    pub fn annotations(&self) -> &Annotations {
453        &self.annotations
454    }
455
456    pub fn with_annotations<I: IntoAnnotations>(self, annotations: I) -> Self {
457        Element::new(annotations.into_annotations(), self.value)
458    }
459
460    pub fn is_null(&self) -> bool {
461        matches!(&self.value, Value::Null(_))
462    }
463
464    pub fn as_int(&self) -> Option<&Int> {
465        match &self.value {
466            Value::Int(i) => Some(i),
467            _ => None,
468        }
469    }
470
471    pub fn as_float(&self) -> Option<f64> {
472        match &self.value {
473            Value::Float(f) => Some(*f),
474            _ => None,
475        }
476    }
477
478    pub fn as_decimal(&self) -> Option<&Decimal> {
479        match &self.value {
480            Value::Decimal(d) => Some(d),
481            _ => None,
482        }
483    }
484
485    pub fn as_timestamp(&self) -> Option<&Timestamp> {
486        match &self.value {
487            Value::Timestamp(t) => Some(t),
488            _ => None,
489        }
490    }
491
492    pub fn as_text(&self) -> Option<&str> {
493        match &self.value {
494            Value::String(text) => Some(text.as_ref()),
495            Value::Symbol(sym) => sym.text(),
496            _ => None,
497        }
498    }
499
500    pub fn as_string(&self) -> Option<&str> {
501        match &self.value {
502            Value::String(text) => Some(text.as_ref()),
503            _ => None,
504        }
505    }
506
507    pub fn as_symbol(&self) -> Option<&Symbol> {
508        match &self.value {
509            Value::Symbol(sym) => Some(sym),
510            _ => None,
511        }
512    }
513
514    pub fn as_bool(&self) -> Option<bool> {
515        match &self.value {
516            Value::Bool(b) => Some(*b),
517            _ => None,
518        }
519    }
520
521    pub fn as_lob(&self) -> Option<&[u8]> {
522        match &self.value {
523            Value::Blob(bytes) | Value::Clob(bytes) => Some(bytes.as_ref()),
524            _ => None,
525        }
526    }
527
528    pub fn as_blob(&self) -> Option<&[u8]> {
529        match &self.value {
530            Value::Blob(bytes) => Some(bytes.as_ref()),
531            _ => None,
532        }
533    }
534
535    pub fn as_clob(&self) -> Option<&[u8]> {
536        match &self.value {
537            Value::Clob(bytes) => Some(bytes.as_ref()),
538            _ => None,
539        }
540    }
541
542    pub fn as_sequence(&self) -> Option<&Sequence> {
543        match &self.value {
544            Value::SExp(s) | Value::List(s) => Some(s),
545            _ => None,
546        }
547    }
548
549    pub fn as_struct(&self) -> Option<&Struct> {
550        match &self.value {
551            Value::Struct(structure) => Some(structure),
552            _ => None,
553        }
554    }
555
556    /// Reads a single Ion [`Element`] from the provided data source.
557    ///
558    /// If the data source is empty, returns `Ok(None)`.
559    /// If the data source has at least one value, returns `Ok(Some(Element))`.
560    /// If the data source has invalid data, returns `Err`.
561    pub fn read_first<A: AsRef<[u8]>>(data: A) -> IonResult<Option<Element>> {
562        let bytes: &[u8] = data.as_ref();
563        // Create an iterator over the Elements in the data
564        let mut reader = ReaderBuilder::default().build(bytes)?;
565        reader.read_next_element()
566    }
567
568    /// Reads a single Ion [`Element`] from the provided data source. If the input has invalid
569    /// data or does not contain at exactly one Ion value, returns `Err(IonError)`.
570    pub fn read_one<A: AsRef<[u8]>>(data: A) -> IonResult<Element> {
571        let bytes: &[u8] = data.as_ref();
572        // Create an iterator over the Elements in the data
573        let mut reader = ReaderBuilder::default().build(bytes)?;
574        reader.read_one_element()
575    }
576
577    /// Reads all available [`Element`]s from the provided data source.
578    ///
579    /// If the input has valid data, returns `Ok(Vec<Element>)`.
580    /// If the input has invalid data, returns `Err(IonError)`.
581    pub fn read_all<A: AsRef<[u8]>>(data: A) -> IonResult<Vec<Element>> {
582        let bytes: &[u8] = data.as_ref();
583        ReaderBuilder::default().build(bytes)?.elements().collect()
584    }
585
586    /// Serializes this element to the provided writer.
587    ///
588    /// ```
589    ///# use ion_rs::IonResult;
590    ///# fn main() -> IonResult<()> {
591    /// use ion_rs::element::Element;
592    /// use ion_rs::{ion_list, IonType, IonWriter, TextWriterBuilder};
593    ///
594    /// // Construct an Element
595    /// let element_before: Element = ion_list! [1, 2, 3].into();
596    ///
597    /// // Serialize the Element to a writer
598    /// let mut writer = TextWriterBuilder::default().build(Vec::new())?;
599    /// element_before.write_to(&mut writer)?;
600    /// writer.flush()?;
601    ///
602    /// // Read the Element back from the serialized form
603    /// let element_after = Element::read_one(writer.output())?;
604    ///
605    /// // Confirm that no data was lost
606    /// assert_eq!(element_before, element_after);
607    ///# Ok(())
608    ///# }
609    /// ```
610    pub fn write_to<W: ElementWriter>(&self, writer: &mut W) -> IonResult<()> {
611        writer.write_element(self)?;
612        Ok(())
613    }
614
615    /// Serializes this [`Element`] as Ion, writing the resulting bytes to the provided [`io::Write`].
616    /// The caller must verify that `output` is either empty or only contains Ion of the same
617    /// format (text or binary) before writing begins.
618    ///
619    /// This method constructs a new writer for each invocation, which means that there will only be a single
620    /// top level value in the output stream. Writing several values to the same stream is preferable to
621    /// maximize encoding efficiency. To reuse a writer and have greater control over resource
622    /// management, see [`Element::write_to`].
623    /// ```
624    ///# use ion_rs::IonResult;
625    ///# fn main() -> IonResult<()> {
626    /// use ion_rs::element::Element;
627    /// use ion_rs::{ion_list, IonType, IonWriter, TextWriterBuilder};
628    /// use ion_rs::element::writer::{Format, TextKind};
629    ///
630    /// // Construct an Element
631    /// let element_before: Element = ion_list! [1, 2, 3].into();
632    ///
633    /// // Write the Element to a buffer using a specified format
634    /// let mut buffer = Vec::new();
635    /// element_before.write_as(Format::Text(TextKind::Pretty), &mut buffer)?;
636    ///
637    /// // Read the Element back from the serialized form
638    /// let element_after = Element::read_one(&buffer)?;
639    ///
640    /// // Confirm that no data was lost
641    /// assert_eq!(element_before, element_after);
642    ///# Ok(())
643    ///# }
644    /// ```
645    pub fn write_as<W: io::Write>(&self, format: Format, output: W) -> IonResult<()> {
646        match format {
647            Format::Text(text_kind) => {
648                let mut text_writer = TextWriterBuilder::new(text_kind).build(output)?;
649                self.write_to(&mut text_writer)?;
650                text_writer.flush()
651            }
652            Format::Binary => {
653                let mut binary_writer = BinaryWriterBuilder::default().build(output)?;
654                self.write_to(&mut binary_writer)?;
655                binary_writer.flush()
656            }
657        }
658    }
659
660    /// Serializes this [`Element`] as binary Ion, returning the output as a `Vec<u8>`.
661    ///
662    /// This is a convenience method; it is less efficient than [`Element::write_to`] because:
663    /// 1. It must allocate a new `Vec<u8>` to fill and return.
664    /// 2. It encodes this [`Element`] as its own binary Ion stream, limiting the benefit of the
665    ///    symbol table.
666    ///
667    /// ```
668    ///# use ion_rs::IonResult;
669    ///# fn main() -> IonResult<()> {
670    /// use ion_rs::element::Element;
671    /// use ion_rs::{ion_list, IonType, IonWriter, TextWriterBuilder};
672    /// use ion_rs::element::writer::{Format, TextKind};
673    ///
674    /// // Construct an Element
675    /// let element_before: Element = ion_list! [1, 2, 3].into();
676    ///
677    /// // Write the Element to a buffer as binary Ion
678    /// let binary_ion: Vec<u8> = element_before.to_binary()?;
679    ///
680    /// // Read the Element back from the serialized form
681    /// let element_after = Element::read_one(&binary_ion)?;
682    ///
683    /// // Confirm that no data was lost
684    /// assert_eq!(element_before, element_after);
685    ///# Ok(())
686    ///# }
687    /// ```
688    pub fn to_binary(&self) -> IonResult<Vec<u8>> {
689        let mut buffer = Vec::new();
690        self.write_as(Format::Binary, &mut buffer)?;
691        Ok(buffer)
692    }
693
694    /// Serializes this [`Element`] as text Ion using the requested [`TextKind`] and returning the
695    /// output as a `String`.
696    ///
697    /// This is a convenience method; to provide your own buffer instead of allocating a `String`
698    /// on each call, see [`Element::write_as`]. To provide your own writer instead of constructing
699    /// a new `String` and writer on each call, see [`Element::write_to`].
700    ///
701    /// ```
702    ///# use ion_rs::IonResult;
703    ///# fn main() -> IonResult<()> {
704    /// use ion_rs::element::Element;
705    /// use ion_rs::{ion_list, IonType, IonWriter, TextWriterBuilder};
706    /// use ion_rs::element::writer::{Format, TextKind};
707    ///
708    /// // Construct an Element
709    /// let element_before: Element = ion_list! [1, 2, 3].into();
710    ///
711    /// let text_ion: String = element_before.to_text(TextKind::Pretty)?;
712    ///
713    /// // Read the Element back from the serialized form
714    /// let element_after = Element::read_one(&text_ion)?;
715    ///
716    /// // Confirm that no data was lost
717    /// assert_eq!(element_before, element_after);
718    ///# Ok(())
719    ///# }
720    /// ```
721    pub fn to_text(&self, text_kind: TextKind) -> IonResult<String> {
722        let mut buffer = Vec::new();
723        self.write_as(Format::Text(text_kind), &mut buffer)?;
724        Ok(std::str::from_utf8(&buffer)
725            .expect("writer produced invalid utf-8")
726            .to_string())
727    }
728}
729
730impl Display for Element {
731    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
732        let mut ivf = IonValueFormatter { output: f };
733
734        // display for annotations of this element
735        ivf.format_annotations(&self.annotations)
736            .map_err(|_| std::fmt::Error)?;
737
738        self.value.fmt(f)
739    }
740}
741
742impl PartialEq for Element {
743    fn eq(&self, other: &Self) -> bool {
744        self.value == other.value && self.annotations == other.annotations
745    }
746}
747
748impl Eq for Element {}
749
750// This implementation allows APIs that require an Into<Element> to accept references to an existing
751// Element.
752impl<'a> From<&'a Element> for Element {
753    fn from(element: &'a Element) -> Self {
754        element.clone()
755    }
756}
757
758// Anything that can be turned into a `Value` can then be turned into an `Element`
759// by associating it with an empty annotations sequence.
760impl<T> From<T> for Element
761where
762    T: Into<Value>,
763{
764    fn from(value: T) -> Self {
765        Element::new(Annotations::empty(), value.into())
766    }
767}
768
769#[cfg(test)]
770mod tests {
771    use crate::element::annotations::IntoAnnotations;
772    use crate::types::Timestamp;
773    use crate::{ion_list, ion_sexp, ion_struct, Decimal, Int, IonType, Symbol};
774    use chrono::*;
775    use rstest::*;
776    use std::iter::{once, Once};
777
778    /// Makes a timestamp from an RFC-3339 string and panics if it can't
779    fn make_timestamp<T: AsRef<str>>(text: T) -> Timestamp {
780        DateTime::parse_from_rfc3339(text.as_ref()).unwrap().into()
781    }
782
783    struct CaseAnnotations {
784        elem: Element,
785        annotations: Annotations,
786    }
787
788    fn annotations_text_case() -> CaseAnnotations {
789        CaseAnnotations {
790            elem: 10i64.with_annotations(["foo", "bar", "baz"]),
791            annotations: ["foo", "bar", "baz"].into_annotations(),
792        }
793    }
794
795    fn no_annotations_case() -> CaseAnnotations {
796        CaseAnnotations {
797            elem: 10i64.into(),
798            annotations: Annotations::empty(),
799        }
800    }
801
802    #[rstest]
803    #[case::annotations_text(annotations_text_case())]
804    #[case::no_annotations(no_annotations_case())]
805    fn annotations_with_element(#[case] input: CaseAnnotations) {
806        let actual: &Annotations = input.elem.annotations();
807        let expected: &Annotations = &input.annotations;
808        assert_eq!(actual, expected);
809    }
810
811    struct CaseSym {
812        eq_annotations: Vec<Symbol>,
813        ne_annotations: Vec<Symbol>,
814    }
815
816    fn sym_text_case() -> CaseSym {
817        // SymbolTokens with same text are equivalent
818        CaseSym {
819            eq_annotations: vec![Symbol::owned("foo"), Symbol::owned("foo")],
820            // These are not equal to any of the ones in `eq_annotations` above
821            ne_annotations: vec![Symbol::owned("bar"), Symbol::owned("baz")],
822        }
823    }
824
825    /// Each case is a set of tokens that are the same, and a set of tokens that are not ever equal to the first.
826    /// This should test symmetry/transitivity/commutativity
827    #[rstest]
828    #[case::owned_sym_text(sym_text_case())]
829    fn symbol_token_eq(#[case] input: CaseSym) {
830        // check if equivalent vector contains set of tokens that are all equal
831        for eq_this_token in &input.eq_annotations {
832            for eq_other_token in &input.eq_annotations {
833                assert_eq!(eq_this_token, eq_other_token);
834            }
835        }
836
837        // check if non_equivalent vector contains a set of tokens that are not ever equal
838        // to the equivalent set tokens.
839        for eq_token in &input.eq_annotations {
840            for non_eq_token in &input.ne_annotations {
841                assert_ne!(eq_token, non_eq_token);
842            }
843        }
844    }
845
846    /// A struct that defines input case for `struct_accessors` method
847    struct CaseStruct {
848        /// set of struct elements that are the same
849        eq_elements: Vec<Element>,
850        /// set of struct elements that are never equal to `eq_annotations`
851        ne_elements: Vec<Element>,
852    }
853
854    /// A convenience method for constructing a Vec<Element> from a collection of
855    /// homogeneously typed values that implement Into<Element>.
856    fn ion_vec<E: Into<Element>, I: IntoIterator<Item = E>>(values: I) -> Vec<Element> {
857        values.into_iter().map(|v| v.into()).collect()
858    }
859
860    fn struct_with_multiple_fields_case() -> CaseStruct {
861        CaseStruct {
862            eq_elements: ion_vec([
863                // structs with different order of fields
864                ion_struct! {
865                    "greetings": "hello",
866                    "name": "Ion"
867                },
868                ion_struct! {
869                    "name": "Ion",
870                    "greetings": "hello"
871                },
872            ]),
873            ne_elements: ion_vec([
874                // structs with different length and duplicates
875                ion_struct! {
876                    "greetings": "hello",
877                    "name": "Ion",
878                    "greetings": "hello"
879                },
880                // structs with different fields length and duplicates
881                ion_struct! {
882                    "greetings": "hello",
883                    "name": "Ion",
884                    "greetings": "bye"
885                },
886                // structs with different fields length
887                ion_struct! {
888                    "greetings": "hello",
889                    "name": "Ion",
890                    "message": "bye"
891                },
892            ]),
893        }
894    }
895
896    fn struct_with_duplicates_in_multiple_fields_case() -> CaseStruct {
897        CaseStruct {
898            // Structs are bags of (field, value) pairs, order is irrelevant
899            eq_elements: ion_vec([
900                ion_struct! {
901                    "a" : 2i64,
902                    "a" : 2i64,
903                    "a" : 1i64
904                },
905                ion_struct! {
906                    "a" : 2i64,
907                    "a" : 1i64,
908                    "a" : 2i64
909                },
910                ion_struct! {
911                    "a" : 1i64,
912                    "a" : 2i64,
913                    "a" : 2i64
914                },
915            ]),
916            ne_elements: ion_vec([
917                // structs with different length
918                ion_struct! {
919                    "a" : 1i64,
920                    "a" : 2i64
921                },
922                // structs with annotated values
923                ion_struct! {
924                    "a" : 2i64,
925                    "a" : 1i64.with_annotations(["a"]),
926                    "a" : 2i64
927                },
928                // structs with different value for duplicates
929                ion_struct! {
930                    "a" : 2i64,
931                    "a" : 3i64,
932                    "a" : 2i64
933                },
934            ]),
935        }
936    }
937
938    fn struct_with_duplicate_fieldnames_case() -> CaseStruct {
939        CaseStruct {
940            eq_elements: ion_vec([
941                // structs with unordered fields
942                ion_struct! {
943                    "greetings" : "world",
944                    "greetings" : "hello"
945                },
946                ion_struct! {
947                    "greetings" : "world",
948                    "greetings" : "hello"
949                },
950            ]),
951            ne_elements: ion_vec([
952                // structs with different length and duplicates
953                ion_struct! {
954                    "greetings" : "world",
955                    "greetings" : "hello",
956                    "greetings" : "hey"
957                },
958                // structs with annotated values
959                ion_struct! {
960                    "greetings" : "world",
961                    "greetings" : "hello".with_annotations(["foo"])
962                },
963                // structs with different length
964                ion_struct! {
965                    "greetings" : "world",
966                    "greetings" : "hello",
967                    "name" : "hello"
968                },
969            ]),
970        }
971    }
972
973    #[rstest]
974    #[case::owned_struct_with_multiple_fields(struct_with_multiple_fields_case())]
975    #[case::owned_struct_with_duplicates_in_multiple_fields(
976        struct_with_duplicates_in_multiple_fields_case()
977    )]
978    #[case::owned_struct_with_duplicate_fieldnames(struct_with_duplicate_fieldnames_case())]
979    fn struct_accessors(#[case] input: CaseStruct) {
980        // check if equivalent vector contains set of structs that are all equal
981        for eq_this_struct in &input.eq_elements {
982            for eq_other_struct in &input.eq_elements {
983                assert_eq!(eq_this_struct, eq_other_struct);
984            }
985        }
986
987        // check if non_equivalent vector contains a set of structs that are not ever equal
988        // to the equivalent set structs.
989        for eq_struct in &input.eq_elements {
990            for non_eq_struct in &input.ne_elements {
991                assert_ne!(eq_struct, non_eq_struct);
992            }
993        }
994    }
995
996    /// Models the operations on `Element` that we want to test.
997    #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
998    enum ElemOp {
999        IsNull,
1000        AsBool,
1001        AsAnyInt,
1002        AsF64,
1003        AsDecimal,
1004        AsTimestamp,
1005        AsStr,
1006        AsSym,
1007        AsBytes,
1008        AsSequence,
1009        AsStruct,
1010    }
1011
1012    impl IntoIterator for ElemOp {
1013        type Item = ElemOp;
1014        type IntoIter = <Once<ElemOp> as IntoIterator>::IntoIter;
1015
1016        fn into_iter(self) -> Self::IntoIter {
1017            once(self)
1018        }
1019    }
1020
1021    use crate::element::{Annotations, Element, IntoAnnotatedElement, Struct};
1022    use crate::types::IntAccess;
1023    use num_bigint::BigInt;
1024    use std::collections::HashSet;
1025    use std::str::FromStr;
1026    use ElemOp::*;
1027
1028    type ElemAssertFn = Box<dyn FnOnce(&Element)>;
1029
1030    struct Case {
1031        elem: Element,
1032        ion_type: IonType,
1033        ops: Vec<ElemOp>,
1034        op_assert: ElemAssertFn,
1035    }
1036
1037    fn null_case() -> Case {
1038        Case {
1039            elem: Element::from(IonType::Null), // null.null
1040            ion_type: IonType::Null,
1041            ops: vec![IsNull],
1042            op_assert: Box::new(|e: &Element| assert!(e.is_null())),
1043        }
1044    }
1045
1046    fn bool_case() -> Case {
1047        Case {
1048            elem: true.into(),
1049            ion_type: IonType::Bool,
1050            ops: vec![AsBool],
1051            op_assert: Box::new(|e: &Element| {
1052                let expected = Element::from(true);
1053                assert_eq!(Some(true), e.as_bool());
1054                assert_eq!(&expected, e);
1055            }),
1056        }
1057    }
1058
1059    fn i64_case() -> Case {
1060        Case {
1061            elem: 100.into(),
1062            ion_type: IonType::Int,
1063            ops: vec![AsAnyInt],
1064            op_assert: Box::new(|e: &Element| {
1065                let expected: Element = 100i64.into();
1066                assert_eq!(Some(&Int::I64(100)), e.as_int());
1067                assert_eq!(Some(100), e.as_i64());
1068                assert_eq!(None, e.as_big_int());
1069                assert_eq!(&expected, e);
1070            }),
1071        }
1072    }
1073
1074    fn big_int_case() -> Case {
1075        Case {
1076            elem: BigInt::from(100).into(),
1077            ion_type: IonType::Int,
1078            ops: vec![AsAnyInt],
1079            op_assert: Box::new(|e: &Element| {
1080                let expected: Element = BigInt::from(100).into();
1081                assert_eq!(Some(&Int::BigInt(BigInt::from(100))), e.as_int());
1082                assert_eq!(BigInt::from_str("100").unwrap(), *e.as_big_int().unwrap());
1083                assert_eq!(&expected, e);
1084            }),
1085        }
1086    }
1087
1088    fn f64_case() -> Case {
1089        Case {
1090            elem: 16.0.into(),
1091            ion_type: IonType::Float,
1092            ops: vec![AsF64],
1093            op_assert: Box::new(|e: &Element| {
1094                let expected = Element::from(16.0f64);
1095                assert_eq!(Some(16.0), e.as_float());
1096                assert_eq!(&expected, e);
1097            }),
1098        }
1099    }
1100
1101    fn timestamp_case() -> Case {
1102        Case {
1103            elem: make_timestamp("2014-10-16T12:01:00-00:00").into(),
1104            ion_type: IonType::Timestamp,
1105            ops: vec![AsTimestamp],
1106            op_assert: Box::new(|e: &Element| {
1107                let expected: Element = make_timestamp("2014-10-16T12:01:00+00:00").into();
1108                assert_eq!(
1109                    Some(&make_timestamp("2014-10-16T12:01:00+00:00")),
1110                    e.as_timestamp()
1111                );
1112                assert_eq!(&expected, e);
1113            }),
1114        }
1115    }
1116
1117    fn decimal_case() -> Case {
1118        Case {
1119            elem: Decimal::new(8, 3).into(),
1120            ion_type: IonType::Decimal,
1121            ops: vec![AsDecimal],
1122            op_assert: Box::new(|e: &Element| {
1123                let expected: Element = Decimal::new(8, 3).into();
1124                assert_eq!(Some(&Decimal::new(80, 2)), e.as_decimal());
1125                assert_eq!(&expected, e);
1126            }),
1127        }
1128    }
1129
1130    fn string_case() -> Case {
1131        Case {
1132            elem: "hello".into(),
1133            ion_type: IonType::String,
1134            ops: vec![AsStr],
1135            op_assert: Box::new(|e: &Element| assert_eq!(Some("hello"), e.as_text())),
1136        }
1137    }
1138
1139    fn symbol_case() -> Case {
1140        Case {
1141            elem: Symbol::owned("foo").into(),
1142            ion_type: IonType::Symbol,
1143            ops: vec![AsSym, AsStr],
1144            op_assert: Box::new(|e: &Element| {
1145                assert_eq!(Some("foo"), e.as_symbol().unwrap().text());
1146                assert_eq!(Some("foo"), e.as_text());
1147            }),
1148        }
1149    }
1150
1151    fn blob_case() -> Case {
1152        Case {
1153            elem: Element::blob(b"hello"),
1154            ion_type: IonType::Blob,
1155            ops: vec![AsBytes],
1156            op_assert: Box::new(|e: &Element| assert_eq!(Some("hello".as_bytes()), e.as_lob())),
1157        }
1158    }
1159
1160    fn clob_case() -> Case {
1161        Case {
1162            elem: Element::clob(b"goodbye"),
1163            ion_type: IonType::Clob,
1164            ops: vec![AsBytes],
1165            op_assert: Box::new(|e: &Element| assert_eq!(Some("goodbye".as_bytes()), e.as_lob())),
1166        }
1167    }
1168
1169    fn list_case() -> Case {
1170        Case {
1171            elem: ion_list![true, false].into(),
1172            ion_type: IonType::List,
1173            ops: vec![AsSequence],
1174            op_assert: Box::new(|e: &Element| {
1175                let actual = e.as_sequence().unwrap();
1176                let expected: Vec<Element> = ion_vec([true, false]);
1177                // assert the length of list
1178                assert_eq!(2, actual.len());
1179                for (i, actual_item) in actual.elements().enumerate() {
1180                    // assert the list elements one-by-one
1181                    assert_eq!(&expected[i], actual_item);
1182                }
1183                assert!(!actual.is_empty());
1184            }),
1185        }
1186    }
1187
1188    fn sexp_case() -> Case {
1189        Case {
1190            elem: ion_sexp!(true false).into(),
1191            ion_type: IonType::SExp,
1192            ops: vec![AsSequence],
1193            op_assert: Box::new(|e: &Element| {
1194                let actual = e.as_sequence().unwrap();
1195                let expected: Vec<Element> = ion_vec([true, false]);
1196                // assert the length of s-expression
1197                assert_eq!(2, actual.len());
1198                for (i, actual_item) in actual.elements().enumerate() {
1199                    // assert the s-expression elements one-by-one
1200                    assert_eq!(&expected[i], actual_item);
1201                }
1202            }),
1203        }
1204    }
1205
1206    fn struct_case() -> Case {
1207        Case {
1208            elem: ion_struct! {"greetings": "hello", "name": "ion"}.into(),
1209            ion_type: IonType::Struct,
1210            ops: vec![AsStruct],
1211            op_assert: Box::new(|e: &Element| {
1212                let actual: &Struct = e.as_struct().unwrap();
1213
1214                // verify that the field order is maintained when creating Struct
1215                assert_eq!(
1216                    actual.iter().next(),
1217                    Some((&"greetings".into(), &"hello".into()))
1218                );
1219
1220                assert_eq!(actual.get("greetings"), Some(&"hello".into()));
1221            }),
1222        }
1223    }
1224    // TODO add more tests to remove the separate Owned/Borrowed tests and only keep generic tests
1225
1226    #[rstest]
1227    #[case::owned_null(null_case())]
1228    #[case::owned_bool(bool_case())]
1229    #[case::owned_i64(i64_case())]
1230    #[case::owned_big_int(big_int_case())]
1231    #[case::owned_f64(f64_case())]
1232    #[case::owned_decimal(decimal_case())]
1233    #[case::owned_timestamp(timestamp_case())]
1234    #[case::owned_string(string_case())]
1235    #[case::owned_blob(blob_case())]
1236    #[case::owned_clob(clob_case())]
1237    #[case::owned_list(list_case())]
1238    #[case::owned_sexp(sexp_case())]
1239    #[case::owned_struct(struct_case())]
1240    #[case::owned_symbol(symbol_case())]
1241    fn element_accessors(#[case] input_case: Case) {
1242        // table of negative assertions for each operation
1243        let neg_table: Vec<(ElemOp, ElemAssertFn)> = vec![
1244            (IsNull, Box::new(|e| assert!(!e.is_null()))),
1245            (AsBool, Box::new(|e| assert_eq!(None, e.as_bool()))),
1246            (
1247                AsAnyInt,
1248                Box::new(|e| {
1249                    assert_eq!(None, e.as_int());
1250                    assert_eq!(None, e.as_i64());
1251                    assert_eq!(None, e.as_big_int());
1252                }),
1253            ),
1254            (AsF64, Box::new(|e| assert_eq!(None, e.as_float()))),
1255            (AsDecimal, Box::new(|e| assert_eq!(None, e.as_decimal()))),
1256            (
1257                AsTimestamp,
1258                Box::new(|e| assert_eq!(None, e.as_timestamp())),
1259            ),
1260            (AsStr, Box::new(|e| assert_eq!(None, e.as_text()))),
1261            (AsSym, Box::new(|e| assert_eq!(None, e.as_symbol()))),
1262            (AsBytes, Box::new(|e| assert_eq!(None, e.as_lob()))),
1263            (AsSequence, Box::new(|e| assert!(e.as_sequence().is_none()))),
1264            (AsStruct, Box::new(|e| assert_eq!(None, e.as_struct()))),
1265        ];
1266
1267        // produce the table of assertions to operate on, replacing the one specified by
1268        // the test case
1269        let valid_ops: HashSet<ElemOp> = input_case.ops.into_iter().collect();
1270        let op_assertions: Vec<ElemAssertFn> = neg_table
1271            .into_iter()
1272            .filter(|(op, _)| !valid_ops.contains(op))
1273            .map(|(_, neg_assert)| neg_assert)
1274            .chain(once(input_case.op_assert))
1275            .collect();
1276
1277        // construct an element to test
1278        assert_eq!(input_case.ion_type, input_case.elem.ion_type());
1279
1280        for assert in op_assertions {
1281            assert(&input_case.elem);
1282        }
1283
1284        // assert that an element as-is is equal to itself
1285        // Creating an alias here bypasses clippy's objection to comparing any literal to itself.
1286        let itself = &input_case.elem;
1287        assert_eq!(&input_case.elem, itself);
1288    }
1289}
1290
1291#[cfg(test)]
1292mod value_tests {
1293    use crate::element::*;
1294    use crate::ion_data::IonEq;
1295    use crate::{ion_list, ion_sexp, ion_struct, IonType};
1296    use rstest::*;
1297
1298    #[test]
1299    fn demonstrate_element_implements_send() {
1300        use std::thread;
1301        // The Element type must implement `Send` in order for values to be
1302        // moved between threads. If changes are made to the `Element` type
1303        // or its nested field types (like the `Value` enum and its variants)
1304        // which accidentally cause it not to implement `Send`, then this test
1305        // will fail to compile.
1306        let list: Element = ion_list![1, 2, 3].into();
1307        thread::scope(|_| {
1308            // Move `list` into this scope, demonstrating `Send`
1309            let elements = vec![list];
1310            // Trivial assertion to use `elements`
1311            assert_eq!(elements.len(), 1);
1312        });
1313    }
1314
1315    #[rstest]
1316    #[case::strings(
1317        Element::from("hello"), // An explicitly constructed String Element
1318        "hello"                 // A Rust &str, which implements Into<Element>
1319    )]
1320    #[case::symbols(
1321        Element::from(Symbol::owned("hello")), // An explicitly constructed Symbol Element
1322        Symbol::owned("hello")                 // A Symbol, which implements Into<Element>
1323    )]
1324    #[case::struct_(
1325        ion_struct!{"greetings": "hello"},
1326        Element::read_one(r#"{greetings: "hello"}"#).unwrap()
1327    )]
1328    #[case::strings(
1329        Element::from("hello"), // An explicitly constructed String Element
1330        "hello"                 // A Rust &str, which implements Into<Element>
1331    )]
1332    #[case::symbols(
1333        Element::from(Symbol::owned("hello")), // An explicitly constructed Symbol Element
1334        Symbol::owned("hello")                 // A Symbol, which implements Into<Element>
1335    )]
1336    #[case::struct_(
1337        ion_struct!{"greetings": "hello"},
1338        Element::read_one(r#"{greetings: "hello"}"#).unwrap()
1339    )]
1340    fn owned_element_accessors<E1, E2>(#[case] e1: E1, #[case] e2: E2)
1341    where
1342        E1: Into<Element>,
1343        E2: Into<Element>,
1344    {
1345        // assert that both element construction methods create the same element
1346        assert_eq!(e1.into(), e2.into());
1347    }
1348
1349    #[rstest]
1350    #[case::struct_(ion_struct!{"greetings": "hello", "name": "Ion"}, 2)]
1351    #[case::list(ion_list!["greetings", 5, true], 3)]
1352    #[case::sexp(ion_sexp!(5 true), 2)]
1353    fn owned_container_len_test<I: Into<Element>>(#[case] container: I, #[case] length: usize) {
1354        let container = container.into();
1355        match container.ion_type() {
1356            IonType::List | IonType::SExp => {
1357                // check length for given sequence value
1358                assert_eq!(container.as_sequence().unwrap().len(), length);
1359            }
1360            IonType::Struct => {
1361                // check length for given struct value
1362                assert_eq!(container.as_struct().unwrap().len(), length);
1363            }
1364            _ => {
1365                unreachable!("This test is only for container type elements")
1366            }
1367        }
1368    }
1369
1370    #[rstest]
1371    #[case::struct_(ion_struct!{"greetings": "hello", "name": "Ion"}, false)]
1372    #[case::list(ion_list!["greetings", 5, true], false)]
1373    #[case::list_empty(ion_list![], true)]
1374    #[case::sexp(ion_sexp!(5 true), false)]
1375    #[case::sexp_empty(ion_sexp!(), true)]
1376    fn owned_container_is_empty_test<I: Into<Element>>(
1377        #[case] container: I,
1378        #[case] is_empty: bool,
1379    ) {
1380        let container = container.into();
1381        match container.ion_type() {
1382            IonType::List | IonType::SExp => {
1383                // check length for given sequence value
1384                assert_eq!(container.as_sequence().unwrap().is_empty(), is_empty);
1385            }
1386            IonType::Struct => {
1387                // check length for given struct value
1388                assert_eq!(container.as_struct().unwrap().is_empty(), is_empty);
1389            }
1390            _ => {
1391                unreachable!("This test is only for container type elements")
1392            }
1393        }
1394    }
1395
1396    #[test]
1397    fn list_display_roundtrip() {
1398        let list = ion_list![1, 2, 3, true, false];
1399
1400        // Use the Display impl to serialize the list to text
1401        let text_list = format!("{list}");
1402        // Parse the result and make sure it represents the same data
1403        let expected_element: Element = list.into();
1404        let actual_element = Element::read_one(text_list).unwrap();
1405        assert!(expected_element.ion_eq(&actual_element));
1406    }
1407
1408    #[test]
1409    fn sexp_display_roundtrip() {
1410        let sexp = ion_sexp! (1 2 3 true false);
1411
1412        // Use the Display impl to serialize the sexp to text
1413        let text_sexp = format!("{sexp}");
1414        // Parse the result and make sure it represents the same data
1415        let expected_element: Element = sexp.into();
1416        let actual_element = Element::read_one(text_sexp).unwrap();
1417        assert!(expected_element.ion_eq(&actual_element));
1418    }
1419
1420    #[test]
1421    fn struct_display_roundtrip() {
1422        let struct_ = ion_struct! {"foo": 1, "bar": 2, "baz": ion_list! [true, false]};
1423
1424        // Use the Display impl to serialize the struct to text
1425        let text_struct = format!("{struct_}");
1426        // Parse the result and make sure it represents the same data
1427        let expected_element: Element = struct_.into();
1428        let actual_element = Element::read_one(text_struct).unwrap();
1429        assert!(expected_element.ion_eq(&actual_element));
1430    }
1431}