Skip to content

Commit

Permalink
Adds "experimental-reader" feature (amazon-ion#577)
Browse files Browse the repository at this point in the history
This PR is the first of a short series that will move the streaming types
behind an experimental feature. It is part of issue amazon-ion#576.

In this PR, we move the public re-exports of:
* `IonReader`
* `Reader`/`StreamItem`
* `SystemReader`/`SystemStreamItem`
* `RawReader`/`RawStreamItem`
* `BlockingRawReader`

behind the feature flag `"experimental-reader"`.

No behavior is changed, and internal modules can continue to access
these types as desired.
  • Loading branch information
zslayton authored Jun 20, 2023
1 parent 14c4582 commit 247ac34
Show file tree
Hide file tree
Showing 19 changed files with 226 additions and 376 deletions.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@ ion-hash = ["digest"]
# Feature for indicating particularly bleeding edge APIs or functionality in the library.
# These are not guaranteed any sort of API stability and may also have non-standard
# Ion behavior (e.g., draft Ion 1.1 capabilities).
experimental = ["experimental-streaming", "experimental-lazy-reader"]
experimental = ["experimental-streaming", "experimental-reader", "experimental-lazy-reader"]

# Experimental streaming APIs
experimental-streaming = []

# Access to the `IonReader` trait, its implementations, and the `ReaderBuilder` requires enabling this feature.
# These APIs are functional and well-tested, but are not yet stable.
experimental-reader = []

# A reader API that parks on a top-level value and yields 'lazy' handles to the data
# contained therein. These lazy handles can be read multiple times, allowing for
# an inexpensive form of 'rewind' functionality.
Expand Down
309 changes: 161 additions & 148 deletions examples/read_all_values.rs
Original file line number Diff line number Diff line change
@@ -1,166 +1,179 @@
use ion_rs::binary::non_blocking::raw_binary_reader::RawBinaryReader;
use ion_rs::raw_reader::RawStreamItem;
use ion_rs::result::IonResult;
use ion_rs::{BlockingRawBinaryReader, IonReader, IonType, RawReader, StreamItem, UserReader};
use memmap::MmapOptions;
use std::fs::File;
use std::process::exit;
#[cfg(not(feature = "experimental-reader"))]
fn main() {
println!("This example requires the 'experimental-reader' feature to work.");
}

fn main() -> IonResult<()> {
let args: Vec<String> = std::env::args().collect();
let mode = args.get(1).unwrap_or_else(|| {
eprintln!(
"USAGE:\n\n {} [raw-blocking|raw-nonblocking|user] [Binary Ion file]\n",
args.get(0).unwrap()
);
eprintln!("No mode was specified.");
exit(1);
});
let path = args.get(2).unwrap_or_else(|| {
eprintln!(
"USAGE:\n\n {} [raw-blocking|raw-nonblocking|user] [Binary Ion file]\n",
args.get(0).unwrap()
);
eprintln!("No input file was specified.");
exit(2);
});
let file = File::open(path).unwrap();
#[cfg(feature = "experimental-reader")]
fn main() {
example::main().unwrap();
}

// This example uses `mmap` so we can use either the blocking reader (which reads from an
// io::BufRead) or the non-blocking reader (which reads from an AsRef<[u8]>).
let mmap = unsafe { MmapOptions::new().map(&file).unwrap() };
#[cfg(feature = "experimental-reader")]
mod example {
use ion_rs::binary::non_blocking::raw_binary_reader::RawBinaryReader;
use ion_rs::result::IonResult;
use ion_rs::RawStreamItem;
use ion_rs::{BlockingRawBinaryReader, IonReader, IonType, RawReader, StreamItem, UserReader};
use memmap::MmapOptions;
use std::fs::File;
use std::process::exit;

// Treat the mmap as a byte array.
let ion_data: &[u8] = &mmap[..];
pub fn main() -> IonResult<()> {
let args: Vec<String> = std::env::args().collect();
let mode = args.get(1).unwrap_or_else(|| {
eprintln!(
"USAGE:\n\n {} [raw-blocking|raw-nonblocking|user] [Binary Ion file]\n",
args.get(0).unwrap()
);
eprintln!("No mode was specified.");
exit(1);
});
let path = args.get(2).unwrap_or_else(|| {
eprintln!(
"USAGE:\n\n {} [raw-blocking|raw-nonblocking|user] [Binary Ion file]\n",
args.get(0).unwrap()
);
eprintln!("No input file was specified.");
exit(2);
});
let file = File::open(path).unwrap();

if mode == "raw-blocking" {
let mut reader = BlockingRawBinaryReader::new(ion_data)?;
let number_of_values = read_all_values_raw(&mut reader)?;
println!("Blocking: read {} values", number_of_values);
} else if mode == "raw-nonblocking" {
let mut reader = RawBinaryReader::new(ion_data);
let number_of_values = read_all_values_raw(&mut reader)?;
println!("Non-blocking: read {} values", number_of_values);
} else if mode == "user" {
let raw_reader = RawBinaryReader::new(ion_data);
let mut reader = UserReader::new(raw_reader);
let number_of_values = read_all_values(&mut reader)?;
println!("Non-blocking: read {} values", number_of_values);
} else {
eprintln!("Unsupported `mode`: {}.", mode);
exit(3);
}
// This example uses `mmap` so we can use either the blocking reader (which reads from an
// io::BufRead) or the non-blocking reader (which reads from an AsRef<[u8]>).
let mmap = unsafe { MmapOptions::new().map(&file).unwrap() };

Ok(())
}
// Treat the mmap as a byte array.
let ion_data: &[u8] = &mmap[..];

// Visits each value in the stream recursively, reading each scalar into a native Rust type.
// Prints the total number of values read upon completion.
fn read_all_values_raw<R: RawReader>(reader: &mut R) -> IonResult<usize> {
use IonType::*;
use RawStreamItem::{Nothing, Null as NullValue, Value, VersionMarker};
let mut count: usize = 0;
loop {
match reader.next()? {
VersionMarker(_major, _minor) => {}
NullValue(_ion_type) => {
count += 1;
continue;
}
Value(ion_type) => {
count += 1;
match ion_type {
Struct | List | SExp => reader.step_in()?,
String => {
let _string = reader.read_str()?;
}
Symbol => {
let _symbol_id = reader.read_symbol()?;
}
Int => {
let _int = reader.read_i64()?;
}
Float => {
let _float = reader.read_f64()?;
}
Decimal => {
let _decimal = reader.read_decimal()?;
}
Timestamp => {
let _timestamp = reader.read_timestamp()?;
}
Bool => {
let _boolean = reader.read_bool()?;
}
Blob => {
let _blob = reader.read_blob()?;
}
Clob => {
let _clob = reader.read_clob()?;
if mode == "raw-blocking" {
let mut reader = BlockingRawBinaryReader::new(ion_data)?;
let number_of_values = read_all_values_raw(&mut reader)?;
println!("Blocking: read {} values", number_of_values);
} else if mode == "raw-nonblocking" {
let mut reader = RawBinaryReader::new(ion_data);
let number_of_values = read_all_values_raw(&mut reader)?;
println!("Non-blocking: read {} values", number_of_values);
} else if mode == "user" {
let raw_reader = RawBinaryReader::new(ion_data);
let mut reader = UserReader::new(raw_reader);
let number_of_values = read_all_values(&mut reader)?;
println!("Non-blocking: read {} values", number_of_values);
} else {
eprintln!("Unsupported `mode`: {}.", mode);
exit(3);
}

Ok(())
}

// Visits each value in the stream recursively, reading each scalar into a native Rust type.
// Prints the total number of values read upon completion.
fn read_all_values_raw<R: RawReader>(reader: &mut R) -> IonResult<usize> {
use IonType::*;
use RawStreamItem::{Nothing, Null as NullValue, Value, VersionMarker};
let mut count: usize = 0;
loop {
match reader.next()? {
VersionMarker(_major, _minor) => {}
NullValue(_ion_type) => {
count += 1;
continue;
}
Value(ion_type) => {
count += 1;
match ion_type {
Struct | List | SExp => reader.step_in()?,
String => {
let _string = reader.read_str()?;
}
Symbol => {
let _symbol_id = reader.read_symbol()?;
}
Int => {
let _int = reader.read_i64()?;
}
Float => {
let _float = reader.read_f64()?;
}
Decimal => {
let _decimal = reader.read_decimal()?;
}
Timestamp => {
let _timestamp = reader.read_timestamp()?;
}
Bool => {
let _boolean = reader.read_bool()?;
}
Blob => {
let _blob = reader.read_blob()?;
}
Clob => {
let _clob = reader.read_clob()?;
}
Null => {}
}
Null => {}
}
Nothing if reader.depth() > 0 => {
reader.step_out()?;
}
_ => break,
}
Nothing if reader.depth() > 0 => {
reader.step_out()?;
}
_ => break,
}
Ok(count)
}
Ok(count)
}

// Visits each value in the stream recursively, reading each scalar into a native Rust type.
// Prints the total number of values read upon completion.
fn read_all_values<R: IonReader<Item = StreamItem>>(reader: &mut R) -> IonResult<usize> {
use IonType::*;
use StreamItem::{Nothing, Null as NullValue, Value};
let mut count: usize = 0;
loop {
match reader.next()? {
NullValue(_ion_type) => {
count += 1;
continue;
}
Value(ion_type) => {
count += 1;
match ion_type {
Struct | List | SExp => reader.step_in()?,
String => {
let _string = reader.read_str()?;
}
Symbol => {
let _symbol_id = reader.read_symbol()?;
}
Int => {
let _int = reader.read_i64()?;
}
Float => {
let _float = reader.read_f64()?;
}
Decimal => {
let _decimal = reader.read_decimal()?;
}
Timestamp => {
let _timestamp = reader.read_timestamp()?;
}
Bool => {
let _boolean = reader.read_bool()?;
}
Blob => {
let _blob = reader.read_blob()?;
}
Clob => {
let _clob = reader.read_clob()?;
// Visits each value in the stream recursively, reading each scalar into a native Rust type.
// Prints the total number of values read upon completion.
fn read_all_values<R: IonReader<Item = StreamItem>>(reader: &mut R) -> IonResult<usize> {
use IonType::*;
use StreamItem::{Nothing, Null as NullValue, Value};
let mut count: usize = 0;
loop {
match reader.next()? {
NullValue(_ion_type) => {
count += 1;
continue;
}
Value(ion_type) => {
count += 1;
match ion_type {
Struct | List | SExp => reader.step_in()?,
String => {
let _string = reader.read_str()?;
}
Symbol => {
let _symbol_id = reader.read_symbol()?;
}
Int => {
let _int = reader.read_i64()?;
}
Float => {
let _float = reader.read_f64()?;
}
Decimal => {
let _decimal = reader.read_decimal()?;
}
Timestamp => {
let _timestamp = reader.read_timestamp()?;
}
Bool => {
let _boolean = reader.read_bool()?;
}
Blob => {
let _blob = reader.read_blob()?;
}
Clob => {
let _clob = reader.read_clob()?;
}
Null => {}
}
Null => {}
}
Nothing if reader.depth() > 0 => {
reader.step_out()?;
}
_ => break,
}
Nothing if reader.depth() > 0 => {
reader.step_out()?;
}
_ => break,
}
Ok(count)
}
Ok(count)
}
4 changes: 2 additions & 2 deletions src/binary/binary_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,10 @@ impl<W: Write> IonWriter for BinaryWriter<W> {
#[cfg(test)]
mod tests {
use super::*;
use crate::ion_reader::IonReader;
use crate::reader::ReaderBuilder;
use crate::stream_reader::IonReader;

use crate::StreamItem::Value;
use crate::reader::StreamItem::Value;

#[test]
fn intern_field_names() -> IonResult<()> {
Expand Down
5 changes: 3 additions & 2 deletions src/binary/non_blocking/raw_binary_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ use crate::binary::non_blocking::type_descriptor::{Header, TypeDescriptor};
use crate::binary::uint::DecodedUInt;
use crate::binary::var_uint::VarUInt;
use crate::binary::IonTypeCode;
use crate::raw_reader::{BufferedRawReader, Expandable};
use crate::ion_reader::IonReader;
use crate::raw_reader::{BufferedRawReader, Expandable, RawStreamItem};
use crate::result::{
decoding_error, decoding_error_raw, illegal_operation, illegal_operation_raw,
incomplete_data_error,
};
use crate::types::{Blob, Clob, Decimal, IntAccess, Str, SymbolId};
use crate::{Int, IonReader, IonResult, IonType, RawStreamItem, RawSymbolToken, Timestamp};
use crate::{Int, IonResult, IonType, RawSymbolToken, Timestamp};
use bytes::{BigEndian, Buf, ByteOrder};
use num_bigint::BigUint;
use num_traits::Zero;
Expand Down
6 changes: 2 additions & 4 deletions src/binary/raw_binary_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,15 +904,13 @@ impl<W: Write> IonWriter for RawBinaryWriter<W> {
mod writer_tests {
use std::fmt::Debug;

use crate::StreamItem;

use rstest::*;

use super::*;
use crate::ion_reader::IonReader;
use crate::raw_symbol_token::{local_sid_token, RawSymbolToken};
use crate::reader::{Reader, ReaderBuilder};
use crate::reader::{Reader, ReaderBuilder, StreamItem};
use crate::types::{Blob, Clob, Symbol};
use crate::IonReader;
use num_bigint::BigInt;
use num_traits::Float;
use std::convert::TryInto;
Expand Down
Loading

0 comments on commit 247ac34

Please sign in to comment.