1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#![allow(dead_code)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]
#![deny(rustdoc::bare_urls)]
//! # Reading and writing `Element`s
//!
//! The [Element] API offers a convenient way to read and write Ion data when its exact shape is
//! not known ahead of time.
//!
//! Each `Element` represents an `(annotations, value)` pair. If the value is a container (an Ion
//! `list`, `sexp`, or `struct`), then it will contain its own collection of `Element`s. `Element`s
//! can be nested to arbitrary depth.
//!
//! ## Constructing an `Element`
//!
//! ### From text Ion
//! The [Element::read_one] method will parse the provided data and requires that it contain exactly
//! one Ion value.
//! ```
//! # use ion_rs::IonResult;
//! # fn main() -> IonResult<()> {
//! use ion_rs::element::Element;
//! use ion_rs::IonType;
//! let ion_data = "[1, 2, 3]";
//! let element = Element::read_one(ion_data)?;
//! assert_eq!(element.ion_type(), IonType::List);
//! # Ok(())
//! # }
//! ```
//!
//! [Element::read_all] will read any number of Ion values and return them as a `Vec<Element>`.
//!
//! [Element::read_first] will read the first Ion value without requiring that the stream have
//! exactly one value.
//!
//! ### From a Rust value
//! Most Rust primitives implement `Into<Element>`, allowing them to be converted to an Ion [Element]
//! directly.
//! ```
//! # use ion_rs::IonResult;
//! # fn main() -> IonResult<()> {
//! use ion_rs::element::Element;
//!
//! let int: Element = 5.into();
//! assert_eq!(Element::read_one("5")?, int);
//!
//! let boolean: Element = true.into();
//! assert_eq!(Element::read_one("true")?, boolean);
//!
//! let string: Element = "hello".into();
//! assert_eq!(Element::read_one("\"hello\"")?, string);
//!
//! let ion_version_marker: &[u8] = &[0xE0, 0x01, 0x00, 0xEA]; // Ion 1.0 version marker
//! let blob: Element = ion_version_marker.into();
//! assert_eq!(Element::read_one("{{4AEA6g==}}")?, blob);
//! # Ok(())
//! # }
//! ```
//!
//! ### Using macros
//!
//! When constructing a container [Element], you can use the [`ion_list!`], [`ion_sexp!`],
//! and [`ion_struct!`] macros.
//!
//! ```
//! # use ion_rs::IonResult;
//! # fn main() -> IonResult<()> {
//! use ion_rs::element::Element;
//! use ion_rs::{ion_list, ion_sexp, ion_struct};
//!
//! // Variable names are allowed
//! let six = 6i64;
//! let list: Element = ion_list! [true, six, "foo"].into();
//! assert_eq!(Element::read_one("[true, 6, \"foo\"]")?, list);
//!
//! // Nested use of macros is allowed
//! // Notice that ion_sexp! uses ()s without commas
//! let sexp: Element = ion_sexp! (true six ion_list!["foo", "bar"]).into();
//! assert_eq!(Element::read_one("(true 6 [\"foo\", \"bar\"])")?, sexp);
//!
//! let field_name = "bar";
//! let struct_: Element = ion_struct! {
//!   "foo": six,
//!   field_name: false
//! }.into();
//! assert_eq!(Element::read_one("{foo: 6, bar: false}")?, struct_);
//! # Ok(())
//! # }
//! ```
//!
//! ### From a stream
//!
//! ```no_run
//! # use ion_rs::IonResult;
//! # fn main() -> IonResult<()> {
//! use ion_rs::element::reader::ElementReader;
//! use ion_rs::element::Element;
//! use ion_rs::ReaderBuilder;
//! use std::fs::File;
//! let ion_file = File::open("/foo/bar/baz.ion").unwrap();
//! let mut reader = ReaderBuilder::default().build(ion_file)?;
//! // A simple pretty-printer
//! for element in reader.elements() {
//!     println!("{}", element?)
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ## Traversing an `Element`
//!
//! ```
//! use ion_rs::IonResult;
//! # fn main() -> IonResult<()> {
//! use ion_rs::element::{Element, IntoAnnotatedElement, Value};
//! use ion_rs::{ion_list, ion_struct};
//! let element: Element = ion_struct! {
//!   "foo": "hello",
//!   "bar": true,
//!   "baz": ion_list! [4, 5, 6]
//! }
//! .into();
//!
//! if let Value::Struct(s) = element.value() {
//!     if let Some(Value::List(l)) = s.get("baz").map(|b| b.value()) {
//!         for (index, element) in l.elements().enumerate() {
//!             println!("{}. {}", index + 1, element);
//!             // 1) 4
//!             // 2) 5
//!             // 3) 6
//!         }
//!     }
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ## Writing an `Element` to an `io::Write`
//!
//! ```
//! use ion_rs::IonResult;
//! # fn main() -> IonResult<()> {
//! use ion_rs::element::writer::ElementWriter;
//! use ion_rs::element::{Element, IntoAnnotatedElement, Value};
//! use ion_rs::{ion_list, ion_struct, IonWriter, TextWriterBuilder};
//! let element: Element = ion_struct! {
//!   "foo": "hello",
//!   "bar": true,
//!   "baz": ion_list! [4, 5, 6]
//! }
//! .into();
//!
//! let mut buffer: Vec<u8> = Vec::new();
//! let mut writer = TextWriterBuilder::default().build(&mut buffer)?;
//! writer.write_element(&element)?;
//! writer.flush()?;
//! assert_eq!(
//!     "{foo: \"hello\", bar: true, baz: [4, 5, 6]}".as_bytes(),
//!     writer.output().as_slice()
//! );
//! # Ok(())
//! # }
//! ```

// XXX this top-level import is required because of the macro factoring of rstest_reuse
// XXX Clippy incorrectly indicates that this is redundant
#[cfg(test)]
#[allow(unused_imports)]
#[allow(clippy::single_component_path_imports)]
use rstest_reuse;

// This import is used in the doc comments and test code above. Clippy incorrectly
// declares it an unused import.
#[allow(unused_imports)]
use element::Element;

pub mod result;

pub mod binary;
pub mod data_source;
pub mod element;
pub mod raw_reader;
pub mod text;
pub mod types;

mod ion_data;
#[cfg(feature = "ion-hash")]
pub mod ion_hash;

mod blocking_reader;
mod catalog;
// Public as a workaround for: https://github.com/amazon-ion/ion-rust/issues/484
pub mod constants;
mod raw_symbol_token;
mod raw_symbol_token_ref;
// Public as a workaround for: https://github.com/amazon-ion/ion-rust/issues/484
pub mod reader;
mod shared_symbol_table;
mod stream_reader;
mod symbol_ref;
mod symbol_table;
mod system_reader;
mod writer;

#[cfg(feature = "experimental-lazy-reader")]
pub mod lazy;
// Experimental Streaming APIs
#[cfg(feature = "experimental-streaming")]
pub mod thunk;
#[cfg(feature = "experimental-streaming")]
pub mod tokens;

#[doc(inline)]
pub use data_source::IonDataSource;
#[doc(inline)]
pub use raw_symbol_token::RawSymbolToken;
#[doc(inline)]
pub use raw_symbol_token_ref::RawSymbolTokenRef;

pub use symbol_ref::SymbolRef;
pub use symbol_table::SymbolTable;

pub use types::{Decimal, Int, IonType, Str, Symbol, Timestamp};

pub use ion_data::IonData;

pub use binary::binary_writer::{BinaryWriter, BinaryWriterBuilder};
pub use text::text_writer::{TextWriter, TextWriterBuilder};
pub use writer::IonWriter;

pub use binary::raw_binary_writer::RawBinaryWriter;
pub use blocking_reader::{BlockingRawBinaryReader, BlockingRawReader, BlockingRawTextReader};
pub use raw_reader::{RawReader, RawStreamItem};
pub use reader::{Reader, ReaderBuilder, StreamItem, UserReader};
pub use stream_reader::IonReader;
pub use system_reader::{SystemReader, SystemStreamItem};
pub use text::raw_text_writer::{RawTextWriter, RawTextWriterBuilder};

pub use result::{IonError, IonResult};

/// Re-exports of third party dependencies that are part of our public API.
///
/// See also: <https://github.com/amazon-ion/ion-rust/issues/302>
pub mod external {
    pub use bigdecimal;
}