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}