Skip to main content

haste_fhir_serialization_json_derive/
lib.rs

1mod serde_deserialize;
2mod serde_serialize;
3mod utilities;
4
5use proc_macro::TokenStream;
6use syn::{Attribute, DeriveInput, Expr, Lit, Meta, parse_macro_input};
7
8/// Determines the de/serialization type of the derive macro.
9fn get_attribute_serialization_type(attrs: &[Attribute]) -> Option<String> {
10    attrs.iter().find_map(|attr| match &attr.meta {
11        Meta::NameValue(name_value) => {
12            if name_value.path.is_ident("fhir_serialize_type") {
13                match &name_value.value {
14                    Expr::Lit(lit) => match &lit.lit {
15                        Lit::Str(lit) => Some(lit.value()),
16                        _ => panic!("Expected a string literal"),
17                    },
18                    _ => panic!("Expected a string literal"),
19                }
20            } else {
21                None
22            }
23        }
24        _ => None,
25    })
26}
27
28#[derive(Clone, Copy, PartialEq)]
29enum DeserializeComplexType {
30    Complex,
31    Resource,
32}
33
34/// Derives Serde-based FHIR JSON deserialization implementations.
35///
36/// The macro behavior is selected using the `fhir_serialize_type` attribute.
37///
38/// Supported deserialization types:
39/// - `primitive`
40/// - `valueset`
41/// - `typechoice`
42/// - `complex`
43/// - `resource`
44///
45/// # Panics
46///
47/// Panics if:
48/// - The `fhir_serialize_type` attribute is missing.
49/// - The `fhir_serialize_type` attribute contains an unsupported value.
50/// - A deserialization type other than the supported Serde deserialization
51///   variants is specified.
52///
53/// # Attributes
54///
55/// This macro supports the following attributes:
56/// - `fhir_serialize_type` - Selects the deserialization implementation.
57/// - `rename_field` - Renames a deserialized field.
58/// - `type_choice_field_name` - Defines the field name used for type choice
59///   deserialization.
60/// - `type_choice_variants` - Defines variants for type choice fields.
61/// - `primitive` - Marks primitive FHIR fields.
62/// - `determine_by` - Specifies how enum variants are determined during
63///   deserialization.
64/// - `cardinality` - Defines validation cardinality constraints.
65/// - `reference` - Marks reference fields.
66/// - `fhir_resource_type` - Overrides the FHIR resource type name.
67#[proc_macro_derive(
68    FHIRSerdeDeserialize,
69    attributes(
70        fhir_serialize_type,
71        rename_field,
72
73        // Used on the enum itself for typechoice.
74        type_choice_field_name,
75
76        // Used on field itself for variants.
77        type_choice_variants,
78
79        primitive,
80
81        // Used for enum serialization.
82        determine_by,
83
84        // For validation on vector min maxes.
85        cardinality,
86        reference,
87
88        // if resourcetype doesn't correlate to struct name
89        fhir_resource_type
90    )
91)]
92pub fn serde_deserialize(input: TokenStream) -> TokenStream {
93    let input = parse_macro_input!(input as DeriveInput);
94
95    let serialize_type = get_attribute_serialization_type(&input.attrs);
96
97    match serialize_type.as_deref() {
98        Some("primitive") => serde_deserialize::fhir_primitive_deserialization(input),
99        Some("valueset") => serde_deserialize::valueset_deserialization(input),
100        Some("typechoice") => serde_deserialize::typechoice_deserialization(input),
101        Some("complex") => {
102            serde_deserialize::complex_deserialization(input, DeserializeComplexType::Complex)
103        }
104        Some("resource") => {
105            serde_deserialize::complex_deserialization(input, DeserializeComplexType::Resource)
106        }
107        None => panic!("Missing deserialization type attribute"),
108        _ => panic!("Only primitive and valueset supported for serde deserialization."),
109    }
110}
111
112/// Derives Serde-based FHIR JSON serialization implementations.
113///
114/// The macro behavior is selected using the `fhir_serialize_type` attribute.
115///
116/// Supported serialization types:
117/// - `primitive`
118/// - `valueset`
119/// - `typechoice`
120/// - `complex`
121/// - `resource`
122/// - `enum-variant`
123///
124/// # Panics
125///
126/// Panics if:
127/// - The `fhir_serialize_type` attribute is missing.
128/// - The `fhir_serialize_type` attribute contains an unsupported value.
129///
130/// # Attributes
131///
132/// This macro supports the following attributes:
133/// - `fhir_serialize_type` - Selects the serialization implementation.
134/// - `rename_field` - Renames a serialized field.
135/// - `type_choice_field_name` - Defines the field name used for type choice
136///   serialization.
137/// - `type_choice_variants` - Defines variants for type choice fields.
138/// - `primitive` - Marks primitive FHIR fields.
139/// - `code` - Marks code fields.
140/// - `cardinality` - Defines validation cardinality constraints.
141/// - `reference` - Marks reference fields.
142/// - `fhir_resource_type` - Overrides the FHIR resource type name.
143#[proc_macro_derive(
144    FHIRSerdeSerialize,
145    attributes(
146        fhir_serialize_type,
147        rename_field,
148        // Used on the enum itself for typechoice.
149        type_choice_field_name,
150         // Used on field itself for variants.
151        type_choice_variants,
152        primitive,
153        code,
154        // For validation on vector min maxes.
155        cardinality,
156        reference,
157
158        // if resourcetype doesn't correlate to struct name
159        fhir_resource_type
160    )
161)]
162pub fn serde_serialize(input: TokenStream) -> TokenStream {
163    let input = parse_macro_input!(input as DeriveInput);
164
165    let serialize_type = get_attribute_serialization_type(&input.attrs);
166
167    match serialize_type.as_deref() {
168        Some("primitive") => serde_serialize::fhir_primitive_serialization(input),
169        Some("valueset") => serde_serialize::valueset_serialization(input),
170        Some("typechoice") => serde_serialize::typechoice_serialization(input),
171        Some("complex") => {
172            serde_serialize::complex_serialization(input, DeserializeComplexType::Complex)
173        }
174        Some("resource") => {
175            serde_serialize::complex_serialization(input, DeserializeComplexType::Resource)
176        }
177        Some("enum-variant") => serde_serialize::enum_variant_serialization(input),
178        None => panic!("Missing serialization type attribute"),
179        _ => panic!("Only primitive and valueset supported for serde deserialization."),
180    }
181}