This is an automated email from the ASF dual-hosted git repository.
kriskras99 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/avro-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 927847a feat: Replace `from_avro_datum*` functions with
`GenericDatumReader` (#496)
927847a is described below
commit 927847a410f167dfec314ff9acb72bc5508392a1
Author: Kriskras99 <[email protected]>
AuthorDate: Thu Mar 5 11:09:09 2026 +0100
feat: Replace `from_avro_datum*` functions with `GenericDatumReader` (#496)
* feat: Replace `from_avro_datum*` functions with `GenericDatumReader`
* fix: Replace old naming
---
avro/src/lib.rs | 21 +-
avro/src/reader/datum.rs | 351 ++++++++++++++++++++++++++++++
avro/src/reader/mod.rs | 174 +--------------
avro/src/schema/mod.rs | 12 +-
avro/src/schema/resolve.rs | 2 +-
avro/src/serde/de.rs | 6 +-
avro/src/writer/datum.rs | 8 +-
avro/tests/avro-3786.rs | 32 ++-
avro/tests/avro-3787.rs | 12 +-
avro/tests/io.rs | 63 +++---
avro/tests/schema.rs | 14 +-
avro/tests/to_from_avro_datum_schemata.rs | 24 +-
12 files changed, 472 insertions(+), 247 deletions(-)
diff --git a/avro/src/lib.rs b/avro/src/lib.rs
index f2f9975..314d596 100644
--- a/avro/src/lib.rs
+++ b/avro/src/lib.rs
@@ -56,13 +56,13 @@ mod decimal;
mod decode;
mod duration;
mod encode;
-mod reader;
#[cfg(doc)]
pub mod documentation;
pub mod error;
pub mod headers;
pub mod rabin;
+pub mod reader;
pub mod schema;
pub mod schema_compatibility;
pub mod schema_equality;
@@ -90,8 +90,13 @@ pub use codec::{Codec, DeflateSettings};
pub use decimal::Decimal;
pub use duration::{Days, Duration, Millis, Months};
pub use error::Error;
+#[expect(
+ deprecated,
+ reason = "Still need to export it until we remove it completely"
+)]
pub use reader::{
- Reader, from_avro_datum, from_avro_datum_reader_schemata,
from_avro_datum_schemata,
+ Reader,
+ datum::{from_avro_datum, from_avro_datum_reader_schemata,
from_avro_datum_schemata},
read_marker,
single_object::{GenericSingleObjectReader, SpecificSingleObjectReader},
};
@@ -154,9 +159,11 @@ pub fn set_serde_human_readable(human_readable: bool) ->
bool {
#[cfg(test)]
mod tests {
use crate::{
- Codec, Reader, Schema, Writer, from_avro_datum,
+ Codec, Reader, Schema, Writer,
+ reader::datum::GenericDatumReader,
types::{Record, Value},
};
+ use apache_avro_test_helper::TestResult;
use pretty_assertions::assert_eq;
//TODO: move where it fits better
@@ -301,7 +308,7 @@ mod tests {
}
#[test]
- fn test_illformed_length() {
+ fn test_illformed_length() -> TestResult {
let raw_schema = r#"
{
"type": "record",
@@ -318,7 +325,11 @@ mod tests {
// Would allocate 18446744073709551605 bytes
let illformed: &[u8] = &[0x3e, 0x15, 0xff, 0x1f, 0x15, 0xff];
- let value = from_avro_datum(&schema, &mut &*illformed, None);
+ let value = GenericDatumReader::builder(&schema)
+ .build()?
+ .read_value(&mut &*illformed);
assert!(value.is_err());
+
+ Ok(())
}
}
diff --git a/avro/src/reader/datum.rs b/avro/src/reader/datum.rs
new file mode 100644
index 0000000..80fe937
--- /dev/null
+++ b/avro/src/reader/datum.rs
@@ -0,0 +1,351 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::io::Read;
+
+use bon::bon;
+
+use crate::{AvroResult, Schema, decode::decode_internal,
schema::ResolvedSchema, types::Value};
+
+/// Reader for reading raw Avro data.
+///
+/// This is most likely not what you need. Most users should use
[`Reader`][crate::Reader],
+/// [`GenericSingleObjectReader`][crate::GenericSingleObjectReader], or
+/// [`SpecificSingleObjectReader`][crate::SpecificSingleObjectReader] instead.
+pub struct GenericDatumReader<'s> {
+ writer: &'s Schema,
+ resolved: ResolvedSchema<'s>,
+ reader: Option<(&'s Schema, ResolvedSchema<'s>)>,
+}
+
+#[bon]
+impl<'s> GenericDatumReader<'s> {
+ /// Build a [`GenericDatumReader`].
+ ///
+ /// This is most likely not what you need. Most users should use
[`Reader`][crate::Reader],
+ /// [`GenericSingleObjectReader`][crate::GenericSingleObjectReader], or
+ /// [`SpecificSingleObjectReader`][crate::SpecificSingleObjectReader]
instead.
+ #[builder]
+ pub fn new(
+ /// The schema that was used to write the Avro datum.
+ #[builder(start_fn)]
+ writer_schema: &'s Schema,
+ /// Already resolved schemata that will be used to resolve references
in the writer's schema.
+ resolved_writer_schemata: Option<ResolvedSchema<'s>>,
+ /// The schema that will be used to resolve the value to conform the
the new schema.
+ reader_schema: Option<&'s Schema>,
+ /// Already resolved schemata that will be used to resolve references
in the reader's schema.
+ resolved_reader_schemata: Option<ResolvedSchema<'s>>,
+ ) -> AvroResult<Self> {
+ let resolved_writer_schemata = if let Some(resolved) =
resolved_writer_schemata {
+ resolved
+ } else {
+ ResolvedSchema::try_from(writer_schema)?
+ };
+
+ let reader = if let Some(reader) = reader_schema {
+ if let Some(resolved) = resolved_reader_schemata {
+ Some((reader, resolved))
+ } else {
+ Some((reader, ResolvedSchema::try_from(reader)?))
+ }
+ } else {
+ None
+ };
+
+ Ok(Self {
+ writer: writer_schema,
+ resolved: resolved_writer_schemata,
+ reader,
+ })
+ }
+}
+
+impl<'s, S: generic_datum_reader_builder::State> GenericDatumReaderBuilder<'s,
S> {
+ /// Set the schemata that will be used to resolve any references in the
writer's schema.
+ ///
+ /// This is equivalent to
`.resolved_writer_schemata(ResolvedSchema::new_with_schemata(schemata)?)`.
+ /// If you already have a [`ResolvedSchema`], use that function instead.
+ pub fn writer_schemata(
+ self,
+ schemata: Vec<&'s Schema>,
+ ) -> AvroResult<
+ GenericDatumReaderBuilder<'s,
generic_datum_reader_builder::SetResolvedWriterSchemata<S>>,
+ >
+ where
+ S::ResolvedWriterSchemata: generic_datum_reader_builder::IsUnset,
+ {
+ let resolved = ResolvedSchema::new_with_schemata(schemata)?;
+ Ok(self.resolved_writer_schemata(resolved))
+ }
+
+ /// Set the schemata that will be used to resolve any references in the
reader's schema.
+ ///
+ /// This is equivalent to
`.resolved_reader_schemata(ResolvedSchema::new_with_schemata(schemata)?)`.
+ /// If you already have a [`ResolvedSchema`], use that function instead.
+ ///
+ /// This function can only be called after the reader schema is set.
+ pub fn reader_schemata(
+ self,
+ schemata: Vec<&'s Schema>,
+ ) -> AvroResult<
+ GenericDatumReaderBuilder<'s,
generic_datum_reader_builder::SetResolvedReaderSchemata<S>>,
+ >
+ where
+ S::ResolvedReaderSchemata: generic_datum_reader_builder::IsUnset,
+ S::ReaderSchema: generic_datum_reader_builder::IsSet,
+ {
+ let resolved = ResolvedSchema::new_with_schemata(schemata)?;
+ Ok(self.resolved_reader_schemata(resolved))
+ }
+}
+
+impl<'s> GenericDatumReader<'s> {
+ /// Read a Avro datum from the reader.
+ pub fn read_value<R: Read>(&self, reader: &mut R) -> AvroResult<Value> {
+ let value = decode_internal(self.writer, self.resolved.get_names(),
None, reader)?;
+ if let Some((reader, resolved)) = &self.reader {
+ value.resolve_internal(reader, resolved.get_names(), None, &None)
+ } else {
+ Ok(value)
+ }
+ }
+}
+
+/// Deprecated.
+///
+/// This is equivalent to
+/// ```ignore
+/// GenericDatumReader::builder(writer_schema)
+/// .maybe_reader_schema(reader_schema)
+/// .build()?
+/// .read_value(reader)
+/// ```
+///
+/// Decode a `Value` encoded in Avro format given its `Schema` and anything
implementing `io::Read`
+/// to read from.
+///
+/// In case a reader `Schema` is provided, schema resolution will also be
performed.
+///
+/// **NOTE** This function has a quite small niche of usage and does NOT take
care of reading the
+/// header and consecutive data blocks; use [`Reader`](struct.Reader.html) if
you don't know what
+/// you are doing, instead.
+#[deprecated(since = "0.22.0", note = "Use `GenericDatumReader` instead")]
+pub fn from_avro_datum<R: Read>(
+ writer_schema: &Schema,
+ reader: &mut R,
+ reader_schema: Option<&Schema>,
+) -> AvroResult<Value> {
+ GenericDatumReader::builder(writer_schema)
+ .maybe_reader_schema(reader_schema)
+ .build()?
+ .read_value(reader)
+}
+
+/// Deprecated.
+///
+/// This is equivalent to
+/// ```ignore
+/// GenericDatumReader::builder(writer_schema)
+/// .writer_schemata(writer_schemata)?
+/// .maybe_reader_schema(reader_schema)
+/// .build()?
+/// .read_value(reader)
+/// ```
+///
+/// Decode a `Value` from raw Avro data.
+///
+/// If the writer schema is incomplete, i.e. contains `Schema::Ref`s then it
will use the provided
+/// schemata to resolve any dependencies.
+///
+/// When a reader `Schema` is provided, schema resolution will also be
performed.
+#[deprecated(since = "0.22.0", note = "Use `GenericDatumReader` instead")]
+pub fn from_avro_datum_schemata<R: Read>(
+ writer_schema: &Schema,
+ writer_schemata: Vec<&Schema>,
+ reader: &mut R,
+ reader_schema: Option<&Schema>,
+) -> AvroResult<Value> {
+ GenericDatumReader::builder(writer_schema)
+ .writer_schemata(writer_schemata)?
+ .maybe_reader_schema(reader_schema)
+ .build()?
+ .read_value(reader)
+}
+
+/// Deprecated.
+///
+/// This is equivalent to
+/// ```ignore
+/// GenericDatumReader::builder(writer_schema)
+/// .writer_schemata(writer_schemata)?
+/// .maybe_reader_schema(reader_schema)
+/// .reader_schemata(reader_schemata)?
+/// .build()?
+/// .read_value(reader)
+/// ```
+///
+/// Decode a `Value` from raw Avro data.
+///
+/// If the writer schema is incomplete, i.e. contains `Schema::Ref`s then it
will use the provided
+/// schemata to resolve any dependencies.
+///
+/// When a reader `Schema` is provided, schema resolution will also be
performed.
+#[deprecated(since = "0.22.0", note = "Use `GenericDatumReader` instead")]
+pub fn from_avro_datum_reader_schemata<R: Read>(
+ writer_schema: &Schema,
+ writer_schemata: Vec<&Schema>,
+ reader: &mut R,
+ reader_schema: Option<&Schema>,
+ reader_schemata: Vec<&Schema>,
+) -> AvroResult<Value> {
+ GenericDatumReader::builder(writer_schema)
+ .writer_schemata(writer_schemata)?
+ .maybe_reader_schema(reader_schema)
+ .reader_schemata(reader_schemata)?
+ .build()?
+ .read_value(reader)
+}
+
+#[cfg(test)]
+mod tests {
+ use apache_avro_test_helper::TestResult;
+ use serde::Deserialize;
+
+ use crate::{
+ Schema, from_value,
+ reader::datum::GenericDatumReader,
+ types::{Record, Value},
+ };
+
+ #[test]
+ fn test_from_avro_datum() -> TestResult {
+ let schema = Schema::parse_str(
+ r#"{
+ "type": "record",
+ "name": "test",
+ "fields": [
+ {
+ "name": "a",
+ "type": "long",
+ "default": 42
+ },
+ {
+ "name": "b",
+ "type": "string"
+ }
+ ]
+ }"#,
+ )?;
+ let mut encoded: &'static [u8] = &[54, 6, 102, 111, 111];
+
+ let mut record = Record::new(&schema).unwrap();
+ record.put("a", 27i64);
+ record.put("b", "foo");
+ let expected = record.into();
+
+ let avro_datum = GenericDatumReader::builder(&schema)
+ .build()?
+ .read_value(&mut encoded)?;
+
+ assert_eq!(avro_datum, expected);
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_from_avro_datum_with_union_to_struct() -> TestResult {
+ const TEST_RECORD_SCHEMA_3240: &str = r#"
+ {
+ "type": "record",
+ "name": "test",
+ "fields": [
+ {
+ "name": "a",
+ "type": "long",
+ "default": 42
+ },
+ {
+ "name": "b",
+ "type": "string"
+ },
+ {
+ "name": "a_nullable_array",
+ "type": ["null", {"type": "array", "items": {"type": "string"}}],
+ "default": null
+ },
+ {
+ "name": "a_nullable_boolean",
+ "type": ["null", {"type": "boolean"}],
+ "default": null
+ },
+ {
+ "name": "a_nullable_string",
+ "type": ["null", {"type": "string"}],
+ "default": null
+ }
+ ]
+ }
+ "#;
+ #[derive(Default, Debug, Deserialize, PartialEq, Eq)]
+ struct TestRecord3240 {
+ a: i64,
+ b: String,
+ a_nullable_array: Option<Vec<String>>,
+ // we are missing the 'a_nullable_boolean' field to simulate
missing keys
+ // a_nullable_boolean: Option<bool>,
+ a_nullable_string: Option<String>,
+ }
+
+ let schema = Schema::parse_str(TEST_RECORD_SCHEMA_3240)?;
+ let mut encoded: &'static [u8] = &[54, 6, 102, 111, 111];
+
+ let expected_record: TestRecord3240 = TestRecord3240 {
+ a: 27i64,
+ b: String::from("foo"),
+ a_nullable_array: None,
+ a_nullable_string: None,
+ };
+
+ let avro_datum = GenericDatumReader::builder(&schema)
+ .build()?
+ .read_value(&mut encoded)?;
+ let parsed_record: TestRecord3240 = match &avro_datum {
+ Value::Record(_) => from_value::<TestRecord3240>(&avro_datum)?,
+ unexpected => {
+ panic!("could not map avro data to struct, found unexpected:
{unexpected:?}")
+ }
+ };
+
+ assert_eq!(parsed_record, expected_record);
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_null_union() -> TestResult {
+ let schema = Schema::parse_str(r#"["null", "long"]"#)?;
+ let mut encoded: &'static [u8] = &[2, 0];
+
+ let avro_datum = GenericDatumReader::builder(&schema)
+ .build()?
+ .read_value(&mut encoded)?;
+ assert_eq!(avro_datum, Value::Union(1, Box::new(Value::Long(0))));
+
+ Ok(())
+ }
+}
diff --git a/avro/src/reader/mod.rs b/avro/src/reader/mod.rs
index 0113e50..94af909 100644
--- a/avro/src/reader/mod.rs
+++ b/avro/src/reader/mod.rs
@@ -18,14 +18,10 @@
//! Logic handling reading from Avro format at user level.
mod block;
+pub mod datum;
pub mod single_object;
-use crate::{
- AvroResult,
- decode::{decode, decode_internal},
- schema::{ResolvedSchema, Schema},
- types::Value,
-};
+use crate::{AvroResult, schema::Schema, types::Value};
use block::Block;
use bon::bon;
use std::{collections::HashMap, io::Read};
@@ -137,74 +133,6 @@ impl<R: Read> Iterator for Reader<'_, R> {
}
}
-/// Decode a `Value` encoded in Avro format given its `Schema` and anything
implementing `io::Read`
-/// to read from.
-///
-/// In case a reader `Schema` is provided, schema resolution will also be
performed.
-///
-/// **NOTE** This function has a quite small niche of usage and does NOT take
care of reading the
-/// header and consecutive data blocks; use [`Reader`](struct.Reader.html) if
you don't know what
-/// you are doing, instead.
-pub fn from_avro_datum<R: Read>(
- writer_schema: &Schema,
- reader: &mut R,
- reader_schema: Option<&Schema>,
-) -> AvroResult<Value> {
- let value = decode(writer_schema, reader)?;
- match reader_schema {
- Some(schema) => value.resolve(schema),
- None => Ok(value),
- }
-}
-
-/// Decode a `Value` from raw Avro data.
-///
-/// If the writer schema is incomplete, i.e. contains `Schema::Ref`s then it
will use the provided
-/// schemata to resolve any dependencies.
-///
-/// When a reader `Schema` is provided, schema resolution will also be
performed.
-pub fn from_avro_datum_schemata<R: Read>(
- writer_schema: &Schema,
- writer_schemata: Vec<&Schema>,
- reader: &mut R,
- reader_schema: Option<&Schema>,
-) -> AvroResult<Value> {
- from_avro_datum_reader_schemata(
- writer_schema,
- writer_schemata,
- reader,
- reader_schema,
- Vec::with_capacity(0),
- )
-}
-
-/// Decode a `Value` from raw Avro data.
-///
-/// If the writer schema is incomplete, i.e. contains `Schema::Ref`s then it
will use the provided
-/// schemata to resolve any dependencies.
-///
-/// When a reader `Schema` is provided, schema resolution will also be
performed.
-pub fn from_avro_datum_reader_schemata<R: Read>(
- writer_schema: &Schema,
- writer_schemata: Vec<&Schema>,
- reader: &mut R,
- reader_schema: Option<&Schema>,
- reader_schemata: Vec<&Schema>,
-) -> AvroResult<Value> {
- let rs = ResolvedSchema::try_from(writer_schemata)?;
- let value = decode_internal(writer_schema, rs.get_names(), None, reader)?;
- match reader_schema {
- Some(schema) => {
- if reader_schemata.is_empty() {
- value.resolve(schema)
- } else {
- value.resolve_schemata(schema, reader_schemata)
- }
- }
- None => Ok(value),
- }
-}
-
/// Reads the marker bytes from Avro bytes generated earlier by a `Writer`
pub fn read_marker(bytes: &[u8]) -> [u8; 16] {
assert!(
@@ -219,11 +147,9 @@ pub fn read_marker(bytes: &[u8]) -> [u8; 16] {
#[cfg(test)]
mod tests {
use super::*;
- use crate::from_value;
use crate::types::Record;
use apache_avro_test_helper::TestResult;
use pretty_assertions::assert_eq;
- use serde::Deserialize;
use std::io::Cursor;
const SCHEMA: &str = r#"
@@ -243,7 +169,6 @@ mod tests {
]
}
"#;
- const UNION_SCHEMA: &str = r#"["null", "long"]"#;
const ENCODED: &[u8] = &[
79u8, 98u8, 106u8, 1u8, 4u8, 22u8, 97u8, 118u8, 114u8, 111u8, 46u8,
115u8, 99u8, 104u8,
101u8, 109u8, 97u8, 222u8, 1u8, 123u8, 34u8, 116u8, 121u8, 112u8,
101u8, 34u8, 58u8, 34u8,
@@ -261,101 +186,6 @@ mod tests {
207u8, 108u8, 180u8, 158u8, 57u8, 114u8, 40u8, 173u8, 199u8, 228u8,
239u8,
];
- #[test]
- fn test_from_avro_datum() -> TestResult {
- let schema = Schema::parse_str(SCHEMA)?;
- let mut encoded: &'static [u8] = &[54, 6, 102, 111, 111];
-
- let mut record = Record::new(&schema).unwrap();
- record.put("a", 27i64);
- record.put("b", "foo");
- let expected = record.into();
-
- assert_eq!(from_avro_datum(&schema, &mut encoded, None)?, expected);
-
- Ok(())
- }
-
- #[test]
- fn test_from_avro_datum_with_union_to_struct() -> TestResult {
- const TEST_RECORD_SCHEMA_3240: &str = r#"
- {
- "type": "record",
- "name": "test",
- "fields": [
- {
- "name": "a",
- "type": "long",
- "default": 42
- },
- {
- "name": "b",
- "type": "string"
- },
- {
- "name": "a_nullable_array",
- "type": ["null", {"type": "array", "items": {"type": "string"}}],
- "default": null
- },
- {
- "name": "a_nullable_boolean",
- "type": ["null", {"type": "boolean"}],
- "default": null
- },
- {
- "name": "a_nullable_string",
- "type": ["null", {"type": "string"}],
- "default": null
- }
- ]
- }
- "#;
- #[derive(Default, Debug, Deserialize, PartialEq, Eq)]
- struct TestRecord3240 {
- a: i64,
- b: String,
- a_nullable_array: Option<Vec<String>>,
- // we are missing the 'a_nullable_boolean' field to simulate
missing keys
- // a_nullable_boolean: Option<bool>,
- a_nullable_string: Option<String>,
- }
-
- let schema = Schema::parse_str(TEST_RECORD_SCHEMA_3240)?;
- let mut encoded: &'static [u8] = &[54, 6, 102, 111, 111];
-
- let expected_record: TestRecord3240 = TestRecord3240 {
- a: 27i64,
- b: String::from("foo"),
- a_nullable_array: None,
- a_nullable_string: None,
- };
-
- let avro_datum = from_avro_datum(&schema, &mut encoded, None)?;
- let parsed_record: TestRecord3240 = match &avro_datum {
- Value::Record(_) => from_value::<TestRecord3240>(&avro_datum)?,
- unexpected => {
- panic!("could not map avro data to struct, found unexpected:
{unexpected:?}")
- }
- };
-
- assert_eq!(parsed_record, expected_record);
-
- Ok(())
- }
-
- #[test]
- fn test_null_union() -> TestResult {
- let schema = Schema::parse_str(UNION_SCHEMA)?;
- let mut encoded: &'static [u8] = &[2, 0];
-
- assert_eq!(
- from_avro_datum(&schema, &mut encoded, None)?,
- Value::Union(1, Box::new(Value::Long(0)))
- );
-
- Ok(())
- }
-
#[test]
fn test_reader_iterator() -> TestResult {
let schema = Schema::parse_str(SCHEMA)?;
diff --git a/avro/src/schema/mod.rs b/avro/src/schema/mod.rs
index 91b0450..893b13c 100644
--- a/avro/src/schema/mod.rs
+++ b/avro/src/schema/mod.rs
@@ -1169,7 +1169,7 @@ fn field_ordering_position(field: &str) -> Option<usize> {
mod tests {
use super::*;
use crate::writer::datum::GenericDatumWriter;
- use crate::{error::Details, rabin::Rabin};
+ use crate::{error::Details, rabin::Rabin,
reader::datum::GenericDatumReader};
use apache_avro_test_helper::{
TestResult,
logger::{assert_logged, assert_not_logged},
@@ -2998,7 +2998,10 @@ mod tests {
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = crate::from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 2);
@@ -3585,7 +3588,10 @@ mod tests {
let mut x = &datum[..];
// Deserialization should succeed and we should be able to resolve the
schema.
- let deser_value = crate::from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
assert!(deser_value.validate(&reader_schema));
// Verify that we can read a field from the record.
diff --git a/avro/src/schema/resolve.rs b/avro/src/schema/resolve.rs
index 449436b..5087c8e 100644
--- a/avro/src/schema/resolve.rs
+++ b/avro/src/schema/resolve.rs
@@ -23,7 +23,7 @@ use crate::schema::{
use crate::{AvroResult, Error, Schema};
use std::collections::HashMap;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ResolvedSchema<'s> {
pub(super) names_ref: NamesRef<'s>,
schemata: Vec<&'s Schema>,
diff --git a/avro/src/serde/de.rs b/avro/src/serde/de.rs
index ee9dec1..82d40d5 100644
--- a/avro/src/serde/de.rs
+++ b/avro/src/serde/de.rs
@@ -953,8 +953,8 @@ mod tests {
use apache_avro_test_helper::TestResult;
use super::*;
- use crate::Decimal;
use crate::writer::datum::GenericDatumWriter;
+ use crate::{Decimal, reader::datum::GenericDatumReader};
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct StringEnum {
@@ -997,7 +997,9 @@ mod tests {
);
// decode from avro
- let value = crate::from_avro_datum(&schema, &mut buf, None)?;
+ let value = GenericDatumReader::builder(&schema)
+ .build()?
+ .read_value(&mut buf)?;
let decoded_data: StringEnum = crate::from_value(&value)?;
diff --git a/avro/src/writer/datum.rs b/avro/src/writer/datum.rs
index c5eb4a2..3019554 100644
--- a/avro/src/writer/datum.rs
+++ b/avro/src/writer/datum.rs
@@ -211,6 +211,8 @@ pub fn to_avro_datum_schemata<T: Into<Value>>(
mod tests {
use apache_avro_test_helper::TestResult;
+ use super::*;
+ use crate::reader::datum::GenericDatumReader;
use crate::{
Days, Decimal, Duration, Millis, Months,
schema::{DecimalSchema, FixedSchema, InnerDecimalSchema, Name},
@@ -218,8 +220,6 @@ mod tests {
util::zig_i64,
};
- use super::*;
-
const SCHEMA: &str = r#"
{
"type": "record",
@@ -346,7 +346,9 @@ mod tests {
// Should deserialize from the schema into the logical type.
let mut r = ser.as_slice();
- let de = crate::from_avro_datum(&schema, &mut r, None)?;
+ let de = GenericDatumReader::builder(&schema)
+ .build()?
+ .read_value(&mut r)?;
assert_eq!(de, value);
Ok(())
}
diff --git a/avro/tests/avro-3786.rs b/avro/tests/avro-3786.rs
index 461de7c..9719fd0 100644
--- a/avro/tests/avro-3786.rs
+++ b/avro/tests/avro-3786.rs
@@ -16,7 +16,7 @@
// under the License.
use apache_avro::writer::datum::GenericDatumWriter;
-use apache_avro::{Schema, from_avro_datum, to_value, types};
+use apache_avro::{Schema, reader::datum::GenericDatumReader, to_value, types};
use apache_avro_test_helper::TestResult;
#[test]
@@ -138,7 +138,10 @@ fn avro_3786_deserialize_union_with_different_enum_order()
-> TestResult {
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 2);
@@ -264,7 +267,10 @@ fn
avro_3786_deserialize_union_with_different_enum_order_defined_in_record() ->
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 1);
@@ -379,7 +385,10 @@ fn
test_avro_3786_deserialize_union_with_different_enum_order_defined_in_record_
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 1);
@@ -494,7 +503,10 @@ fn
test_avro_3786_deserialize_union_with_different_enum_order_defined_in_record_
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 1);
@@ -609,7 +621,10 @@ fn
deserialize_union_with_different_enum_order_defined_in_record() -> TestResult
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 1);
@@ -885,7 +900,10 @@ fn
deserialize_union_with_record_with_enum_defined_inline_reader_has_different_i
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 3);
diff --git a/avro/tests/avro-3787.rs b/avro/tests/avro-3787.rs
index 03d6158..b1558d9 100644
--- a/avro/tests/avro-3787.rs
+++ b/avro/tests/avro-3787.rs
@@ -16,7 +16,7 @@
// under the License.
use apache_avro::writer::datum::GenericDatumWriter;
-use apache_avro::{Schema, from_avro_datum, to_value, types};
+use apache_avro::{Schema, reader::datum::GenericDatumReader, to_value, types};
use apache_avro_test_helper::TestResult;
#[test]
@@ -139,7 +139,10 @@ fn avro_3787_deserialize_union_with_unknown_symbol() ->
TestResult {
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 2);
@@ -272,7 +275,10 @@ fn
avro_3787_deserialize_union_with_unknown_symbol_no_ref() -> TestResult {
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
types::Value::Record(fields) => {
assert_eq!(fields.len(), 1);
diff --git a/avro/tests/io.rs b/avro/tests/io.rs
index ae51a79..2998a2c 100644
--- a/avro/tests/io.rs
+++ b/avro/tests/io.rs
@@ -17,7 +17,7 @@
//! Port of
<https://github.com/apache/avro/blob/release-1.9.1/lang/py/test/test_io.py>
use apache_avro::writer::datum::GenericDatumWriter;
-use apache_avro::{Error, Schema, error::Details, from_avro_datum,
types::Value};
+use apache_avro::{Error, Schema, error::Details,
reader::datum::GenericDatumReader, types::Value};
use apache_avro_test_helper::TestResult;
use pretty_assertions::assert_eq;
use std::{io::Cursor, sync::OnceLock};
@@ -235,7 +235,9 @@ fn test_round_trip() -> TestResult {
let encoded = GenericDatumWriter::builder(&schema)
.build()?
.write_value_to_vec(value.clone())?;
- let decoded = from_avro_datum(&schema, &mut Cursor::new(encoded),
None).unwrap();
+ let decoded = GenericDatumReader::builder(&schema)
+ .build()?
+ .read_value(&mut Cursor::new(encoded))?;
assert_eq!(value, &decoded);
}
@@ -285,14 +287,10 @@ fn test_schema_promotion() -> TestResult {
let encoded = GenericDatumWriter::builder(&writer_schema)
.build()?
.write_value_to_vec(original_value.clone())?;
- let decoded = from_avro_datum(
- &writer_schema,
- &mut Cursor::new(encoded),
- Some(&reader_schema),
- )
- .unwrap_or_else(|_| {
- panic!("failed to decode {original_value:?} with schema:
{reader_raw_schema:?}",)
- });
+ let decoded = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut Cursor::new(encoded))?;
assert_eq!(decoded, promotable_values[j]);
}
}
@@ -310,11 +308,10 @@ fn test_unknown_symbol() -> TestResult {
let encoded = GenericDatumWriter::builder(&writer_schema)
.build()?
.write_value_to_vec(original_value.clone())?;
- let decoded = from_avro_datum(
- &writer_schema,
- &mut Cursor::new(encoded),
- Some(&reader_schema),
- );
+ let decoded = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut Cursor::new(encoded));
assert!(decoded.is_err());
Ok(())
@@ -336,11 +333,10 @@ fn test_default_value() -> TestResult {
let encoded = GenericDatumWriter::builder(long_record_schema())
.build()?
.write_value_to_vec(long_record_datum().clone())?;
- let datum_read = from_avro_datum(
- long_record_schema(),
- &mut Cursor::new(encoded),
- Some(&reader_schema),
- )?;
+ let datum_read = GenericDatumReader::builder(long_record_schema())
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut Cursor::new(encoded))?;
match default_datum {
// For float/double, NaN != NaN, so we check specially here.
@@ -395,11 +391,10 @@ fn test_no_default_value() -> TestResult {
let encoded = GenericDatumWriter::builder(long_record_schema())
.build()?
.write_value_to_vec(long_record_datum().clone())?;
- let result = from_avro_datum(
- long_record_schema(),
- &mut Cursor::new(encoded),
- Some(&reader_schema),
- );
+ let result = GenericDatumReader::builder(long_record_schema())
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut Cursor::new(encoded));
assert!(result.is_err());
Ok(())
@@ -426,11 +421,10 @@ fn test_projection() -> TestResult {
let encoded = GenericDatumWriter::builder(long_record_schema())
.build()?
.write_value_to_vec(long_record_datum().clone())?;
- let datum_read = from_avro_datum(
- long_record_schema(),
- &mut Cursor::new(encoded),
- Some(&reader_schema),
- )?;
+ let datum_read = GenericDatumReader::builder(long_record_schema())
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut Cursor::new(encoded))?;
assert_eq!(datum_to_read, datum_read);
Ok(())
@@ -457,11 +451,10 @@ fn test_field_order() -> TestResult {
let encoded = GenericDatumWriter::builder(long_record_schema())
.build()?
.write_value_to_vec(long_record_datum().clone())?;
- let datum_read = from_avro_datum(
- long_record_schema(),
- &mut Cursor::new(encoded),
- Some(&reader_schema),
- )?;
+ let datum_read = GenericDatumReader::builder(long_record_schema())
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut Cursor::new(encoded))?;
assert_eq!(datum_to_read, datum_read);
Ok(())
diff --git a/avro/tests/schema.rs b/avro/tests/schema.rs
index 3542657..89e328a 100644
--- a/avro/tests/schema.rs
+++ b/avro/tests/schema.rs
@@ -19,7 +19,8 @@ use apache_avro::writer::datum::GenericDatumWriter;
use apache_avro::{
Codec, Error, Reader, Schema, Writer,
error::Details,
- from_avro_datum, from_value,
+ from_value,
+ reader::datum::GenericDatumReader,
schema::{EnumSchema, FixedSchema, Name, RecordField, RecordSchema},
to_value,
types::{Record, Value},
@@ -862,8 +863,10 @@ fn avro_old_issue_47() -> TestResult {
.build()?
.write_value_to_vec(ser_value)?;
- let de_value = &from_avro_datum(&schema, &mut &*serialized_bytes, None)?;
- let deserialized_record = from_value::<MyRecord>(de_value)?;
+ let de_value = GenericDatumReader::builder(&schema)
+ .build()?
+ .read_value(&mut &*serialized_bytes)?;
+ let deserialized_record = from_value::<MyRecord>(&de_value)?;
assert_eq!(record, deserialized_record);
Ok(())
@@ -988,7 +991,10 @@ fn
test_avro_3785_deserialize_namespace_with_nullable_type_containing_reference_
.write_value_to_vec(avro_value)?;
let mut x = &datum[..];
let reader_schema = Schema::parse_str(reader_schema)?;
- let deser_value = from_avro_datum(&writer_schema, &mut x,
Some(&reader_schema))?;
+ let deser_value = GenericDatumReader::builder(&writer_schema)
+ .reader_schema(&reader_schema)
+ .build()?
+ .read_value(&mut x)?;
match deser_value {
Value::Record(fields) => {
assert_eq!(fields.len(), 2);
diff --git a/avro/tests/to_from_avro_datum_schemata.rs
b/avro/tests/to_from_avro_datum_schemata.rs
index 5cc7973..0849367 100644
--- a/avro/tests/to_from_avro_datum_schemata.rs
+++ b/avro/tests/to_from_avro_datum_schemata.rs
@@ -15,11 +15,9 @@
// specific language governing permissions and limitations
// under the License.
+use apache_avro::reader::datum::GenericDatumReader;
use apache_avro::writer::datum::GenericDatumWriter;
-use apache_avro::{
- Codec, Reader, Schema, Writer, from_avro_datum_reader_schemata,
from_avro_datum_schemata,
- types::Value,
-};
+use apache_avro::{Codec, Reader, Schema, Writer, types::Value};
use apache_avro_test_helper::{TestResult, init};
static SCHEMA_A_STR: &str = r#"{
@@ -59,7 +57,10 @@ fn test_avro_3683_multiple_schemata_to_from_avro_datum() ->
TestResult {
.write_value_to_vec(record.clone())?;
assert_eq!(actual, expected);
- let value = from_avro_datum_schemata(schema_b, schemata, &mut
actual.as_slice(), None)?;
+ let value = GenericDatumReader::builder(schema_b)
+ .writer_schemata(schemata)?
+ .build()?
+ .read_value(&mut actual.as_slice())?;
assert_eq!(value, record);
Ok(())
@@ -86,13 +87,12 @@ fn
avro_rs_106_test_multiple_schemata_to_from_avro_datum_with_resolution() -> Te
.write_value_to_vec(record.clone())?;
assert_eq!(actual, expected);
- let value = from_avro_datum_reader_schemata(
- schema_b,
- schemata.clone(),
- &mut actual.as_slice(),
- Some(schema_b),
- schemata,
- )?;
+ let value = GenericDatumReader::builder(schema_b)
+ .writer_schemata(schemata.clone())?
+ .reader_schema(schema_b)
+ .reader_schemata(schemata)?
+ .build()?
+ .read_value(&mut actual.as_slice())?;
assert_eq!(value, record);
Ok(())