Skip to main content

ion_rs/
lib.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2#![deny(rustdoc::private_intra_doc_links)]
3#![deny(rustdoc::bare_urls)]
4#![deny(rust_2018_idioms)]
5// Warn if example code in the doc tests contains unused imports/variables
6#![doc(test(attr(warn(unused))))]
7//! # Reading and writing `Element`s
8//!
9//! The [Element] API offers a convenient way to read and write Ion data when its exact shape is
10//! not known ahead of time.
11//!
12//! Each `Element` represents an `(annotations, value)` pair. If the value is a container (an Ion
13//! `list`, `sexp`, or `struct`), then it will contain its own collection of `Element`s. `Element`s
14//! can be nested to arbitrary depth.
15//!
16//! ## Constructing an `Element`
17//!
18//! ### From text Ion
19//! The [Element::read_one] method will parse the provided data and requires that it contain exactly
20//! one Ion value.
21//! ```
22//! # use ion_rs::IonResult;
23//! # fn main() -> IonResult<()> {
24//! use ion_rs::{Element, IonType};
25//! let ion_data = "[1, 2, 3]";
26//! let element = Element::read_one(ion_data)?;
27//! assert_eq!(element.ion_type(), IonType::List);
28//! # Ok(())
29//! # }
30//! ```
31//!
32//! [Element::read_all] will read any number of Ion values and return them as a [`Sequence`].
33//!
34//! [Element::read_first] will read the first Ion value without requiring that the stream have
35//! exactly one value.
36//!
37//! ### From a Rust value
38//! Most Rust primitives implement `Into<Element>`, allowing them to be converted to an Ion [Element]
39//! directly.
40//! ```
41//! # use ion_rs::IonResult;
42//! # fn main() -> IonResult<()> {
43//! use ion_rs::Element;
44//!
45//! let int: Element = 5.into();
46//! assert_eq!(Element::read_one("5")?, int);
47//!
48//! let boolean: Element = true.into();
49//! assert_eq!(Element::read_one("true")?, boolean);
50//!
51//! let string: Element = "hello".into();
52//! assert_eq!(Element::read_one("\"hello\"")?, string);
53//!
54//! let ion_version_marker: &[u8] = &[0xE0, 0x01, 0x00, 0xEA]; // Ion 1.0 version marker
55//! let blob: Element = ion_version_marker.into();
56//! assert_eq!(Element::read_one("{{4AEA6g==}}")?, blob);
57//! # Ok(())
58//! # }
59//! ```
60//!
61//! ### Using macros
62//!
63//! When constructing a container [Element], you can use the [`ion_list!`], [`ion_sexp!`],
64//! and [`ion_struct!`] macros.
65//!
66//! ```
67//! # use ion_rs::IonResult;
68//! # fn main() -> IonResult<()> {
69//! use ion_rs::{Element, ion_list, ion_sexp, ion_struct};
70//!
71//! // Variable names are allowed
72//! let six = 6i64;
73//! let list: Element = ion_list! [true, six, "foo"].into();
74//! assert_eq!(Element::read_one("[true, 6, \"foo\"]")?, list);
75//!
76//! // Nested use of macros is allowed
77//! // Notice that ion_sexp! uses ()s without commas
78//! let sexp: Element = ion_sexp! (true six ion_list!["foo", "bar"]).into();
79//! assert_eq!(Element::read_one("(true 6 [\"foo\", \"bar\"])")?, sexp);
80//!
81//! let field_name = "bar";
82//! let struct_: Element = ion_struct! {
83//!   "foo": six,
84//!   field_name: false
85//! }.into();
86//! assert_eq!(Element::read_one("{foo: 6, bar: false}")?, struct_);
87//! # Ok(())
88//! # }
89//! ```
90//!
91//! ### From a stream
92//!
93//! ```no_run
94//! # use ion_rs::IonResult;
95//! # fn main() -> IonResult<()> {
96//! use ion_rs::Element;
97//! use std::fs::File;
98//! let ion_file = File::open("/foo/bar/baz.ion").unwrap();
99//! // A simple pretty-printer
100//! for element in Element::iter(ion_file)? {
101//!     println!("{}", element?)
102//! }
103//! # Ok(())
104//! # }
105//! ```
106//!
107//! ## Traversing an `Element`
108//!
109//! ```
110//! # use ion_rs::IonResult;
111//! # fn main() -> IonResult<()> {
112//! use ion_rs::{Element, Value, ion_list, ion_struct};
113//! let element: Element = ion_struct! {
114//!   "foo": "hello",
115//!   "bar": true,
116//!   "baz": ion_list! [4, 5, 6]
117//! }
118//! .into();
119//!
120//! if let Value::Struct(s) = element.value() {
121//!     if let Some(Value::List(l)) = s.get("baz").map(|b| b.value()) {
122//!         for (index, element) in l.elements().enumerate() {
123//!             println!("{}. {}", index + 1, element);
124//!             // 1) 4
125//!             // 2) 5
126//!             // 3) 6
127//!         }
128//!     }
129//! }
130//! # Ok(())
131//! # }
132//! ```
133
134// XXX this top-level import is required because of the macro factoring of rstest_reuse
135// XXX Clippy incorrectly indicates that this is redundant
136#[cfg(test)]
137#[allow(unused_imports)]
138#[allow(clippy::single_component_path_imports)]
139use rstest_reuse;
140
141// Exposed to allow benchmark comparisons between the 1.0 primitives and 1.1 primitives
142#[cfg(feature = "experimental-reader-writer")]
143pub use catalog::{Catalog, EmptyCatalog, MapCatalog};
144pub use element::builders::{SequenceBuilder, StructBuilder};
145#[cfg(feature = "experimental-reader-writer")]
146pub use element::{element_writer::ElementWriter, reader::ElementReader};
147pub use element::{Annotations, Element, IntoAnnotatedElement, IntoAnnotations, Sequence, Value};
148pub use ion_data::IonData;
149pub use lazy::streaming_raw_reader::IonInput;
150pub use location::SourceLocation;
151
152#[doc(inline)]
153pub use result::{ConversionOperationError, ConversionOperationResult, IonError, IonResult};
154#[cfg(feature = "experimental-reader-writer")]
155pub use shared_symbol_table::SharedSymbolTable;
156pub use symbol_ref::SymbolRef;
157#[doc(inline)]
158pub use types::{
159    decimal::Decimal, Blob, Bytes, Clob, Int, IonType, List, Null, SExp, Str, Struct, Symbol,
160    Timestamp, TimestampPrecision, UInt,
161};
162pub mod decimal {
163    //! Types for working with Ion decimal coefficients.
164    pub use crate::types::decimal::{Coefficient, Sign};
165}
166#[cfg(feature = "experimental-reader-writer")]
167pub use types::SymbolId;
168#[cfg(not(feature = "experimental-reader-writer"))]
169pub(crate) use types::SymbolId;
170
171#[cfg(feature = "experimental-tooling-apis")]
172pub use crate::text::text_formatter::{FmtValueFormatter, IoValueFormatter};
173
174// Private modules that serve to organize implementation details.
175pub(crate) mod binary;
176pub(crate) mod catalog;
177pub(crate) mod constants;
178mod ion_data;
179mod raw_symbol_ref;
180mod shared_symbol_table;
181mod symbol_ref;
182mod symbol_table;
183mod text;
184
185// Publicly-visible modules with nested items which users may choose to import
186mod element;
187pub(crate) mod result;
188mod types;
189
190mod position;
191mod read_config;
192#[cfg(feature = "experimental-serde")]
193pub mod serde;
194pub(crate) mod unsafe_helpers;
195
196#[cfg(feature = "experimental-ion-hash")]
197pub mod ion_hash;
198pub(crate) mod lazy;
199mod location;
200mod write_config;
201
202#[cfg(feature = "experimental-reader-writer")]
203pub use crate::lazy::any_encoding::AnyEncoding;
204#[cfg(not(feature = "experimental-reader-writer"))]
205pub(crate) use crate::lazy::any_encoding::AnyEncoding;
206
207#[cfg(feature = "experimental-tooling-apis")]
208pub use crate::lazy::decoder::{HasRange, HasSpan};
209#[cfg(not(feature = "experimental-tooling-apis"))]
210pub(crate) use crate::lazy::decoder::{HasRange, HasSpan};
211
212#[cfg(feature = "experimental-tooling-apis")]
213pub use crate::lazy::span::Span;
214#[cfg(not(feature = "experimental-tooling-apis"))]
215pub(crate) use crate::lazy::span::Span;
216macro_rules! v1_x_reader_writer {
217    ($visibility:vis) => {
218       #[allow(unused_imports)]
219        $visibility use crate::{
220            lazy::streaming_raw_reader::{IonSlice, IonStream},
221            lazy::decoder::Decoder,
222            lazy::encoder::Encoder,
223            lazy::encoding::Encoding,
224            lazy::encoder::annotate::Annotatable,
225            lazy::encoder::write_as_ion::WriteAsIon,
226            lazy::encoder::writer::Writer,
227            lazy::reader::Reader,
228            raw_symbol_ref::RawSymbolRef,
229            symbol_table::SymbolTable,
230            lazy::value::LazyValue,
231            lazy::value_ref::ValueRef,
232            lazy::r#struct::{LazyStruct, LazyField},
233            lazy::sequence::{LazyList, LazySExp},
234            lazy::encoder::value_writer::{AnnotatableWriter, ValueWriter, ContextWriter, StructWriter, SequenceWriter, EExpWriter},
235            lazy::any_encoding::IonEncoding,
236            lazy::expanded::compiler::TemplateCompiler,
237            lazy::expanded::template::TemplateMacro,
238            lazy::expanded::template::TemplateBodyExpr,
239            lazy::expanded::template::TemplateBodyExprKind,
240            lazy::expanded::template::TemplateMacroInvocation,
241            lazy::expanded::macro_table::MacroDef,
242            lazy::expanded::macro_evaluator::MacroEvaluator,
243            lazy::expanded::macro_evaluator::MacroExpansionKind,
244            lazy::expanded::macro_table::MacroKind,
245            lazy::expanded::macro_table::MacroTable,
246            lazy::expanded::EncodingContext,
247            lazy::any_encoding::IonVersion,
248            lazy::binary::raw::reader::LazyRawBinaryReader_1_0,
249            lazy::binary::raw::v1_1::reader::LazyRawBinaryReader_1_1,
250            lazy::expanded::macro_evaluator::RawEExpression,
251            lazy::expanded::macro_evaluator::ValueExpr,
252            lazy::expanded::macro_evaluator::MacroExpr,
253            lazy::expanded::macro_evaluator::MacroExprKind,
254            lazy::expanded::macro_evaluator::MacroExprArgsIterator,
255        };
256    };
257}
258
259pub use crate::write_config::WriteConfig;
260
261macro_rules! v1_0_reader_writer {
262    ($visibility:vis) => {
263        #[allow(unused_imports)]
264        $visibility use crate::{
265            lazy::encoder::writer::{BinaryWriter_1_0 as BinaryWriter, TextWriter_1_0 as TextWriter},
266        };
267    };
268}
269
270macro_rules! v1_1_reader_writer {
271    ($visibility:vis) => {
272        #[allow(unused_imports)]
273        $visibility use crate::{
274            lazy::encoder::writer::{BinaryWriter_1_1 as BinaryWriter, TextWriter_1_1 as TextWriter},
275            lazy::encoding::{BinaryEncoding_1_1 as Binary, TextEncoding_1_1 as Text},
276            lazy::expanded::macro_table::Macro
277        };
278    };
279}
280
281macro_rules! v1_x_tooling_apis {
282    ($visibility:vis) => {
283        #[allow(unused_imports)]
284        $visibility use crate::{
285            lazy::raw_stream_item::RawStreamItem,
286            lazy::any_encoding::{
287                LazyRawAnyVersionMarker, LazyRawAnyVersionMarkerKind,
288                LazyRawAnyValue, LazyRawValueKind,
289                LazyRawAnyList, LazyRawListKind,
290                LazyRawAnySExp, LazyRawSExpKind,
291                LazyRawAnyStruct, LazyRawStructKind,
292                LazyRawAnyFieldName, LazyRawFieldNameKind,
293                LazyRawAnyEExpression, LazyRawAnyEExpressionKind,
294                AnyEExpArgGroup, AnyEExpArgGroupKind, AnyEExpArgGroupIterator
295            },
296            lazy::decoder::{
297                LazyRawSequence,
298                LazyRawStruct,
299                LazyRawFieldExpr,
300                LazyRawFieldName,
301                LazyRawValue,
302                LazyRawReader,
303                RawVersionMarker,
304                LazyRawContainer,
305            },
306            lazy::encoder::{
307                LazyRawWriter,
308            },
309            lazy::encoder::value_writer_config::{
310                ValueWriterConfig,
311                ContainerEncoding,
312                SymbolValueEncoding,
313                AnnotationsEncoding,
314                FieldNameEncoding,
315            },
316            lazy::expanded::r#struct::{
317                LazyExpandedStruct, ExpandedStructSource,
318                LazyExpandedField,
319                LazyExpandedFieldName,
320                FieldExpr,
321            },
322            lazy::expanded::e_expression::{EExpression, EExpressionArgsIterator, EExpArgGroup, EExpArgGroupIterator},
323            lazy::expanded::sequence::{Environment, ExpandedListSource, ExpandedSExpSource, LazyExpandedList, LazyExpandedSExp},
324            lazy::expanded::{ExpandedStreamItem, LazyExpandedValue, ExpandingReader, ExpandedValueSource, ExpandedAnnotationsSource, ExpandedValueRef},
325            lazy::system_stream_item::SystemStreamItem,
326            lazy::system_reader::{SystemReader},
327        };
328    };
329}
330
331macro_rules! v1_0_tooling_apis {
332    ($visibility:vis) => {
333        #[allow(unused_imports)]
334        $visibility use crate::{
335            binary::uint::DecodedUInt,
336            binary::var_int::VarInt,
337            binary::var_uint::VarUInt,
338            lazy::binary::binary_buffer::{BinaryBuffer, AnnotationsWrapper},
339            lazy::binary::raw::type_descriptor::Header,
340            lazy::raw_value_ref::RawValueRef,
341            lazy::encoder::binary::v1_0::writer::LazyRawBinaryWriter_1_0 as RawBinaryWriter,
342            lazy::encoder::text::v1_0::writer::LazyRawTextWriter_1_0 as RawTextWriter,
343            lazy::binary::raw::sequence::{
344                LazyRawBinaryList_1_0 as LazyRawBinaryList,
345                LazyRawBinarySExp_1_0 as LazyRawBinarySExp
346            },
347            lazy::binary::raw::r#struct::{LazyRawBinaryStruct_1_0 as LazyRawBinaryStruct, LazyRawBinaryFieldName_1_0 as LazyRawBinaryFieldName},
348            lazy::binary::raw::value::{
349                BinaryValueLiteral,
350                LazyRawBinaryValue_1_0 as LazyRawBinaryValue,
351                LazyRawBinaryVersionMarker_1_0 as LazyRawBinaryVersionMarker,
352                EncodedBinaryValueData_1_0 as EncodedBinaryValueData,
353                EncodedBinaryAnnotations_1_0 as EncodedBinaryAnnotations
354            },
355        };
356    };
357}
358
359macro_rules! v1_1_tooling_apis {
360    ($visibility:vis) => {
361        #[allow(unused_imports)]
362        $visibility use crate::{
363            lazy::encoder::binary::v1_1::flex_int::FlexInt,
364            lazy::encoder::binary::v1_1::flex_uint::FlexUInt,
365            lazy::encoder::binary::v1_1::writer::LazyRawBinaryWriter_1_1 as RawBinaryWriter,
366            lazy::encoder::text::v1_1::writer::LazyRawTextWriter_1_1 as RawTextWriter,
367            lazy::binary::raw::v1_1::sequence::{
368                LazyRawBinaryList_1_1 as LazyRawBinaryList,
369                LazyRawBinarySExp_1_1 as LazyRawBinarySExp
370            },
371            lazy::binary::raw::v1_1::r#struct::{LazyRawBinaryStruct_1_1 as LazyRawBinaryStruct, LazyRawBinaryFieldName_1_1 as LazyRawBinaryFieldName},
372            lazy::binary::raw::v1_1::value::{
373                LazyRawBinaryValue_1_1 as LazyRawBinaryValue,
374                LazyRawBinaryVersionMarker_1_1 as LazyRawBinaryVersionMarker,
375            },
376        };
377    };
378}
379
380#[cfg(feature = "experimental-reader-writer")]
381v1_x_reader_writer!(pub);
382
383#[cfg(not(feature = "experimental-reader-writer"))]
384v1_x_reader_writer!(pub(crate));
385
386#[cfg(feature = "experimental-tooling-apis")]
387v1_x_tooling_apis!(pub);
388
389#[cfg(not(feature = "experimental-tooling-apis"))]
390v1_x_tooling_apis!(pub(crate));
391
392pub mod v1_0 {
393    #[cfg(feature = "experimental-tooling-apis")]
394    v1_0_tooling_apis!(pub);
395
396    #[cfg(not(feature = "experimental-tooling-apis"))]
397    v1_0_tooling_apis!(pub(crate));
398
399    #[cfg(feature = "experimental-reader-writer")]
400    v1_0_reader_writer!(pub);
401
402    #[cfg(not(feature = "experimental-reader-writer"))]
403    v1_0_reader_writer!(pub(crate));
404
405    pub use crate::lazy::encoding::{BinaryEncoding_1_0 as Binary, TextEncoding_1_0 as Text};
406}
407
408#[cfg(feature = "experimental-ion-1-1")]
409pub mod v1_1 {
410    pub use crate::constants::v1_1::constants;
411    pub use crate::constants::v1_1::system_symbols;
412
413    #[cfg(feature = "experimental-tooling-apis")]
414    v1_1_tooling_apis!(pub);
415
416    #[cfg(not(feature = "experimental-tooling-apis"))]
417    v1_1_tooling_apis!(pub(crate));
418
419    #[cfg(feature = "experimental-reader-writer")]
420    v1_1_reader_writer!(pub);
421
422    #[cfg(not(feature = "experimental-reader-writer"))]
423    v1_1_reader_writer!(pub(crate));
424}
425
426#[cfg(not(feature = "experimental-ion-1-1"))]
427pub(crate) mod v1_1 {
428    #[cfg(feature = "experimental-tooling-apis")]
429    v1_1_tooling_apis!(pub);
430
431    #[cfg(not(feature = "experimental-tooling-apis"))]
432    v1_1_tooling_apis!(pub(crate));
433
434    #[cfg(feature = "experimental-reader-writer")]
435    v1_1_reader_writer!(pub);
436
437    #[cfg(not(feature = "experimental-reader-writer"))]
438    v1_1_reader_writer!(pub(crate));
439}
440
441/// Whether or not the text spacing is generous/human-friendly or something more compact.
442#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
443#[non_exhaustive]
444pub enum TextFormat {
445    Compact,
446    Lines,
447    #[default]
448    Pretty,
449}
450
451/// Early returns `Some(Err(_))` if the provided expression returns an `Err(_)`.
452///
453/// Acts as an ersatz `?` operator in methods that return `Option<IonResult<T>>`.
454macro_rules! try_or_some_err {
455    ($expr:expr) => {
456        match $expr {
457            Ok(v) => v,
458            Err(e) => return Some(Err(e)),
459        }
460    };
461}
462
463pub(crate) use try_or_some_err;
464
465/// Tries to get the next value from an expression of type `Option<Result<_>>`, early returning if
466/// the expression is `None` or `Some(Err(_))`. This is useful in the context of iterator
467/// implementations that produce an `Option<Result>>` and so cannot easily use the `?` operator.
468///
469/// If the expression evaluates to `None`, early returns `None`.
470/// If the expression evaluates to `Some(Err(e))`, early returns `Some(Err(e))`.
471/// If the expression evaluates to `Some(Ok(value))`, evaluates to `value`.
472macro_rules! try_next {
473    ($expr:expr) => {
474        match $expr {
475            Some(Ok(v)) => v,
476            None => return None,
477            Some(Err(e)) => return Some(Err(e)),
478        }
479    };
480}
481
482pub(crate) use try_next;