Skip to content

Commit

Permalink
Doc cleanup and 2x bug fixes (#774)
Browse files Browse the repository at this point in the history
* s/LazyDecoder/Decoder/, s/LazyEncoder/Encoder/, rm `memmap` dep
* binary 1.0 reader checks bytes available when reading annotations seq
* Updated write_many_structs benchmark
* Updates README.md, makes `Text.with_format(...)` pub
* Fixes bug in calculation of unannotated value range
  • Loading branch information
zslayton authored May 24, 2024
1 parent 8a7b3a4 commit 85a4a31
Show file tree
Hide file tree
Showing 59 changed files with 369 additions and 386 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ rstest_reuse = "0.6.0"
# Used by ion-tests integration
walkdir = "2.5.0"
test-generator = "0.3"
memmap = "0.7.0"
criterion = "0.5.1"
rand = "0.8.5"
tempfile = "3.10.0"
Expand Down
33 changes: 16 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ A Rust implementation of the [Amazon Ion][spec] data format.

## Example

For more information, please see our [official documentation](https://docs.rs/ion-rs).
For more information, please see the [documentation](https://docs.rs/ion-rs).

```rust
use ion_rs::{Element, IonResult, IonType, ion_seq};
use crate::{ion_seq, Element, IonResult, Timestamp};

fn main() -> IonResult<()> {

// Read a single value from a string/slice/Vec
let element = Element::read_one("\"Hello, world!\"")?;
let text = element.expect_string()?;
Expand All @@ -35,25 +34,23 @@ fn main() -> IonResult<()> {
for element in Element::iter(ion_file)? {
println!("{}", element?)
}

// Construct a sequence of Ion elements from Rust values
let values = ion_seq!(
"foo",
Timestamp::with_ymd(2016, 5, 11).build(),
Timestamp::with_ymd(2016, 5, 11).build()?,
3.1416f64,
true
);

// Write values to a buffer in generously-spaced text
let mut text_buffer: Vec<u8> = Vec::new();
Element::write_all_as(&values, Format::Text(TextKind::Pretty), &mut text_buffer)?;
assert_eq!(values, Element::read_all(text_buffer)?);
// Write values to a String using generously-spaced text
let text_ion: String = values.encode_as(v1_0::Text.with_format(TextFormat::Pretty))?;
assert_eq!(values, Element::read_all(text_ion)?);

// Write values to a buffer in compact binary
let mut binary_buffer: Vec<u8> = Vec::new();
Element::write_all_as(&values, Format::Binary, &mut binary_buffer)?;
let binary_buffer: Vec<u8> = values.encode_as(v1_0::Binary)?;
assert_eq!(values, Element::read_all(binary_buffer)?);

Ok(())
}
```
Expand All @@ -64,11 +61,10 @@ The `ion_rs` library has a number of features that users can opt into. While the
are complete and well-tested, their APIs are not stable and are subject to change without notice
between minor versions of the library.

1. `experimental-ion-hash`, an implementation of [Ion Hash][ion-hash-spec].
2. `experimental-reader`, a streaming reader API.
3. `experimental-writer`, a streaming writer API.

Features that are defined in `Cargo.toml` but not listed above have not been thoroughly tested.
1. `experimental-reader-writer`, a streaming reader and writer API.
2. `experimental-tooling-apis`, APIs for accessing the encoding-level details of the stream.
3. `experimental-serde`, a `serde` serializer and deserializer.
4. `experimental-ion-hash`, an implementation of [Ion Hash][ion-hash-spec].

## Development

Expand Down Expand Up @@ -106,6 +102,9 @@ $ ./clean-rebuild.sh
```

[spec]: https://amazon-ion.github.io/ion-docs/docs/spec.html

[ion-tests]: https://github.com/amazon-ion/ion-tests

[ion-hash-spec]: https://amazon-ion.github.io/ion-hash/docs/spec.html

[ion-hash-tests]: https://github.com/amazon-ion/ion-hash-tests
8 changes: 4 additions & 4 deletions benches/read_many_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ mod benchmark {
mod benchmark {
use criterion::{black_box, Criterion};
use ion_rs::{v1_0, v1_1, ElementReader, Encoding, IonData, IonReader, WriteConfig};
use ion_rs::{Element, IonResult, LazyDecoder, LazyStruct, LazyValue, ValueRef};
use ion_rs::{Decoder, Element, IonResult, LazyStruct, LazyValue, ValueRef};

fn rewrite_as<E: Encoding>(
pretty_ion: &str,
Expand All @@ -24,7 +24,7 @@ mod benchmark {
Ok(buffer)
}

fn count_value_and_children<D: LazyDecoder>(lazy_value: &LazyValue<'_, D>) -> IonResult<usize> {
fn count_value_and_children<D: Decoder>(lazy_value: &LazyValue<'_, D>) -> IonResult<usize> {
use ValueRef::*;
let child_count = match lazy_value.read()? {
List(s) => count_sequence_children(s.iter())?,
Expand All @@ -38,7 +38,7 @@ mod benchmark {
Ok(1 + child_count)
}

fn count_sequence_children<'a, D: LazyDecoder>(
fn count_sequence_children<'a, D: Decoder>(
lazy_sequence: impl Iterator<Item = IonResult<LazyValue<'a, D>>>,
) -> IonResult<usize> {
let mut count = 0;
Expand All @@ -48,7 +48,7 @@ mod benchmark {
Ok(count)
}

fn count_struct_children<D: LazyDecoder>(lazy_struct: &LazyStruct<'_, D>) -> IonResult<usize> {
fn count_struct_children<D: Decoder>(lazy_struct: &LazyStruct<'_, D>) -> IonResult<usize> {
let mut count = 0;
for field in lazy_struct {
count += count_value_and_children(&field?.value())?;
Expand Down
20 changes: 9 additions & 11 deletions benches/write_many_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ mod benchmark {
#[cfg(feature = "experimental")]
mod benchmark {
use criterion::{black_box, Criterion};
use ion_rs::v1_0::LazyRawBinaryWriter_1_0;
use ion_rs::v1_1::LazyRawBinaryWriter_1_1;
use ion_rs::{IonResult, RawSymbolRef, SequenceWriter, StructWriter, ValueWriter};
use ion_rs::{v1_0, v1_1, IonResult, RawSymbolRef, SequenceWriter, StructWriter, ValueWriter};

fn write_struct_with_string_values(value_writer: impl ValueWriter) -> IonResult<()> {
let mut struct_ = value_writer.struct_writer()?;
Expand Down Expand Up @@ -131,7 +129,7 @@ mod benchmark {
binary_1_0_group.bench_function("write structs with string values", |b| {
b.iter(|| {
buffer.clear();
let mut writer = LazyRawBinaryWriter_1_0::new(&mut buffer).unwrap();
let mut writer = v1_0::RawBinaryWriter::new(&mut buffer).unwrap();
write_struct_with_string_values(writer.value_writer()).unwrap();
writer.flush().unwrap();
black_box(buffer.as_slice());
Expand All @@ -149,7 +147,7 @@ mod benchmark {
binary_1_0_group.bench_function("write structs with symbol values", |b| {
b.iter(|| {
buffer.clear();
let mut writer = LazyRawBinaryWriter_1_0::new(&mut buffer).unwrap();
let mut writer = v1_0::RawBinaryWriter::new(&mut buffer).unwrap();
write_struct_with_symbol_values(writer.value_writer()).unwrap();
writer.flush().unwrap();

Expand All @@ -166,7 +164,7 @@ mod benchmark {
binary_1_1_group.bench_function("write structs with string values", |b| {
b.iter(|| {
buffer.clear();
let mut writer = LazyRawBinaryWriter_1_1::new(&mut buffer).unwrap();
let mut writer = v1_1::RawBinaryWriter::new(&mut buffer).unwrap();
write_struct_with_string_values(writer.value_writer()).unwrap();
writer.flush().unwrap();
black_box(buffer.as_slice());
Expand All @@ -180,7 +178,7 @@ mod benchmark {
binary_1_1_group.bench_function("write structs with symbol values", |b| {
b.iter(|| {
buffer.clear();
let mut writer = LazyRawBinaryWriter_1_1::new(&mut buffer).unwrap();
let mut writer = v1_1::RawBinaryWriter::new(&mut buffer).unwrap();
write_struct_with_symbol_values(writer.value_writer()).unwrap();
writer.flush().unwrap();

Expand All @@ -195,7 +193,7 @@ mod benchmark {
binary_1_1_group.bench_function("write delimited structs with string values", |b| {
b.iter(|| {
buffer.clear();
let mut writer = LazyRawBinaryWriter_1_1::new(&mut buffer).unwrap();
let mut writer = v1_1::RawBinaryWriter::new(&mut buffer).unwrap();
write_struct_with_string_values(writer.value_writer().with_delimited_containers())
.unwrap();
writer.flush().unwrap();
Expand All @@ -213,7 +211,7 @@ mod benchmark {
binary_1_1_group.bench_function("write delimited structs with symbol values", |b| {
b.iter(|| {
buffer.clear();
let mut writer = LazyRawBinaryWriter_1_1::new(&mut buffer).unwrap();
let mut writer = v1_1::RawBinaryWriter::new(&mut buffer).unwrap();
write_struct_with_symbol_values(writer.value_writer().with_delimited_containers())
.unwrap();
writer.flush().unwrap();
Expand All @@ -229,7 +227,7 @@ mod benchmark {
binary_1_1_group.bench_function("write structs with string values using macros", |b| {
b.iter(|| {
buffer.clear();
let mut writer = LazyRawBinaryWriter_1_1::new(&mut buffer).unwrap();
let mut writer = v1_1::RawBinaryWriter::new(&mut buffer).unwrap();
write_eexp_with_string_values(writer.value_writer()).unwrap();
writer.flush().unwrap();
black_box(buffer.as_slice());
Expand All @@ -246,7 +244,7 @@ mod benchmark {
binary_1_1_group.bench_function("write structs with symbol values using macros", |b| {
b.iter(|| {
buffer.clear();
let mut writer = LazyRawBinaryWriter_1_1::new(&mut buffer).unwrap();
let mut writer = v1_1::RawBinaryWriter::new(&mut buffer).unwrap();
write_eexp_with_symbol_values(writer.value_writer()).unwrap();
writer.flush().unwrap();
black_box(buffer.as_slice());
Expand Down
19 changes: 6 additions & 13 deletions examples/read_all_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ mod lazy_reader_example {
use std::fs::File;
use std::process::exit;

use memmap::MmapOptions;

use ion_rs::{v1_0, Encoding, IonResult, LazyStruct, LazyValue, ValueRef};
use ion_rs::{Decoder, IonResult, LazyStruct, LazyValue, Reader, ValueRef};

pub fn read_all_values() -> IonResult<()> {
let args: Vec<String> = std::env::args().collect();
Expand All @@ -29,15 +27,10 @@ mod lazy_reader_example {
});

let file = File::open(path).unwrap();

// This example uses `mmap` so we can view the entire input file as a `&[u8]`.
let mmap = unsafe { MmapOptions::new().map(&file).unwrap() };
let ion_data: &[u8] = &mmap[..];

let mut reader = Reader::new(file)?;
// We're going to recursively visit and read every value in the input stream, counting
// them as we go.
let mut count = 0;
let mut reader = v1_0::BinaryReader::new(ion_data)?;
while let Some(lazy_value) = reader.next()? {
count += count_value_and_children(&lazy_value)?;
}
Expand All @@ -46,7 +39,7 @@ mod lazy_reader_example {
}

// Counts scalar values as 1 and container values as (the number of children) + 1.
fn count_value_and_children<E: Encoding>(lazy_value: &LazyValue<E>) -> IonResult<usize> {
fn count_value_and_children<D: Decoder>(lazy_value: &LazyValue<D>) -> IonResult<usize> {
use ValueRef::*;
let child_count = match lazy_value.read()? {
List(s) => count_sequence_children(s.iter())?,
Expand All @@ -57,8 +50,8 @@ mod lazy_reader_example {
Ok(1 + child_count)
}

fn count_sequence_children<'a, E: Encoding>(
lazy_sequence: impl Iterator<Item = IonResult<LazyValue<'a, E>>>,
fn count_sequence_children<'a, D: Decoder>(
lazy_sequence: impl Iterator<Item = IonResult<LazyValue<'a, D>>>,
) -> IonResult<usize> {
let mut count = 0;
for value in lazy_sequence {
Expand All @@ -67,7 +60,7 @@ mod lazy_reader_example {
Ok(count)
}

fn count_struct_children<E: Encoding>(lazy_struct: &LazyStruct<E>) -> IonResult<usize> {
fn count_struct_children<D: Decoder>(lazy_struct: &LazyStruct<D>) -> IonResult<usize> {
let mut count = 0;
for field in lazy_struct {
count += count_value_and_children(&field?.value())?;
Expand Down
6 changes: 3 additions & 3 deletions src/binary/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ where

#[cfg(test)]
mod binary_decimal_tests {
use crate::lazy::encoder::writer::IonWriter;
use crate::lazy::encoder::writer::Writer;
use crate::lazy::encoding::{BinaryEncoding_1_0, Encoding};
use crate::lazy::reader::Reader;
use rstest::*;
Expand Down Expand Up @@ -152,10 +152,10 @@ mod binary_decimal_tests {
#[case::foo(Decimal::new(i128::MIN + 1, i32::MIN))]
fn roundtrip_decimals_with_extreme_values(#[case] value: Decimal) -> IonResult<()> {
let mut writer =
IonWriter::with_config(BinaryEncoding_1_0::default_write_config(), Vec::new())?;
Writer::with_config(BinaryEncoding_1_0::default_write_config(), Vec::new())?;
writer.write(value)?;
let output = writer.close()?;
let mut reader = Reader::new(output);
let mut reader = Reader::new(output)?;
let after_round_trip = reader.expect_next()?.read()?.expect_decimal()?;
assert_eq!(value, after_round_trip);
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion src/binary/timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ mod binary_timestamp_tests {
#[case] input: &str,
#[case] expected: usize,
) -> IonResult<()> {
let mut reader = Reader::new(input);
let mut reader = Reader::new(input)?;
let timestamp = reader.expect_next()?.read()?.expect_timestamp()?;
let mut buf = vec![];
let written = buf.encode_timestamp_value(&timestamp)?;
Expand Down
8 changes: 4 additions & 4 deletions src/element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,14 +653,14 @@ impl Element {
/// If the data source has at least one value, returns `Ok(Some(Element))`.
/// If the data source has invalid data, returns `Err`.
pub fn read_first<A: AsRef<[u8]>>(data: A) -> IonResult<Option<Element>> {
let mut reader = Reader::new(IonSlice::new(data));
let mut reader = Reader::new(IonSlice::new(data))?;
reader.read_next_element()
}

/// Reads a single Ion [`Element`] from the provided data source. If the input has invalid
/// data or does not contain at exactly one Ion value, returns `Err(IonError)`.
pub fn read_one<A: AsRef<[u8]>>(data: A) -> IonResult<Element> {
let mut reader = Reader::new(IonSlice::new(data));
let mut reader = Reader::new(IonSlice::new(data))?;
reader.read_one_element()
}

Expand All @@ -669,7 +669,7 @@ impl Element {
/// If the input has valid data, returns `Ok(Sequence)`.
/// If the input has invalid data, returns `Err(IonError)`.
pub fn read_all<A: AsRef<[u8]>>(data: A) -> IonResult<Sequence> {
Ok(Reader::new(IonSlice::new(data))
Ok(Reader::new(IonSlice::new(data))?
.into_elements()
.collect::<IonResult<Vec<_>>>()?
.into())
Expand All @@ -681,7 +681,7 @@ impl Element {
pub fn iter<'a, I: IonInput + 'a>(
source: I,
) -> IonResult<impl Iterator<Item = IonResult<Element>> + 'a> {
Ok(Reader::new(source).into_elements())
Ok(Reader::new(source)?.into_elements())
}

/// Encodes this element as an Ion stream with itself as the only top-level value.
Expand Down
Loading

0 comments on commit 85a4a31

Please sign in to comment.