k8s_openapi_codegen_common/templates/
impl_deserialize.rs

1pub(crate) fn generate(
2    mut writer: impl std::io::Write,
3    type_name: &str,
4    generics: super::Generics<'_>,
5    fields: &[super::Property<'_>],
6    map_namespace: &impl crate::MapNamespace,
7    resource_metadata: Option<&super::ResourceMetadata<'_>>,
8) -> Result<(), crate::Error> {
9    use std::fmt::Write;
10
11    let local = crate::map_namespace_local_to_string(map_namespace)?;
12
13    let type_generics_impl: std::borrow::Cow<'_, str> = match generics.type_part {
14        Some(part) => format!("<'de, {part}>").into(),
15        None => "<'de>".into(),
16    };
17    let type_generics_type = generics.type_part.map(|part| format!("<{part}>")).unwrap_or_default();
18    let type_generics_where = generics.where_part.map(|part| format!(" where {part}")).unwrap_or_default();
19
20    let (visitor_field, visitor_create_field) =
21        if type_generics_type.is_empty() {
22            (String::new(), "")
23        }
24        else {
25            (format!("(core::marker::PhantomData{type_generics_type})"), "(Default::default())")
26        };
27
28    let mut fields_string = String::new();
29    let mut str_to_field_match_arms = String::new();
30    let mut field_value_defs = String::new();
31    let mut field_value_match_arms = String::new();
32    let mut field_name_list = String::new();
33    let mut field_value_assignment = String::new();
34
35    let mut flattened_field = None;
36
37    if resource_metadata.is_some() {
38        writeln!(fields_string, "            Key_api_version,")?;
39        writeln!(fields_string, "            Key_kind,")?;
40
41        writeln!(str_to_field_match_arms, r#"                            "apiVersion" => Field::Key_api_version,"#)?;
42        writeln!(str_to_field_match_arms, r#"                            "kind" => Field::Key_kind,"#)?;
43
44        writeln!(field_value_match_arms, r#"                        Field::Key_api_version => {{"#)?;
45        writeln!(field_value_match_arms, r#"                            let value_api_version: std::string::String = {local}serde::de::MapAccess::next_value(&mut map)?;"#)?;
46        writeln!(field_value_match_arms, r#"                            if value_api_version != <Self::Value as {local}Resource>::API_VERSION {{"#)?;
47        writeln!(field_value_match_arms,
48            r#"                                return Err({local}serde::de::Error::invalid_value({local}serde::de::Unexpected::Str(&value_api_version), &<Self::Value as {local}Resource>::API_VERSION));"#)?;
49        writeln!(field_value_match_arms, r#"                            }}"#)?;
50        writeln!(field_value_match_arms, r#"                        }},"#)?;
51
52        writeln!(field_value_match_arms, r#"                        Field::Key_kind => {{"#)?;
53        writeln!(field_value_match_arms, r#"                            let value_kind: std::string::String = {local}serde::de::MapAccess::next_value(&mut map)?;"#)?;
54        writeln!(field_value_match_arms, r#"                            if value_kind != <Self::Value as {local}Resource>::KIND {{"#)?;
55        writeln!(field_value_match_arms,
56            r#"                                return Err({local}serde::de::Error::invalid_value({local}serde::de::Unexpected::Str(&value_kind), &<Self::Value as {local}Resource>::KIND));"#)?;
57        writeln!(field_value_match_arms, r#"                            }}"#)?;
58        writeln!(field_value_match_arms, r#"                        }},"#)?;
59
60        writeln!(field_name_list, r#"                "apiVersion","#)?;
61        writeln!(field_name_list, r#"                "kind","#)?;
62    }
63    for super::Property { name, field_name, field_type_name, required, is_flattened, .. } in fields {
64        if *is_flattened {
65            if flattened_field.is_some() {
66                return Err(format!("{type_name} has two flattened fields").into());
67            }
68
69            flattened_field = Some((field_name, field_type_name));
70
71            writeln!(field_value_defs,
72                r#"                let mut value_{field_name}: {local}serde_json::Map<std::string::String, {local}serde_json::Value> = Default::default();"#)?;
73        }
74        else {
75            writeln!(fields_string, "            Key_{field_name},")?;
76
77            writeln!(str_to_field_match_arms, r#"                            {name:?} => Field::Key_{field_name},"#)?;
78
79            match required {
80                super::PropertyRequired::Required { is_default } => {
81                    writeln!(field_value_defs, r#"                let mut value_{field_name}: Option<{field_type_name}> = None;"#)?;
82
83                    // The API server doesn't always validate required fields when a resource is created,
84                    // so consequently required fields aren't always present when a resource is fetched.
85                    //
86                    // An example is in https://github.com/Arnavion/k8s-openapi/issues/110 which says it's possible
87                    // to create a DaemonSet with a PodSpec that doesn't have its required fields.
88                    //
89                    // Since the Deserialize impl only matters for parsing the API server response, there's no point being stricter
90                    // about the response than the API server is. So we can just pretend that the missing field is the default value
91                    // if the field is Default-able. But if the field isn't Default-able, then there's nothing we can do but fail as usual.
92                    if *is_default {
93                        writeln!(field_value_match_arms,
94                            r#"                        Field::Key_{field_name} => value_{field_name} = {local}serde::de::MapAccess::next_value(&mut map)?,"#)?;
95
96                        writeln!(field_value_assignment, "                    {field_name}: value_{field_name}.unwrap_or_default(),")?;
97                    }
98                    else {
99                        writeln!(field_value_match_arms,
100                            r#"                        Field::Key_{field_name} => value_{field_name} = Some({local}serde::de::MapAccess::next_value(&mut map)?),"#)?;
101
102                        writeln!(field_value_assignment,
103                            "                    {field_name}: value_{field_name}.ok_or_else(|| {local}serde::de::Error::missing_field({name:?}))?,")?;
104                    }
105                },
106
107                super::PropertyRequired::Optional => {
108                    writeln!(field_value_defs, r#"                let mut value_{field_name}: {field_type_name} = None;"#)?;
109
110                    writeln!(field_value_match_arms,
111                        r#"                        Field::Key_{field_name} => value_{field_name} = {local}serde::de::MapAccess::next_value(&mut map)?,"#)?;
112
113                    writeln!(field_value_assignment, "                    {field_name}: value_{field_name},")?;
114                },
115
116                super::PropertyRequired::OptionalDefault => {
117                    writeln!(field_value_defs, r#"                let mut value_{field_name}: Option<{field_type_name}> = None;"#)?;
118
119                    writeln!(field_value_match_arms,
120                        r#"                        Field::Key_{field_name} => value_{field_name} = {local}serde::de::MapAccess::next_value(&mut map)?,"#)?;
121
122                    writeln!(field_value_assignment, "                    {field_name}: value_{field_name}.unwrap_or_default(),")?;
123                },
124            }
125
126            writeln!(field_name_list, r#"                {name:?},"#)?;
127        }
128    }
129
130    if let Some((field_name, _)) = flattened_field {
131        writeln!(fields_string, "            Other(String),")?;
132
133        writeln!(str_to_field_match_arms, "                            v => Field::Other(v.into()),")?;
134
135        writeln!(field_value_match_arms,
136            "                        Field::Other(key) => {{ value_{field_name}.insert(key, {local}serde::de::MapAccess::next_value(&mut map)?); }},")?;
137
138        writeln!(field_value_assignment,
139            "                    {field_name}: {{")?;
140        writeln!(field_value_assignment,
141            "                        let value_{field_name} = {local}serde::Deserialize::deserialize(value_{field_name}).map_err({local}serde::de::Error::custom)?;")?;
142        writeln!(field_value_assignment,
143            "                        value_{field_name}")?;
144        writeln!(field_value_assignment,
145            "                    }},")?;
146    }
147    else {
148        writeln!(fields_string, "            Other,")?;
149
150        writeln!(str_to_field_match_arms, "                            _ => Field::Other,")?;
151
152        writeln!(field_value_match_arms,
153            "                        Field::Other => {{ let _: {local}serde::de::IgnoredAny = {local}serde::de::MapAccess::next_value(&mut map)?; }},")?;
154    }
155
156    let deserialize_type_name =
157        if resource_metadata.is_some() {
158            format!("<Self as {local}Resource>::KIND")
159        }
160        else {
161            format!("{type_name:?}")
162        };
163
164    let visitor_expecting_type_name =
165        if resource_metadata.is_some() {
166            format!("<Self::Value as {local}Resource>::KIND")
167        }
168        else {
169            format!("{type_name:?}")
170        };
171
172    writeln!(
173        writer,
174        include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/impl_deserialize.rs")),
175        local = local,
176        type_name = type_name,
177        type_generics_impl = type_generics_impl,
178        type_generics_type = type_generics_type,
179        type_generics_where = type_generics_where,
180        fields = fields_string,
181        str_to_field_match_arms = str_to_field_match_arms,
182        field_value_defs = field_value_defs,
183        field_value_match_arms = field_value_match_arms,
184        field_value_assignment = field_value_assignment,
185        field_name_list = field_name_list,
186        visitor_field = visitor_field,
187        visitor_create_field = visitor_create_field,
188        deserialize_type_name = deserialize_type_name,
189        visitor_expecting_type_name = visitor_expecting_type_name,
190    )?;
191
192    Ok(())
193}