| Crates.io | helios-fhir-macro |
| lib.rs | helios-fhir-macro |
| version | 0.1.16 |
| created_at | 2025-08-22 15:10:15.871368+00 |
| updated_at | 2025-09-11 12:50:18.80267+00 |
| description | The helios-fhirpath-support crate serves as a bridge module that provides essential types and traits for integration between the FHIRPath evaluator, it's associated functions, and also the FHIR model code in the fhir module, and it's generated code that is created by fhir_macro. |
| homepage | https://github.com/HeliosSoftware/hfs/tree/main/crates/fhir-macro |
| repository | https://github.com/HeliosSoftware/hfs |
| max_upload_size | |
| id | 1806487 |
| size | 184,678 |
This crate provides procedural macros that enable automatic code generation for FHIR (Fast Healthcare Interoperability Resources) implementations in Rust. It contains the core macro functionality that powers serialization, deserialization, and FHIRPath evaluation.
The helios-fhir-macro crate implements two essential derive macros that handle the complex serialization patterns required by the FHIR specification:
#[derive(FhirSerde)] - Custom serialization/deserialization handling FHIR's JSON representation including it's extension pattern#[derive(FhirPath)] - Automatic conversion to FHIRPath evaluation results for resource traversalThese macros are automatically applied to thousands of generated FHIR types, eliminating the need for hand-written serialization code while ensuring compliance with FHIR's serialization requirements.
#[derive(FhirSerde)]The FhirSerde derive macro automatically implements serde::Serialize and serde::Deserialize for FHIR types, handling the serialization patterns required by the FHIR specification.
_fieldName extension patternElement<T, Extension> and DecimalElement<Extension> typesvalue[x] fields) with proper renaming// Field renaming for FHIR naming conventions
#[fhir_serde(rename = "implicitRules")]
pub implicit_rules: Option<Uri>,
// Field flattening for choice types and inheritance
#[fhir_serde(flatten)]
pub subject: Option<ActivityDefinitionSubject>,
use helios_fhir_macro::FhirSerde;
// Basic struct with FHIR serialization
#[derive(Debug, Clone, PartialEq, Eq, FhirSerde, Default)]
pub struct Patient {
pub id: Option<String>,
pub extension: Option<Vec<Extension>>,
#[fhir_serde(rename = "implicitRules")]
pub implicit_rules: Option<Uri>,
pub active: Option<Boolean>, // Element<bool, Extension>
pub name: Option<Vec<HumanName>>,
}
// Choice type enum with proper serialization
#[derive(Debug, Clone, PartialEq, Eq, FhirSerde)]
pub enum ObservationValue {
#[fhir_serde(rename = "valueQuantity")]
Quantity(Quantity),
#[fhir_serde(rename = "valueCodeableConcept")]
CodeableConcept(CodeableConcept),
#[fhir_serde(rename = "valueString")]
String(String),
}
The macro automatically handles FHIR's extension pattern where primitive elements can have extensions:
// Input JSON
{
"status": "active",
"_status": {
"id": "status-1",
"extension": [...]
}
}
// Generated serialization code handles both parts automatically
pub struct SomeResource {
pub status: Option<Code>, // Element<String, Extension>
}
#[derive(FhirPath)]The FhirPath derive macro automatically implements the fhirpath_support::IntoEvaluationResult trait, enabling FHIR resources to be used in FHIRPath expressions.
EvaluationResult::Object with field mappingsresourceType field for Resource enum variants#[fhir_serde(rename)])use helios_fhir_macro::FhirPath;
use helios_fhirpath_support::{IntoEvaluationResult, EvaluationResult};
// Struct conversion to FHIRPath object
#[derive(FhirPath)]
pub struct Patient {
pub id: Option<String>,
pub active: Option<Boolean>,
pub name: Option<Vec<HumanName>>,
}
// Usage in FHIRPath evaluation
let patient = Patient {
id: Some("123".to_string()),
active: Some(Boolean::from(true)),
name: Some(vec![...]),
};
let result = patient.to_evaluation_result();
// Results in EvaluationResult::Object with fields: id, active, name
The FhirSerde macro implements FHIR's complex extension pattern:
// For fields like: pub status: Option<Code>
// Where Code = Element<String, Extension>
// Serializes as:
{
"status": "active", // The primitive value
"_status": { // Extension object if present
"id": "status-1",
"extension": [...]
}
}
// Deserializes by:
// 1. Collecting both "status" and "_status" fields
// 2. Constructing Element<String, Extension> with both parts
// 3. Handling cases where only primitive or only extension exists
Choice types (FHIR's [x] fields) are handled through enum serialization:
// Generated enum
pub enum ObservationValue {
#[fhir_serde(rename = "valueQuantity")]
Quantity(Quantity),
#[fhir_serde(rename = "valueString")]
String(String),
}
// Serializes as single key-value pair:
{ "valueQuantity": {...} } // for Quantity variant
{ "valueString": "text" } // for String variant
For arrays of Element types, the macro implements FHIR's split array pattern:
// Field: pub given: Option<Vec<String>> // Vec<Element<String, Extension>>
// Serializes as:
{
"given": ["John", "Michael", null], // Primitive array
"_given": [null, {"id": "name-2"}, {}] // Extension array
}
#[fhir_serde(rename = "...")]Renames fields during serialization to match FHIR naming conventions:
#[fhir_serde(rename = "modifierExtension")]
pub modifier_extension: Option<Vec<Extension>>,
// Serializes as "modifierExtension" not "modifier_extension"
#[fhir_serde(flatten)]Flattens fields into the parent object for choice types and inheritance:
pub struct ActivityDefinition {
pub name: Option<String>,
#[fhir_serde(flatten)]
pub subject: Option<ActivityDefinitionSubject>, // Choice type enum
}
// Flattens the enum variant directly into the parent:
{
"name": "My Activity",
"subjectCodeableConcept": {...} // From flattened choice
}
All generated FHIR types in the fhir crate automatically use these macros:
// In crates/fhir/src/r4.rs, r4b.rs, r5.rs, r6.rs:
use helios_fhir_macro::{FhirSerde, FhirPath};
#[derive(Debug, Clone, PartialEq, Eq, FhirSerde, FhirPath, Default)]
pub struct Patient {
// ... fields with proper attributes
}
#[derive(Debug, Clone, PartialEq, Eq, FhirSerde, FhirPath)]
pub enum ObservationValue {
#[fhir_serde(rename = "valueQuantity")]
Quantity(Quantity),
// ... other variants
}
The FhirPath derive enables seamless integration with the FHIRPath evaluator:
// In crates/fhirpath/src/evaluator.rs:
use helios_fhirpath_support::IntoEvaluationResult;
// All FHIR types can be used directly in FHIRPath expressions
fn evaluate_expression(resource: &Patient, path: &str) -> EvaluationResult {
// Patient automatically implements IntoEvaluationResult via #[derive(FhirPath)]
resource.to_evaluation_result()
}
The helios-fhir-gen crate automatically applies these derives:
// In crates/fhir_gen/src/lib.rs:
let struct_derives = vec!["Debug", "Clone", "PartialEq", "Eq", "FhirSerde", "FhirPath", "Default"];
output.push_str(&format!("#[derive({})]\n", struct_derives.join(", ")));
// For enums:
let enum_derives = vec!["Debug", "Clone", "PartialEq", "Eq", "FhirSerde", "FhirPath"];
The macro implementations include comprehensive tests covering:
_fieldName patterns