Expand description
Provides a in-memory tree representation of Ion values that can be operated on in a dynamically typed way.
This module consists of two submodules that implement the value traits:
- The
owned
module provides an implementation of values that have no associated lifetime. These types are convenient, but may imply extra copying/cloning. - The
borrowed
module provides an implementation of values that are tied to some associated lifetime and borrow a reference to their underlying data in some way (e.g. storing a&str
in the value versus a fully ownedString
). - The
reader
module provides API and implementation to read Ion data intoElement
instances. - The
writer
module provides API and implementation to write Ion data fromElement
instances.
Examples
In general, users will use the ElementReader
trait to read in data:
use ion_rs::IonType;
use ion_rs::result::IonResult;
use ion_rs::value::{Element, Struct};
use ion_rs::value::reader::element_reader;
use ion_rs::value::reader::ElementReader;
fn main() -> IonResult<()> {
let mut iter = element_reader().iterate_over(br#""hello!""#)?;
if let Some(Ok(elem)) = iter.next() {
assert_eq!(IonType::String, elem.ion_type());
assert_eq!("hello!", elem.as_str().unwrap());
} else {
panic!("Expected an element!");
}
assert!(iter.next().is_none());
Ok(())
}
ElementReader::read_all
is a convenient way to put all of the
parsed Element
into a Vec
, with a single IonError
wrapper:
let elems = element_reader().read_all(br#""hello" world"#)?;
assert_eq!(2, elems.len());
assert_eq!(IonType::String, elems[0].ion_type());
assert_eq!("hello", elems[0].as_str().unwrap());
assert_eq!(IonType::Symbol, elems[1].ion_type());
assert_eq!("world", elems[1].as_str().unwrap());
ElementReader::read_one
is another convenient way to parse a single
top-level element into a Element
. This method will return an error if the data has
a parsing error or if there is more than one Element
in the stream:
// read a single value from binary: 42
let elem = element_reader().read_one(&[0xE0, 0x01, 0x00, 0xEA, 0x21, 0x2A])?;
assert_eq!(IonType::Integer, elem.ion_type());
assert_eq!(42, elem.as_i64().unwrap());
// cannot read two values in a stream this way: 42 0
assert!(element_reader().read_one(&[0xE0, 0x01, 0x00, 0xEA, 0x21, 0x2A, 0x20]).is_err());
// cannot read an empty stream (binary IVM only)
assert!(element_reader().read_one(&[0xE0, 0x01, 0x00, 0xEA]).is_err());
// normal malformed binary is a failure!
assert!(element_reader().read_one(&[0xE0, 0x01, 0x00, 0xEA, 0xF0]).is_err());
// also an error if malformed data happens after valid single value
assert!(element_reader().read_one(&[0xE0, 0x01, 0x00, 0xEA, 0x20, 0x30]).is_err());
To serialize data, users can use the ElementWriter
trait to serialize data
from Element
to binary or text Ion:
use ion_rs::result::IonResult;
use ion_rs::value::Element;
use ion_rs::value::reader::{element_reader, ElementReader};
use ion_rs::value::writer::{ElementWriter, Format};
// a fixed buffer length to write to
const BUF_SIZE: usize = 8 * 1024 * 1024;
fn main() -> IonResult<()> {
let elems = element_reader().read_all(b"null true 1")?;
let mut buf = vec![0u8; BUF_SIZE];
let mut writer = Format::Binary.element_writer_for_slice(&mut buf)?;
writer.write_all(elems.iter())?;
let output = writer.finish()?;
assert_eq!(&[0xE0, 0x01, 0x00, 0xEA, 0x0F, 0x11, 0x21, 0x01], output);
Ok(())
}
Users should use the traits in this module to make their code work
in contexts that have either borrowed
or owned
values. This can be done
most easily by writing generic functions that can work with a reference of any type.
For example, consider a fairly contrived, but generic extract_text
function that unwraps
and converts SymbolToken::text()
into an owned String
:
use ion_rs::value::SymbolToken;
use ion_rs::value::borrowed::BorrowedSymbolToken;
use ion_rs::value::owned::OwnedSymbolToken;
fn extract_text<T: SymbolToken>(tok: &T) -> String {
tok.text().unwrap().into()
}
let owned_token: OwnedSymbolToken = "hello".into();
// owned value to emphasize lifetime
let text = String::from("hello");
let borrowed_token: BorrowedSymbolToken = text.as_str().into();
let owned_text = extract_text(&owned_token);
let borrowed_text = extract_text(&borrowed_token);
assert_eq!(owned_text, borrowed_text);
This extends to the Element
trait as well which is the “top-level” API type for
any Ion datum. Consider a contrived function that extracts and returns the annotations
of an underlying element as a Vec<String>
. Note that it filters out any annotation
that may not have text (so data could be dropped):
use ion_rs::value::{Element, SymbolToken};
use ion_rs::value::borrowed::{
BorrowedValue,
BorrowedElement,
local_sid_token as borrowed_local_sid_token,
text_token as borrowed_text_token
};
use ion_rs::value::owned::{
OwnedValue,
OwnedElement,
local_sid_token as owned_local_sid_token,
text_token as owned_text_token
};
fn extract_annotations<T: Element>(elem: &T) -> Vec<Option<String>> {
elem.annotations().map(
|tok| tok.text().map(|text_ref| text_ref.to_string())
).collect()
}
let owned_elem = OwnedElement::new(
vec![
owned_local_sid_token(300).with_source("foo", 12),
owned_text_token("hello")
],
OwnedValue::String("world".into())
);
// owned values to emphasize lifetime
let strings: Vec<String> =
vec!["hello", "world"].iter().map(|x| x.to_string()).collect();
let borrowed_elem = BorrowedElement::new(
vec![
borrowed_local_sid_token(200).with_source("bar", 9),
borrowed_text_token(&strings[0])
],
BorrowedValue::String(&strings[1])
);
let owned_annotations = extract_annotations(&owned_elem);
let borrowed_annotations = extract_annotations(&borrowed_elem);
assert_eq!(owned_annotations, borrowed_annotations);
For reference here are a couple other value style APIs for JSON:
Modules
Provides borrowed implementations of SymbolToken
, Element
and its dependents.
Provides owned implementations of SymbolToken
, Element
and its dependents.
Enums
Traits
Represents a either a borrowed or owned Ion datum. There are/will be specific APIs for borrowed and owned implementations, but this trait unifies operations on either.
The shared symbol table source of a given SymbolToken
.
Represents the value of sequences of Ion elements (i.e. list
and sexp
).
Represents the value of struct
of Ion elements.
A view of a symbolic token.