Module ion_rs::value [−][src]
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
loader
module provides API and implementation to load Ion data intoElement
instances.
Examples
In general, users will use the Loader
trait to load in data:
use ion_rs::IonType; use ion_rs::result::IonResult; use ion_rs::value::{Element, Struct}; use ion_rs::value::loader::loader; use ion_rs::value::loader::Loader; fn main() -> IonResult<()> { let mut iter = loader().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(()) }
Loader::load_all
is a convenient way to put all of the
parsed Element
into a Vec
, with a single IonError
wrapper:
let elems = loader().load_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());
Loader::load_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:
// load a single value from binary: 42 let elem = loader().load_one(&[0xE0, 0x01, 0x00, 0xEA, 0x21, 0x2A])?; assert_eq!(IonType::Integer, elem.ion_type()); assert_eq!(42, elem.as_i64().unwrap()); // cannot load two values in a stream this way: 42 0 assert!(loader().load_one(&[0xE0, 0x01, 0x00, 0xEA, 0x21, 0x2A, 0x20]).is_err()); // cannot load an empty stream (binary IVM only) assert!(loader().load_one(&[0xE0, 0x01, 0x00, 0xEA]).is_err()); // normal malformed binary is a failure! assert!(loader().load_one(&[0xE0, 0x01, 0x00, 0xEA, 0xF0]).is_err()); // also an error if malformed data happens after valid single value assert!(loader().load_one(&[0xE0, 0x01, 0x00, 0xEA, 0x20, 0x30]).is_err());
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
borrowed | Provides borrowed implementations of |
loader | Provides utility to load Ion data into |
owned | Provides owned implementations of |
Enums
AnyInt | Container for either an integer that can fit in a 64-bit word or an arbitrarily sized
|
Traits
Builder | |
Element | 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. |
ImportSource | The shared symbol table source of a given |
IntAccess | Provides convenient integer accessors for integer values that are like |
Sequence | Represents the value of sequences of Ion elements (i.e. |
Struct | Represents the value of |
SymbolToken | A view of a symbolic token.
This can be either a symbol value itself, an annotation, or an field name.
A token may have |