ion_rs/
lib.rs

1#![allow(dead_code)]
2#![deny(rustdoc::broken_intra_doc_links)]
3#![deny(rustdoc::private_intra_doc_links)]
4#![deny(rustdoc::bare_urls)]
5//! # Reading and writing `Element`s
6//!
7//! The [Element] API offers a convenient way to read and write Ion data when its exact shape is
8//! not known ahead of time.
9//!
10//! Each `Element` represents an `(annotations, value)` pair. If the value is a container (an Ion
11//! `list`, `sexp`, or `struct`), then it will contain its own collection of `Element`s. `Element`s
12//! can be nested to arbitrary depth.
13//!
14//! ## Constructing an `Element`
15//!
16//! ### From text Ion
17//! The [Element::read_one] method will parse the provided data and requires that it contain exactly
18//! one Ion value.
19//! ```
20//! # use ion_rs::IonResult;
21//! # fn main() -> IonResult<()> {
22//! use ion_rs::element::Element;
23//! use ion_rs::IonType;
24//! let ion_data = "[1, 2, 3]";
25//! let element = Element::read_one(ion_data)?;
26//! assert_eq!(element.ion_type(), IonType::List);
27//! # Ok(())
28//! # }
29//! ```
30//!
31//! [Element::read_all] will read any number of Ion values and return them as a `Vec<Element>`.
32//!
33//! [Element::read_first] will read the first Ion value without requiring that the stream have
34//! exactly one value.
35//!
36//! ### From a Rust value
37//! Most Rust primitives implement `Into<Element>`, allowing them to be converted to an Ion [Element]
38//! directly.
39//! ```
40//! # use ion_rs::IonResult;
41//! # fn main() -> IonResult<()> {
42//! use ion_rs::element::Element;
43//!
44//! let int: Element = 5.into();
45//! assert_eq!(Element::read_one("5")?, int);
46//!
47//! let boolean: Element = true.into();
48//! assert_eq!(Element::read_one("true")?, boolean);
49//!
50//! let string: Element = "hello".into();
51//! assert_eq!(Element::read_one("\"hello\"")?, string);
52//!
53//! let ion_version_marker: &[u8] = &[0xE0, 0x01, 0x00, 0xEA]; // Ion 1.0 version marker
54//! let blob: Element = ion_version_marker.into();
55//! assert_eq!(Element::read_one("{{4AEA6g==}}")?, blob);
56//! # Ok(())
57//! # }
58//! ```
59//!
60//! ### Using macros
61//!
62//! When constructing a container [Element], you can use the [`ion_list!`], [`ion_sexp!`],
63//! and [`ion_struct!`] macros.
64//!
65//! ```
66//! # use ion_rs::IonResult;
67//! # fn main() -> IonResult<()> {
68//! use ion_rs::element::Element;
69//! use ion_rs::{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::reader::ElementReader;
97//! use ion_rs::element::Element;
98//! use ion_rs::ReaderBuilder;
99//! use std::fs::File;
100//! let ion_file = File::open("/foo/bar/baz.ion").unwrap();
101//! let mut reader = ReaderBuilder::default().build(ion_file)?;
102//! // A simple pretty-printer
103//! for element in reader.elements() {
104//!     println!("{}", element?)
105//! }
106//! # Ok(())
107//! # }
108//! ```
109//!
110//! ## Traversing an `Element`
111//!
112//! ```
113//! use ion_rs::IonResult;
114//! # fn main() -> IonResult<()> {
115//! use ion_rs::element::{Element, IntoAnnotatedElement, Value};
116//! use ion_rs::{ion_list, ion_struct};
117//! let element: Element = ion_struct! {
118//!   "foo": "hello",
119//!   "bar": true,
120//!   "baz": ion_list! [4, 5, 6]
121//! }
122//! .into();
123//!
124//! if let Value::Struct(s) = element.value() {
125//!     if let Some(Value::List(l)) = s.get("baz").map(|b| b.value()) {
126//!         for (index, element) in l.elements().enumerate() {
127//!             println!("{}. {}", index + 1, element);
128//!             // 1) 4
129//!             // 2) 5
130//!             // 3) 6
131//!         }
132//!     }
133//! }
134//! # Ok(())
135//! # }
136//! ```
137//!
138//! ## Writing an `Element` to an `io::Write`
139//!
140//! ```
141//! use ion_rs::IonResult;
142//! # fn main() -> IonResult<()> {
143//! use ion_rs::element::writer::ElementWriter;
144//! use ion_rs::element::{Element, IntoAnnotatedElement, Value};
145//! use ion_rs::{ion_list, ion_struct, IonWriter, TextWriterBuilder};
146//! let element: Element = ion_struct! {
147//!   "foo": "hello",
148//!   "bar": true,
149//!   "baz": ion_list! [4, 5, 6]
150//! }
151//! .into();
152//!
153//! let mut buffer: Vec<u8> = Vec::new();
154//! let mut writer = TextWriterBuilder::default().build(&mut buffer)?;
155//! writer.write_element(&element)?;
156//! writer.flush()?;
157//! assert_eq!(
158//!     "{foo: \"hello\", bar: true, baz: [4, 5, 6]}".as_bytes(),
159//!     writer.output().as_slice()
160//! );
161//! # Ok(())
162//! # }
163//! ```
164
165// XXX this top-level import is required because of the macro factoring of rstest_reuse
166// XXX Clippy incorrectly indicates that this is redundant
167#[cfg(test)]
168#[allow(unused_imports)]
169#[allow(clippy::single_component_path_imports)]
170use rstest_reuse;
171
172// This import is used in the doc comments and test code above. Clippy incorrectly
173// declares it an unused import.
174#[allow(unused_imports)]
175use element::Element;
176
177pub mod result;
178
179pub mod binary;
180pub mod data_source;
181pub mod element;
182pub mod raw_reader;
183pub mod text;
184pub mod types;
185
186mod ion_data;
187#[cfg(feature = "ion-hash")]
188pub mod ion_hash;
189
190mod blocking_reader;
191mod catalog;
192// Public as a workaround for: https://github.com/amazon-ion/ion-rust/issues/484
193pub mod constants;
194mod raw_symbol_token;
195mod raw_symbol_token_ref;
196// Public as a workaround for: https://github.com/amazon-ion/ion-rust/issues/484
197pub mod reader;
198mod shared_symbol_table;
199mod stream_reader;
200mod symbol_ref;
201mod symbol_table;
202mod system_reader;
203mod writer;
204
205#[cfg(feature = "experimental-lazy-reader")]
206pub mod lazy;
207// Experimental Streaming APIs
208#[cfg(feature = "experimental-streaming")]
209pub mod thunk;
210#[cfg(feature = "experimental-streaming")]
211pub mod tokens;
212
213#[doc(inline)]
214pub use data_source::IonDataSource;
215#[doc(inline)]
216pub use raw_symbol_token::RawSymbolToken;
217#[doc(inline)]
218pub use raw_symbol_token_ref::RawSymbolTokenRef;
219
220pub use symbol_ref::SymbolRef;
221pub use symbol_table::SymbolTable;
222
223pub use types::{Decimal, Int, IonType, Str, Symbol, Timestamp};
224
225pub use ion_data::IonData;
226
227pub use binary::binary_writer::{BinaryWriter, BinaryWriterBuilder};
228pub use text::text_writer::{TextWriter, TextWriterBuilder};
229pub use writer::IonWriter;
230
231pub use binary::raw_binary_writer::RawBinaryWriter;
232pub use blocking_reader::{BlockingRawBinaryReader, BlockingRawReader, BlockingRawTextReader};
233pub use raw_reader::{RawReader, RawStreamItem};
234pub use reader::{Reader, ReaderBuilder, StreamItem, UserReader};
235pub use stream_reader::IonReader;
236pub use system_reader::{SystemReader, SystemStreamItem};
237pub use text::raw_text_writer::{RawTextWriter, RawTextWriterBuilder};
238
239pub use result::{IonError, IonResult};
240
241/// Re-exports of third party dependencies that are part of our public API.
242///
243/// See also: <https://github.com/amazon-ion/ion-rust/issues/302>
244pub mod external {
245    pub use bigdecimal;
246}