Skip to main content

apache_avro/serde/
mod.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! # Using Avro in Rust, the Serde way.
19//!
20//! Avro is a schema-based format, this means it requires a few extra steps to use compared to
21//! a data format like JSON.
22//!
23//! ## Schemas
24//! It's strongly recommended to derive the schemas for your types using the [`AvroSchema`] derive macro.
25//! The macro uses the Serde attributes to generate a matching schema and checks that no attributes are
26//! used that are incompatible with the Serde implementation in this crate. See [the trait documentation] for
27//! details on how to change the generated schema.
28//!
29//! Alternatively, you can write your own schema. If you go down this path, it is recommended you start with
30//! the schema derived by [`AvroSchema`] and then modify it to fit your needs. For more information on mapping
31//! between Serde and Avro see [Avro to Serde](crate::documentation::avro_data_model_to_serde) and [Serde to Avro](crate::documentation::serde_data_model_to_avro).
32//!
33//! #### Performance pitfall
34//! One performance pitfall with Serde is (de)serializing bytes. The implementation of [`Serialize`][`serde::Serialize`]
35//! and [`Deserialize`][`serde::Deserialize`] for types as `Vec<u8>`, `&[u8]` and `Cow<[u8]>` will
36//! all use the array of integers representation. This can normally be fixed using the [`serde_bytes`]
37//! crate, however this crate also needs some extra information. Therefore, you need to use the
38//! [`bytes`], [`bytes_opt`], [`fixed`], [`fixed_opt`], [`mod@slice`], and [`slice_opt`] modules of
39//! this crate instead.
40//!
41//! #### Using existing schemas
42//! If you have schemas that are already being used in other parts of your software stack, generating types
43//! from the schema can be very useful. There is a **third-party** crate [`rsgen-avro`] that implements this.
44//!
45//! ## Serializing data
46//! Writing data is very simple. Use [`T::get_schema()`](AvroSchema::get_schema()) to get the schema
47//! for the type you want to serialize. It is recommended to keep this schema around as long as possible
48//! as generating the schema is quite expensive. Then create a [`Writer`](crate::Writer) with your schema
49//! and use the [`append_ser()`](crate::Writer::append_ser()) function to serialize your data.
50//!
51//! ## Deserializing data
52//! Reading data is both simpler and more complex than writing. On the one hand, you don't need to
53//! generate a schema, as the Avro file has it embedded. But you can't directly deserialize from a
54//! [`Reader`](crate::Reader). Instead, you have to iterate over the [`Value`](crate::types::Value)s
55//! in the reader and deserialize from those via [`from_value`].
56//!
57//! ## Putting it all together
58//!
59//! The following is an example of how to combine everything showed so far and it is meant to be a
60//! quick reference of the Serde interface:
61//!
62//! ```
63//! # use std::io::Cursor;
64//! # use serde::{Serialize, Deserialize};
65//! # use apache_avro::{AvroSchema, Error, Reader, Writer, serde::{from_value, to_value}};
66//! #[derive(AvroSchema, Serialize, Deserialize, PartialEq, Debug)]
67//! struct Foo {
68//!     a: i64,
69//!     b: String,
70//!     // Otherwise it will be serialized as an array of integers
71//!     #[avro(with)]
72//!     #[serde(with = "apache_avro::serde::bytes")]
73//!     c: Vec<u8>,
74//! }
75//!
76//! // Creating this schema is expensive, reuse it as much as possible
77//! let schema = Foo::get_schema();
78//! // A writer needs the schema of the type that is going to be written
79//! let mut writer = Writer::new(&schema, Vec::new())?;
80//!
81//! let foo = Foo {
82//!     a: 42,
83//!     b: "Hello".to_string(),
84//!     c: b"Data".to_vec()
85//! };
86//!
87//! // Serialize as many items as you want.
88//! writer.append_ser(&foo)?;
89//! writer.append_ser(&foo)?;
90//! writer.append_ser(&foo)?;
91//!
92//! // Always flush
93//! writer.flush()?;
94//! // Or consume the writer
95//! let data = writer.into_inner()?;
96//!
97//! // The reader does not need a schema as it's included in the data
98//! let reader = Reader::new(Cursor::new(data))?;
99//! // The reader is an iterator
100//! for result in reader {
101//!     let value = result?;
102//!     let new_foo: Foo = from_value(&value)?;
103//!     assert_eq!(new_foo, foo);
104//! }
105//! # Ok::<(), Error>(())
106//! ```
107//!
108//! [`rsgen-avro`]: https://docs.rs/rsgen-avro/latest/rsgen_avro/
109//! [the trait documentation]: AvroSchema
110
111mod de;
112mod derive;
113pub(crate) mod deser_schema;
114mod ser;
115pub(crate) mod ser_schema;
116mod util;
117mod with;
118
119pub use de::from_value;
120pub use derive::{AvroSchema, AvroSchemaComponent};
121pub use ser::to_value;
122pub use with::{
123    array, array_opt, bigdecimal, bigdecimal_opt, bytes, bytes_opt, fixed, fixed_opt, slice,
124    slice_opt,
125};
126
127#[doc(hidden)]
128pub use derive::get_record_fields_in_ctxt;