#![cfg_attr(docsrs, feature(rustdoc_internals))]
#![cfg_attr(docsrs, allow(internal_features))]
mod bigdecimal;
mod bytes;
mod codec;
mod decimal;
mod decode;
mod duration;
mod encode;
#[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;
pub mod serde;
pub mod types;
pub mod util;
pub mod validator;
pub mod writer;
#[expect(deprecated)]
pub use crate::{
bigdecimal::BigDecimal,
bytes::{
serde_avro_bytes, serde_avro_bytes_opt, serde_avro_fixed, serde_avro_fixed_opt,
serde_avro_slice, serde_avro_slice_opt,
},
};
#[cfg(feature = "bzip")]
pub use codec::bzip::Bzip2Settings;
#[cfg(feature = "xz")]
pub use codec::xz::XzSettings;
#[cfg(feature = "zstandard")]
pub use codec::zstandard::ZstandardSettings;
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,
datum::{from_avro_datum, from_avro_datum_reader_schemata, from_avro_datum_schemata},
read_marker,
single_object::{GenericSingleObjectReader, SpecificSingleObjectReader},
};
pub use schema::Schema;
pub use serde::{AvroSchema, AvroSchemaComponent, from_value, to_value};
pub use uuid::Uuid;
#[expect(
deprecated,
reason = "Still need to export it until we remove it completely"
)]
pub use writer::{
Clearable, Writer, WriterBuilder,
datum::{to_avro_datum, to_avro_datum_schemata, write_avro_datum_ref},
single_object::{GenericSingleObjectWriter, SpecificSingleObjectWriter},
};
#[cfg(feature = "derive")]
pub use apache_avro_derive::AvroSchema;
pub type AvroResult<T> = Result<T, Error>;
#[deprecated(
since = "0.21.0",
note = "Please use apache_avro::util::max_allocation_bytes"
)]
pub fn max_allocation_bytes(num_bytes: usize) -> usize {
util::max_allocation_bytes(num_bytes)
}
#[deprecated(
since = "0.21.0",
note = "Please use apache_avro::util::set_serde_human_readable"
)]
pub fn set_serde_human_readable(human_readable: bool) -> bool {
util::set_serde_human_readable(human_readable)
}
#[cfg(test)]
mod tests {
use crate::{
Codec, Reader, Schema, Writer,
reader::datum::GenericDatumReader,
types::{Record, Value},
};
use apache_avro_test_helper::TestResult;
use pretty_assertions::assert_eq;
#[test]
fn test_enum_default() {
let writer_raw_schema = r#"
{
"type": "record",
"name": "test",
"fields": [
{"name": "a", "type": "long", "default": 42},
{"name": "b", "type": "string"}
]
}
"#;
let reader_raw_schema = r#"
{
"type": "record",
"name": "test",
"fields": [
{"name": "a", "type": "long", "default": 42},
{"name": "b", "type": "string"},
{
"name": "c",
"type": {
"type": "enum",
"name": "suit",
"symbols": ["diamonds", "spades", "clubs", "hearts"]
},
"default": "spades"
}
]
}
"#;
let writer_schema = Schema::parse_str(writer_raw_schema).unwrap();
let reader_schema = Schema::parse_str(reader_raw_schema).unwrap();
let mut writer = Writer::with_codec(&writer_schema, Vec::new(), Codec::Null).unwrap();
let mut record = Record::new(writer.schema()).unwrap();
record.put("a", 27i64);
record.put("b", "foo");
writer.append_value(record).unwrap();
let input = writer.into_inner().unwrap();
let mut reader = Reader::builder(&input[..])
.reader_schema(&reader_schema)
.build()
.unwrap();
assert_eq!(
reader.next().unwrap().unwrap(),
Value::Record(vec![
("a".to_string(), Value::Long(27)),
("b".to_string(), Value::String("foo".to_string())),
("c".to_string(), Value::Enum(1, "spades".to_string())),
])
);
assert!(reader.next().is_none());
}
#[test]
fn test_enum_string_value() {
let raw_schema = r#"
{
"type": "record",
"name": "test",
"fields": [
{"name": "a", "type": "long", "default": 42},
{"name": "b", "type": "string"},
{
"name": "c",
"type": {
"type": "enum",
"name": "suit",
"symbols": ["diamonds", "spades", "clubs", "hearts"]
},
"default": "spades"
}
]
}
"#;
let schema = Schema::parse_str(raw_schema).unwrap();
let mut writer = Writer::with_codec(&schema, Vec::new(), Codec::Null).unwrap();
let mut record = Record::new(writer.schema()).unwrap();
record.put("a", 27i64);
record.put("b", "foo");
record.put("c", "clubs");
writer.append_value(record).unwrap();
let input = writer.into_inner().unwrap();
let mut reader = Reader::builder(&input[..])
.reader_schema(&schema)
.build()
.unwrap();
assert_eq!(
reader.next().unwrap().unwrap(),
Value::Record(vec![
("a".to_string(), Value::Long(27)),
("b".to_string(), Value::String("foo".to_string())),
("c".to_string(), Value::Enum(2, "clubs".to_string())),
])
);
assert!(reader.next().is_none());
}
#[test]
fn test_enum_no_reader_schema() {
let writer_raw_schema = r#"
{
"type": "record",
"name": "test",
"fields": [
{"name": "a", "type": "long", "default": 42},
{"name": "b", "type": "string"},
{
"name": "c",
"type": {
"type": "enum",
"name": "suit",
"symbols": ["diamonds", "spades", "clubs", "hearts"]
},
"default": "spades"
}
]
}
"#;
let writer_schema = Schema::parse_str(writer_raw_schema).unwrap();
let mut writer = Writer::with_codec(&writer_schema, Vec::new(), Codec::Null).unwrap();
let mut record = Record::new(writer.schema()).unwrap();
record.put("a", 27i64);
record.put("b", "foo");
record.put("c", "clubs");
writer.append_value(record).unwrap();
let input = writer.into_inner().unwrap();
let mut reader = Reader::new(&input[..]).unwrap();
assert_eq!(
reader.next().unwrap().unwrap(),
Value::Record(vec![
("a".to_string(), Value::Long(27)),
("b".to_string(), Value::String("foo".to_string())),
("c".to_string(), Value::Enum(2, "clubs".to_string())),
])
);
}
#[test]
fn test_illformed_length() -> TestResult {
let raw_schema = r#"
{
"type": "record",
"name": "test",
"fields": [
{"name": "a", "type": "long", "default": 42},
{"name": "b", "type": "string"}
]
}
"#;
let schema = Schema::parse_str(raw_schema).unwrap();
let illformed: &[u8] = &[0x3e, 0x15, 0xff, 0x1f, 0x15, 0xff];
let value = GenericDatumReader::builder(&schema)
.build()?
.read_value(&mut &*illformed);
assert!(value.is_err());
Ok(())
}
}