1use std::{io::Read, marker::PhantomData};
19
20use bon::bon;
21use serde::de::DeserializeOwned;
22
23use crate::{
24 AvroResult, AvroSchema, Schema,
25 decode::{DecodeContext, decode_internal},
26 schema::{ResolvedOwnedSchema, ResolvedSchema},
27 serde::deser_schema::{Config, SchemaAwareDeserializer},
28 types::Value,
29 util::is_human_readable,
30};
31
32pub struct GenericDatumReader<'s> {
38 writer: &'s Schema,
39 resolved: ResolvedSchema<'s>,
40 reader: Option<(&'s Schema, ResolvedSchema<'s>)>,
41 human_readable: bool,
42}
43
44#[bon]
45impl<'s> GenericDatumReader<'s> {
46 #[builder]
52 pub fn new(
53 #[builder(start_fn)]
55 writer_schema: &'s Schema,
56 resolved_writer_schemata: Option<ResolvedSchema<'s>>,
58 reader_schema: Option<&'s Schema>,
60 resolved_reader_schemata: Option<ResolvedSchema<'s>>,
62 #[builder(default = is_human_readable())]
64 human_readable: bool,
65 ) -> AvroResult<Self> {
66 let resolved_writer_schemata = if let Some(resolved) = resolved_writer_schemata {
67 resolved
68 } else {
69 ResolvedSchema::try_from(writer_schema)?
70 };
71
72 let reader = if let Some(reader) = reader_schema {
73 if let Some(resolved) = resolved_reader_schemata {
74 Some((reader, resolved))
75 } else {
76 Some((reader, ResolvedSchema::try_from(reader)?))
77 }
78 } else {
79 None
80 };
81
82 Ok(Self {
83 writer: writer_schema,
84 resolved: resolved_writer_schemata,
85 reader,
86 human_readable,
87 })
88 }
89}
90
91impl<'s, S: generic_datum_reader_builder::State> GenericDatumReaderBuilder<'s, S> {
92 pub fn writer_schemata(
97 self,
98 schemata: Vec<&'s Schema>,
99 ) -> AvroResult<
100 GenericDatumReaderBuilder<'s, generic_datum_reader_builder::SetResolvedWriterSchemata<S>>,
101 >
102 where
103 S::ResolvedWriterSchemata: generic_datum_reader_builder::IsUnset,
104 {
105 let resolved = ResolvedSchema::new_with_schemata(schemata)?;
106 Ok(self.resolved_writer_schemata(resolved))
107 }
108
109 pub fn reader_schemata(
116 self,
117 schemata: Vec<&'s Schema>,
118 ) -> AvroResult<
119 GenericDatumReaderBuilder<'s, generic_datum_reader_builder::SetResolvedReaderSchemata<S>>,
120 >
121 where
122 S::ResolvedReaderSchemata: generic_datum_reader_builder::IsUnset,
123 S::ReaderSchema: generic_datum_reader_builder::IsSet,
124 {
125 let resolved = ResolvedSchema::new_with_schemata(schemata)?;
126 Ok(self.resolved_reader_schemata(resolved))
127 }
128}
129
130impl<'s> GenericDatumReader<'s> {
131 pub fn read_value<R: Read>(&self, reader: &mut R) -> AvroResult<Value> {
133 let value = decode_internal(
134 self.writer,
135 self.resolved.get_names(),
136 None,
137 reader,
138 &mut DecodeContext::new(),
139 )?;
140 if let Some((reader, resolved)) = &self.reader {
141 value.resolve_internal(reader, resolved.get_names(), None, None)
142 } else {
143 Ok(value)
144 }
145 }
146
147 pub fn read_deser<T: DeserializeOwned>(&self, reader: &mut impl Read) -> AvroResult<T> {
152 if let Some((_, _)) = &self.reader {
155 panic!("Schema aware deserialisation does not resolve schemas yet");
157 } else {
158 T::deserialize(SchemaAwareDeserializer::new(
159 reader,
160 self.writer,
161 Config {
162 names: self.resolved.get_names(),
163 human_readable: self.human_readable,
164 recursion_depth: 0,
165 },
166 )?)
167 }
168 }
169}
170
171pub struct SpecificDatumReader<T: AvroSchema> {
177 resolved: ResolvedOwnedSchema,
178 human_readable: bool,
179 phantom: PhantomData<T>,
180}
181
182#[bon]
183impl<T: AvroSchema> SpecificDatumReader<T> {
184 #[builder]
190 pub fn new(#[builder(default = is_human_readable())] human_readable: bool) -> AvroResult<Self> {
191 Ok(Self {
192 resolved: T::get_schema().try_into()?,
193 human_readable,
194 phantom: PhantomData,
195 })
196 }
197}
198
199impl<T: AvroSchema + DeserializeOwned> SpecificDatumReader<T> {
200 pub fn read<R: Read>(&self, reader: &mut R) -> AvroResult<T> {
201 T::deserialize(SchemaAwareDeserializer::new(
202 reader,
203 self.resolved.get_root_schema(),
204 Config {
205 names: self.resolved.get_names(),
206 human_readable: self.human_readable,
207 recursion_depth: 0,
208 },
209 )?)
210 }
211}
212
213#[deprecated(since = "0.22.0", note = "Use `GenericDatumReader` instead")]
232pub fn from_avro_datum<R: Read>(
233 writer_schema: &Schema,
234 reader: &mut R,
235 reader_schema: Option<&Schema>,
236) -> AvroResult<Value> {
237 GenericDatumReader::builder(writer_schema)
238 .maybe_reader_schema(reader_schema)
239 .build()?
240 .read_value(reader)
241}
242
243#[deprecated(since = "0.22.0", note = "Use `GenericDatumReader` instead")]
261pub fn from_avro_datum_schemata<R: Read>(
262 writer_schema: &Schema,
263 writer_schemata: Vec<&Schema>,
264 reader: &mut R,
265 reader_schema: Option<&Schema>,
266) -> AvroResult<Value> {
267 GenericDatumReader::builder(writer_schema)
268 .writer_schemata(writer_schemata)?
269 .maybe_reader_schema(reader_schema)
270 .build()?
271 .read_value(reader)
272}
273
274#[deprecated(since = "0.22.0", note = "Use `GenericDatumReader` instead")]
293pub fn from_avro_datum_reader_schemata<R: Read>(
294 writer_schema: &Schema,
295 writer_schemata: Vec<&Schema>,
296 reader: &mut R,
297 reader_schema: Option<&Schema>,
298 reader_schemata: Vec<&Schema>,
299) -> AvroResult<Value> {
300 GenericDatumReader::builder(writer_schema)
301 .writer_schemata(writer_schemata)?
302 .maybe_reader_schema(reader_schema)
303 .reader_schemata(reader_schemata)?
304 .build()?
305 .read_value(reader)
306}
307
308#[cfg(test)]
309mod tests {
310 use apache_avro_test_helper::TestResult;
311 use serde::Deserialize;
312
313 use crate::{
314 Schema,
315 reader::datum::GenericDatumReader,
316 types::{Record, Value},
317 };
318
319 #[test]
320 fn test_from_avro_datum() -> TestResult {
321 let schema = Schema::parse_str(
322 r#"{
323 "type": "record",
324 "name": "test",
325 "fields": [
326 {
327 "name": "a",
328 "type": "long",
329 "default": 42
330 },
331 {
332 "name": "b",
333 "type": "string"
334 }
335 ]
336 }"#,
337 )?;
338 let mut encoded: &'static [u8] = &[54, 6, 102, 111, 111];
339
340 let mut record = Record::new(&schema).unwrap();
341 record.put("a", 27i64);
342 record.put("b", "foo");
343 let expected = record.into();
344
345 let avro_datum = GenericDatumReader::builder(&schema)
346 .build()?
347 .read_value(&mut encoded)?;
348
349 assert_eq!(avro_datum, expected);
350
351 Ok(())
352 }
353
354 #[test]
355 fn test_from_avro_datum_with_union_to_struct() -> TestResult {
356 const TEST_RECORD_SCHEMA_3240: &str = r#"
357 {
358 "type": "record",
359 "name": "TestRecord3240",
360 "fields": [
361 {
362 "name": "a",
363 "type": "long",
364 "default": 42
365 },
366 {
367 "name": "b",
368 "type": "string"
369 },
370 {
371 "name": "a_nullable_array",
372 "type": ["null", {"type": "array", "items": {"type": "string"}}],
373 "default": null
374 },
375 {
376 "name": "a_nullable_boolean",
377 "type": ["null", {"type": "boolean"}],
378 "default": null
379 },
380 {
381 "name": "a_nullable_string",
382 "type": ["null", {"type": "string"}],
383 "default": null
384 }
385 ]
386 }
387 "#;
388 #[derive(Default, Debug, Deserialize, PartialEq, Eq)]
389 struct TestRecord3240 {
390 a: i64,
391 b: String,
392 a_nullable_array: Option<Vec<String>>,
393 a_nullable_string: Option<String>,
396 }
397
398 let schema = Schema::parse_str(TEST_RECORD_SCHEMA_3240)?;
399 let mut encoded: &[u8] = &[54, 6, 102, 111, 111];
400
401 let error = GenericDatumReader::builder(&schema)
402 .build()?
403 .read_deser::<TestRecord3240>(&mut encoded)
404 .unwrap_err();
405 assert_eq!(
407 error.to_string(),
408 "Failed to read bytes for decoding variable length integer: failed to fill whole buffer"
409 );
410
411 Ok(())
412 }
413
414 #[test]
415 fn test_null_union() -> TestResult {
416 let schema = Schema::parse_str(r#"["null", "long"]"#)?;
417 let mut encoded: &'static [u8] = &[2, 0];
418
419 let avro_datum = GenericDatumReader::builder(&schema)
420 .build()?
421 .read_value(&mut encoded)?;
422 assert_eq!(avro_datum, Value::Union(1, Box::new(Value::Long(0))));
423
424 Ok(())
425 }
426}