1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// 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.
//! # Mapping the Serde data model to the Avro data model
//!
//! When manually mapping Rust types to an Avro schema, or the reverse, it is important to understand
//! how the different data models are mapped. When mapping from an Avro schema to Rust types,
//! see [the documentation for the reverse](super::avro_data_model_to_serde).
//!
//! Only the schemas generated by the [`AvroSchema`] derive and the mapping as defined here are
//! supported. Any other behavior might change in a minor version.
//!
//! The following list is based on [the data model defined by Serde](https://serde.rs/data-model.html):
//! - **14 primitive types**
//! - `bool` => [`Schema::Boolean`]
//! - `i8`, `i16`, `i32`, `u8`, `u16` => [`Schema::Int`]
//! - `i64`, `u32` => [`Schema::Long`]
//! - `u64` => [`Schema::Fixed`]`(name: "org.apache.avro.rust.u64", size: 8)`
//! - This is not a `Schema::Long` as that is a signed number of maximum 64 bits.
//! - `i128` => [`Schema::Fixed`]`(name: "org.apache.avro.rust.i128", size: 16)`
//! - `u128` => [`Schema::Fixed`]`(name: "org.apache.avro.rust.u128", size: 16)`
//! - `f32` => [`Schema::Float`]
//! - `f64` => [`Schema::Double`]
//! - `char` => [`Schema::String`]
//! - Only one character allowed, deserializer will return an error for strings with more than one character.
//! - **string** => [`Schema::String`]
//! - **byte array** => [`Schema::Bytes`] or [`Schema::Fixed`]
//! - **option** => [`Schema::Union([Schema::Null, _])`](crate::schema::Schema::Union)
//! - **unit** => [`Schema::Null`]
//! - **unit struct** => [`Schema::Record`] with the unqualified name equal to the name of the struct and zero fields
//! - **unit variant** => See [Enums](#enums)
//! - **newtype struct** => [`Schema::Record`] with the unqualified name equal to the name of the struct and one field
//! - **newtype variant** => See [Enums](#enums)
//! - **seq** => [`Schema::Array`]
//! - **tuple**
//! - For tuples with one element, the schema will be the schema of the only element
//! - For tuples with more than one element, the schema will be a [`Schema::Record`] with as many fields as there are elements.
//! The schema must have the attribute `org.apache.avro.rust.tuple` with the value set to `true`.
//! - **Note:** Serde (de)serializes arrays (`[T; N]`) as tuples. To (de)serialize an array as a
//! [`Schema::Array`] use [`apache_avro::serde::array`].
//! - **tuple_struct** => [`Schema::Record`] with the unqualified name equal to the name of the struct and as many fields as there are elements
//! - **Note:** Tuple structs with 0 or 1 elements will also be (de)serialized as a [`Schema::Record`]. This
//! is different from normal tuples.
//! - **tuple_variant** => See [Enums](#enums)
//! - **map** => [`Schema::Map`]
//! - **Note:** the key type of the map will be (de)serialized as a [`Schema::String`]
//! - **struct** => [`Schema::Record`]
//! - **struct_variant** => See [Enums](#enums)
//!
//! ## Enums
//!
//! ### Externally tagged
//! This is the default enum representation for Serde. It can be mapped in three ways to the Avro data model.
//! For all three options it is important that the enum index matches the Avro index.
//! - As a [`Schema::Enum`], this is only possible for enums with only unit variants.
//! - As a [`Schema::Union`] with a [`Schema::Record`] for every variant:
//! - **unit_variant** => [`Schema::Record`] named as the variant and with no fields.
//! - **newtype_variant** => [`Schema::Record`] named as the variant and with one field.
//! The schema must have the attribute `org.apache.avro.rust.union_of_records` with the value set to `true`.
//! - **tuple_variant** => [`Schema::Record`] named as the variant and with as many fields as there are elements.
//! - **struct_variant** => [`Schema::Record`] named as the variant and with a field for every field of the struct variant.
//! - As a [`Schema::Union`] without the wrapper [`Schema::Record`], all schemas must be unique:
//! - **unit_variant** => [`Schema::Null`].
//! - **newtype_variant** => The schema of the inner type.
//! - **tuple_variant** => [`Schema::Record`] named as the variant and with as many fields as there are elements.
//! - **struct_variant** => [`Schema::Record`] named as the variant and with a field for every field of the struct variant.
//!
//! ### Internally tagged
//! This enum representation is used by Serde if the attribute `#[serde(tag = "...")]` is used.
//! It maps to a [`Schema::Record`]. There must be at least one field that is named as the value of the
//! `tag` attribute. If a field is not used by all variants it must have a `default` set.
//!
//! ### Adjacently tagged
//! This enum representation is used by Serde if the attributes `#[serde(tag = "...", content = "...")]` are used.
//! It maps to a [`Schema::Record`] with two fields. One field must be named as the value of the `tag`
//! attribute and use the [`Schema::Enum`] schema. The other field must be named as the value of the
//! `content` tag and use the [`Schema::Union`] schema. The content of the union schema is equivalent
//! to the untagged representation.
//!
//! ### Untagged
//! This enum representation is used by Serde if the attribute `#[serde(untagged)]` is used. It maps
//! to a [`Schema::Union`] with the following schemas:
//! - **unit_variant** => [`Schema::Null`].
//! - **newtype_variant** => The schema of the inner type.
//! - **tuple_variant** => [`Schema::Record`] named as the variant and with as many fields as there are elements.
//! - **struct_variant** => [`Schema::Record`] named as the variant and with a field for every field of the struct variant.
//!
//! [`AvroSchema`]: crate::AvroSchema
//! [`Schema::Array`]: crate::schema::Schema::Array
//! [`Schema::Boolean`]: crate::schema::Schema::Boolean
//! [`Schema::Bytes`]: crate::schema::Schema::Bytes
//! [`Schema::Double`]: crate::schema::Schema::Double
//! [`Schema::Enum`]: crate::schema::Schema::Enum
//! [`Schema::Fixed`]: crate::schema::Schema::Fixed
//! [`Schema::Float`]: crate::schema::Schema::Float
//! [`Schema::Int`]: crate::schema::Schema::Int
//! [`Schema::Long`]: crate::schema::Schema::Long
//! [`Schema::Map`]: crate::schema::Schema::Map
//! [`Schema::Null`]: crate::schema::Schema::Null
//! [`Schema::Record`]: crate::schema::Schema::Record
//! [`Schema::String`]: crate::schema::Schema::String
//! [`Schema::Union`]: crate::schema::Schema::Union
//! [`apache_avro::serde::array`]: crate::serde::array