helios_fhir/
lib.rs

1//! # FHIR Model Infrastructure
2//!
3//! This module provides the foundational types and infrastructure that support the
4//! generated FHIR specification implementations. It contains hand-coded types that
5//! enable the generated code to handle FHIR's complex requirements for precision,
6//! extensions, and cross-version compatibility.
7
8//!
9//! ## Architecture
10//!
11//! The FHIR crate is organized as follows:
12//! - **Generated modules** (`r4.rs`, `r4b.rs`, `r5.rs`, `r6.rs`): Complete FHIR type implementations
13//! - **Infrastructure module** (`lib.rs`): Foundational types used by generated code
14//! - **Test modules**: Validation against official FHIR examples
15//!
16//! ## Key Infrastructure Types
17//!
18//! - [`PreciseDecimal`] - High-precision decimal arithmetic preserving original string format
19//! - [`Element<T, Extension>`] - Base container for FHIR elements with extension support
20//! - [`DecimalElement<Extension>`] - Specialized element for decimal values
21//! - [`FhirVersion`] - Version enumeration for multi-version support
22//!
23//! ## Usage Example
24//!
25//! ```rust
26//! use helios_fhir::r4::{Patient, HumanName};
27//! use helios_fhir::PreciseDecimal;
28//! use rust_decimal::Decimal;
29//!
30//! // Create a patient with precise decimal handling
31//! let patient = Patient {
32//!     name: Some(vec![HumanName {
33//!         family: Some("Doe".to_string().into()),
34//!         given: Some(vec!["John".to_string().into()]),
35//!         ..Default::default()
36//!     }]),
37//!     ..Default::default()
38//! };
39//!
40//! // Work with precise decimals
41//! let precise = PreciseDecimal::from(Decimal::new(12340, 3)); // 12.340
42//! ```
43
44use helios_fhirpath_support::{EvaluationResult, IntoEvaluationResult};
45use rust_decimal::Decimal;
46use serde::{
47    Deserialize, Serialize,
48    de::{self, Deserializer, MapAccess, Visitor},
49    ser::{SerializeStruct, Serializer},
50};
51use std::marker::PhantomData;
52
53/// Custom deserializer that is more forgiving of null values in JSON.
54///
55/// This creates a custom `Option<T>` deserializer that will return None for null values
56/// but also for any deserialization errors. This makes it possible to skip over
57/// malformed or unexpected values in FHIR JSON.
58pub fn deserialize_forgiving_option<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
59where
60    T: Deserialize<'de>,
61    D: Deserializer<'de>,
62{
63    // Use the intermediate Value approach to check for null first
64    let json_value = serde_json::Value::deserialize(deserializer)?;
65
66    match json_value {
67        serde_json::Value::Null => Ok(None),
68        _ => {
69            // Try to deserialize the value, but return None if it fails
70            match T::deserialize(json_value) {
71                Ok(value) => Ok(Some(value)),
72                Err(_) => Ok(None), // Ignore errors and return None
73            }
74        }
75    }
76}
77
78/// High-precision decimal type that preserves original string representation.
79///
80/// FHIR requires that decimal values maintain their original precision and format
81/// when serialized back to JSON. This type stores both the parsed `Decimal` value
82/// for mathematical operations and the original string for serialization.
83///
84/// # FHIR Precision Requirements
85///
86/// FHIR decimal values must:
87/// - Preserve trailing zeros (e.g., "12.340" vs "12.34")
88/// - Maintain original precision during round-trip serialization
89/// - Support high-precision arithmetic without floating-point errors
90/// - Handle edge cases like very large or very small numbers
91///
92/// # Examples
93///
94/// ```rust
95/// use helios_fhir::PreciseDecimal;
96/// use rust_decimal::Decimal;
97///
98/// // Create from Decimal (derives string representation)
99/// let precise = PreciseDecimal::from(Decimal::new(12340, 3)); // 12.340
100/// assert_eq!(precise.original_string(), "12.340");
101///
102/// // Create with specific string format
103/// let precise = PreciseDecimal::from_parts(
104///     Some(Decimal::new(1000, 2)),
105///     "10.00".to_string()
106/// );
107/// assert_eq!(precise.original_string(), "10.00");
108/// ```
109#[derive(Debug, Clone)]
110pub struct PreciseDecimal {
111    /// The parsed decimal value, `None` if parsing failed (e.g., out of range)
112    value: Option<Decimal>,
113    /// The original string representation preserving format and precision
114    original_string: String,
115}
116
117/// Implements equality comparison based on the parsed decimal value.
118///
119/// Two `PreciseDecimal` values are equal if their parsed `Decimal` values are equal,
120/// regardless of their original string representations. This enables mathematical
121/// equality while preserving string format for serialization.
122///
123/// # Examples
124///
125/// ```rust
126/// use helios_fhir::PreciseDecimal;
127/// use rust_decimal::Decimal;
128///
129/// let a = PreciseDecimal::from_parts(Some(Decimal::new(100, 1)), "10.0".to_string());
130/// let b = PreciseDecimal::from_parts(Some(Decimal::new(1000, 2)), "10.00".to_string());
131/// assert_eq!(a, b); // Same decimal value (10.0 == 10.00)
132/// ```
133impl PartialEq for PreciseDecimal {
134    fn eq(&self, other: &Self) -> bool {
135        // Compare parsed decimal values for mathematical equality
136        self.value == other.value
137    }
138}
139
140/// Marker trait implementation indicating total equality for `PreciseDecimal`.
141impl Eq for PreciseDecimal {}
142
143/// Implements partial ordering based on the parsed decimal value.
144///
145/// Ordering is based on the mathematical value of the decimal, not the string
146/// representation. `None` values (unparseable decimals) are considered less than
147/// any valid decimal value.
148impl PartialOrd for PreciseDecimal {
149    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
150        Some(self.cmp(other))
151    }
152}
153
154/// Implements total ordering for `PreciseDecimal`.
155///
156/// Provides a consistent ordering for sorting operations. The ordering is based
157/// on the mathematical value: `None` < `Some(smaller_decimal)` < `Some(larger_decimal)`.
158impl Ord for PreciseDecimal {
159    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
160        self.value.cmp(&other.value)
161    }
162}
163
164// === PreciseDecimal Methods ===
165
166impl PreciseDecimal {
167    /// Creates a new `PreciseDecimal` from its constituent parts.
168    ///
169    /// This constructor allows explicit control over both the parsed value and the
170    /// original string representation. Use this when you need to preserve a specific
171    /// string format or when parsing has already been attempted.
172    ///
173    /// # Arguments
174    ///
175    /// * `value` - The parsed decimal value, or `None` if parsing failed
176    /// * `original_string` - The original string representation to preserve
177    ///
178    /// # Examples
179    ///
180    /// ```rust
181    /// use helios_fhir::PreciseDecimal;
182    /// use rust_decimal::Decimal;
183    ///
184    /// // Create with successful parsing
185    /// let precise = PreciseDecimal::from_parts(
186    ///     Some(Decimal::new(12340, 3)),
187    ///     "12.340".to_string()
188    /// );
189    ///
190    /// // Create with failed parsing (preserves original string)
191    /// let invalid = PreciseDecimal::from_parts(
192    ///     None,
193    ///     "invalid_decimal".to_string()
194    /// );
195    /// ```
196    pub fn from_parts(value: Option<Decimal>, original_string: String) -> Self {
197        Self {
198            value,
199            original_string,
200        }
201    }
202
203    /// Helper method to parse a decimal string with support for scientific notation.
204    ///
205    /// This method handles the complexity of parsing decimal strings that may be in
206    /// scientific notation (with 'E' or 'e' exponents) or regular decimal format.
207    /// It normalizes 'E' to 'e' for consistent parsing while preserving the original
208    /// string representation for serialization.
209    ///
210    /// # Arguments
211    ///
212    /// * `s` - The string to parse as a decimal
213    ///
214    /// # Returns
215    ///
216    /// `Some(Decimal)` if parsing succeeds, `None` if the string is not a valid decimal.
217    ///
218    /// # Examples
219    ///
220    /// ```ignore
221    /// use helios_fhir::PreciseDecimal;
222    /// use rust_decimal::Decimal;
223    ///
224    /// // Regular decimal format
225    /// assert!(PreciseDecimal::parse_decimal_string("123.45").is_some());
226    ///
227    /// // Scientific notation with 'e'
228    /// assert!(PreciseDecimal::parse_decimal_string("1.23e2").is_some());
229    ///
230    /// // Scientific notation with 'E' (normalized to 'e')
231    /// assert!(PreciseDecimal::parse_decimal_string("1.23E2").is_some());
232    ///
233    /// // Invalid format
234    /// assert!(PreciseDecimal::parse_decimal_string("invalid").is_none());
235    /// ```
236    fn parse_decimal_string(s: &str) -> Option<Decimal> {
237        // Normalize 'E' to 'e' for consistent parsing
238        let normalized = s.replace('E', "e");
239
240        if normalized.contains('e') {
241            // Use scientific notation parsing
242            Decimal::from_scientific(&normalized).ok()
243        } else {
244            // Use regular decimal parsing
245            normalized.parse::<Decimal>().ok()
246        }
247    }
248
249    /// Returns the parsed decimal value if parsing was successful.
250    ///
251    /// This method provides access to the mathematical value for arithmetic
252    /// operations and comparisons. Returns `None` if the original string
253    /// could not be parsed as a valid decimal.
254    ///
255    /// # Examples
256    ///
257    /// ```rust
258    /// use helios_fhir::PreciseDecimal;
259    /// use rust_decimal::Decimal;
260    ///
261    /// let precise = PreciseDecimal::from(Decimal::new(1234, 2)); // 12.34
262    /// assert_eq!(precise.value(), Some(Decimal::new(1234, 2)));
263    ///
264    /// let invalid = PreciseDecimal::from_parts(None, "invalid".to_string());
265    /// assert_eq!(invalid.value(), None);
266    /// ```
267    pub fn value(&self) -> Option<Decimal> {
268        self.value
269    }
270
271    /// Returns the original string representation.
272    ///
273    /// This method provides access to the exact string format that was used
274    /// to create this `PreciseDecimal`. This string is used during serialization
275    /// to maintain FHIR's precision requirements.
276    ///
277    /// # Examples
278    ///
279    /// ```rust
280    /// use helios_fhir::PreciseDecimal;
281    /// use rust_decimal::Decimal;
282    ///
283    /// let precise = PreciseDecimal::from_parts(
284    ///     Some(Decimal::new(100, 2)),
285    ///     "1.00".to_string()
286    /// );
287    /// assert_eq!(precise.original_string(), "1.00");
288    /// ```
289    pub fn original_string(&self) -> &str {
290        &self.original_string
291    }
292}
293
294/// Converts a `Decimal` to `PreciseDecimal` with derived string representation.
295///
296/// This implementation allows easy conversion from `rust_decimal::Decimal` values
297/// by automatically generating the string representation using the decimal's
298/// `Display` implementation.
299///
300/// # Examples
301///
302/// ```rust
303/// use helios_fhir::PreciseDecimal;
304/// use rust_decimal::Decimal;
305///
306/// let decimal = Decimal::new(12345, 3); // 12.345
307/// let precise: PreciseDecimal = decimal.into();
308/// assert_eq!(precise.value(), Some(decimal));
309/// assert_eq!(precise.original_string(), "12.345");
310/// ```
311impl From<Decimal> for PreciseDecimal {
312    fn from(value: Decimal) -> Self {
313        // Generate string representation from the decimal value
314        let original_string = value.to_string();
315        Self {
316            value: Some(value),
317            original_string,
318        }
319    }
320}
321
322/// Implements serialization for `PreciseDecimal` preserving original format.
323///
324/// This implementation ensures that the exact original string representation
325/// is preserved during JSON serialization, maintaining FHIR's precision
326/// requirements including trailing zeros and specific formatting.
327///
328/// # FHIR Compliance
329///
330/// FHIR requires that decimal values maintain their original precision when
331/// round-tripped through JSON. This implementation uses `serde_json::RawValue`
332/// to serialize the original string directly as a JSON number.
333///
334/// # Examples
335///
336/// ```rust
337/// use helios_fhir::PreciseDecimal;
338/// use rust_decimal::Decimal;
339/// use serde_json;
340///
341/// let precise = PreciseDecimal::from_parts(
342///     Some(Decimal::new(1230, 2)),
343///     "12.30".to_string()
344/// );
345///
346/// let json = serde_json::to_string(&precise).unwrap();
347/// assert_eq!(json, "12.30"); // Preserves trailing zero
348/// ```
349impl Serialize for PreciseDecimal {
350    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
351    where
352        S: Serializer,
353    {
354        // Use RawValue to preserve exact string format in JSON
355        match serde_json::value::RawValue::from_string(self.original_string.clone()) {
356            Ok(raw_value) => raw_value.serialize(serializer),
357            Err(e) => Err(serde::ser::Error::custom(format!(
358                "Failed to serialize PreciseDecimal '{}': {}",
359                self.original_string, e
360            ))),
361        }
362    }
363}
364
365/// Implements deserialization for `PreciseDecimal` preserving original format.
366///
367/// This implementation deserializes JSON numbers and strings into `PreciseDecimal`
368/// while preserving the exact original string representation. It handles various
369/// JSON formats including scientific notation and nested object structures.
370///
371/// # Supported Formats
372///
373/// - Direct numbers: `12.340`
374/// - String numbers: `"12.340"`
375/// - Scientific notation: `1.234e2` or `1.234E2`
376/// - Nested objects: `{"value": 12.340}` (for macro-generated structures)
377///
378/// # Examples
379///
380/// ```rust
381/// use helios_fhir::PreciseDecimal;
382/// use serde_json;
383///
384/// // Deserialize from JSON number (trailing zeros are normalized)
385/// let precise: PreciseDecimal = serde_json::from_str("12.340").unwrap();
386/// assert_eq!(precise.original_string(), "12.340"); // JSON number format
387///
388/// // Deserialize from JSON string (preserves exact format)
389/// let precise: PreciseDecimal = serde_json::from_str("\"12.340\"").unwrap();
390/// assert_eq!(precise.original_string(), "12.340"); // Preserves string format
391/// ```
392impl<'de> Deserialize<'de> for PreciseDecimal {
393    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
394    where
395        D: Deserializer<'de>,
396    {
397        // Use intermediate Value to capture exact string representation
398        let json_value = serde_json::Value::deserialize(deserializer)?;
399
400        match json_value {
401            serde_json::Value::Number(n) => {
402                // Extract string representation from JSON number
403                let original_string = n.to_string();
404                let parsed_value = Self::parse_decimal_string(&original_string);
405                Ok(PreciseDecimal::from_parts(parsed_value, original_string))
406            }
407            serde_json::Value::String(s) => {
408                // Use string value directly (preserves exact format)
409                let parsed_value = Self::parse_decimal_string(&s);
410                Ok(PreciseDecimal::from_parts(parsed_value, s))
411            }
412            // Handle nested object format (for macro-generated structures)
413            serde_json::Value::Object(map) => match map.get("value") {
414                Some(serde_json::Value::Number(n)) => {
415                    let original_string = n.to_string();
416                    let parsed_value = Self::parse_decimal_string(&original_string);
417                    Ok(PreciseDecimal::from_parts(parsed_value, original_string))
418                }
419                Some(serde_json::Value::String(s)) => {
420                    let original_string = s.clone();
421                    let parsed_value = Self::parse_decimal_string(&original_string);
422                    Ok(PreciseDecimal::from_parts(parsed_value, original_string))
423                }
424                Some(serde_json::Value::Null) => Err(de::Error::invalid_value(
425                    de::Unexpected::Unit,
426                    &"a number or string for decimal value",
427                )),
428                None => Err(de::Error::missing_field("value")),
429                _ => Err(de::Error::invalid_type(
430                    de::Unexpected::Map,
431                    &"a map with a 'value' field containing a number or string",
432                )),
433            },
434            // Handle remaining unexpected types
435            other => Err(de::Error::invalid_type(
436                match other {
437                    serde_json::Value::Null => de::Unexpected::Unit, // Or Unexpected::Option if mapping null to None
438                    serde_json::Value::Bool(b) => de::Unexpected::Bool(b),
439                    serde_json::Value::Array(_) => de::Unexpected::Seq,
440                    _ => de::Unexpected::Other("unexpected JSON type for PreciseDecimal"),
441                },
442                &"a number, string, or object with a 'value' field",
443            )),
444        }
445    }
446}
447
448// --- End PreciseDecimal ---
449
450// Removed DecimalElementObjectVisitor
451
452#[cfg(feature = "R4")]
453pub mod r4;
454#[cfg(feature = "R4B")]
455pub mod r4b;
456#[cfg(feature = "R5")]
457pub mod r5;
458#[cfg(feature = "R6")]
459pub mod r6;
460
461pub mod parameters;
462
463// Re-export commonly used types from parameters module
464pub use parameters::{ParameterValueAccessor, VersionIndependentParameters};
465
466// Removed the FhirSerde trait definition
467
468/// Multi-version FHIR resource container supporting version-agnostic operations.
469///
470/// This enum provides a unified interface for working with FHIR resources across
471/// different specification versions. It enables applications to handle multiple
472/// FHIR versions simultaneously while maintaining type safety and version-specific
473/// behavior where needed.
474///
475/// # Supported Versions
476///
477/// - **R4**: FHIR 4.0.1 (normative)
478/// - **R4B**: FHIR 4.3.0 (ballot)  
479/// - **R5**: FHIR 5.0.0 (ballot)
480/// - **R6**: FHIR 6.0.0 (draft)
481///
482/// # Feature Flags
483///
484/// Each FHIR version is controlled by a corresponding Cargo feature flag.
485/// Only enabled versions will be available in the enum variants.
486///
487/// # Examples
488///
489/// ```rust
490/// use helios_fhir::{FhirResource, FhirVersion};
491/// # #[cfg(feature = "R4")]
492/// use helios_fhir::r4::{Patient, HumanName};
493///
494/// # #[cfg(feature = "R4")]
495/// {
496///     // Create an R4 patient
497///     let patient = Patient {
498///         name: Some(vec![HumanName {
499///             family: Some("Doe".to_string().into()),
500///             given: Some(vec!["John".to_string().into()]),
501///             ..Default::default()
502///         }]),
503///         ..Default::default()
504///     };
505///
506///     // Wrap in version-agnostic container
507///     let resource = FhirResource::R4(Box::new(helios_fhir::r4::Resource::Patient(patient)));
508///     assert_eq!(resource.version(), FhirVersion::R4);
509/// }
510/// ```
511///
512/// # Version Detection
513///
514/// Use the `version()` method to determine which FHIR version a resource uses:
515///
516/// ```rust
517/// # use helios_fhir::{FhirResource, FhirVersion};
518/// # #[cfg(feature = "R4")]
519/// # {
520/// # let resource = FhirResource::R4(Box::new(helios_fhir::r4::Resource::Patient(Default::default())));
521/// match resource.version() {
522///     #[cfg(feature = "R4")]
523///     FhirVersion::R4 => println!("This is an R4 resource"),
524///     #[cfg(feature = "R4B")]
525///     FhirVersion::R4B => println!("This is an R4B resource"),
526///     #[cfg(feature = "R5")]
527///     FhirVersion::R5 => println!("This is an R5 resource"),
528///     #[cfg(feature = "R6")]
529///     FhirVersion::R6 => println!("This is an R6 resource"),
530/// }
531/// # }
532/// ```
533#[derive(Debug)]
534pub enum FhirResource {
535    /// FHIR 4.0.1 (normative) resource
536    #[cfg(feature = "R4")]
537    R4(Box<r4::Resource>),
538    /// FHIR 4.3.0 (ballot) resource
539    #[cfg(feature = "R4B")]
540    R4B(Box<r4b::Resource>),
541    /// FHIR 5.0.0 (ballot) resource
542    #[cfg(feature = "R5")]
543    R5(Box<r5::Resource>),
544    /// FHIR 6.0.0 (draft) resource
545    #[cfg(feature = "R6")]
546    R6(Box<r6::Resource>),
547}
548
549impl FhirResource {
550    /// Returns the FHIR specification version of this resource.
551    ///
552    /// This method provides version detection for multi-version applications,
553    /// enabling version-specific processing logic and compatibility checks.
554    ///
555    /// # Returns
556    ///
557    /// The `FhirVersion` enum variant corresponding to this resource's specification.
558    ///
559    /// # Examples
560    ///
561    /// ```rust
562    /// use helios_fhir::{FhirResource, FhirVersion};
563    ///
564    /// # #[cfg(feature = "R5")]
565    /// # {
566    /// # let resource = FhirResource::R5(Box::new(helios_fhir::r5::Resource::Patient(Default::default())));
567    /// let version = resource.version();
568    /// assert_eq!(version, FhirVersion::R5);
569    ///
570    /// // Use version for conditional logic
571    /// match version {
572    ///     FhirVersion::R5 => {
573    ///         println!("Processing R5 resource with latest features");
574    ///     },
575    ///     FhirVersion::R4 => {
576    ///         println!("Processing R4 resource with normative features");
577    ///     },
578    ///     _ => {
579    ///         println!("Processing other FHIR version");
580    ///     }
581    /// }
582    /// # }
583    /// ```
584    pub fn version(&self) -> FhirVersion {
585        match self {
586            #[cfg(feature = "R4")]
587            FhirResource::R4(_) => FhirVersion::R4,
588            #[cfg(feature = "R4B")]
589            FhirResource::R4B(_) => FhirVersion::R4B,
590            #[cfg(feature = "R5")]
591            FhirResource::R5(_) => FhirVersion::R5,
592            #[cfg(feature = "R6")]
593            FhirResource::R6(_) => FhirVersion::R6,
594        }
595    }
596}
597
598/// Enumeration of supported FHIR specification versions.
599///
600/// This enum represents the different versions of the FHIR (Fast Healthcare
601/// Interoperability Resources) specification that this library supports.
602/// Each version represents a specific release of the FHIR standard with
603/// its own set of features, resources, and compatibility requirements.
604///
605/// # Version Status
606///
607/// - **R4** (4.0.1): Normative version, widely adopted in production
608/// - **R4B** (4.3.0): Ballot version with additional features
609/// - **R5** (5.0.0): Ballot version with significant enhancements
610/// - **R6** (6.0.0): Draft version under active development
611///
612/// # Feature Flags
613///
614/// Each version is controlled by a corresponding Cargo feature flag:
615/// - `R4`: Enables FHIR R4 support
616/// - `R4B`: Enables FHIR R4B support  
617/// - `R5`: Enables FHIR R5 support
618/// - `R6`: Enables FHIR R6 support
619///
620/// # Examples
621///
622/// ```rust
623/// use helios_fhir::FhirVersion;
624///
625/// // Version comparison
626/// # #[cfg(all(feature = "R4", feature = "R5"))]
627/// # {
628/// assert_ne!(FhirVersion::R4, FhirVersion::R5);
629/// # }
630///
631/// // String representation
632/// # #[cfg(feature = "R4")]
633/// # {
634/// let version = FhirVersion::R4;
635/// assert_eq!(version.as_str(), "R4");
636/// assert_eq!(version.to_string(), "R4");
637/// # }
638/// ```
639///
640/// # CLI Integration
641///
642/// This enum implements `clap::ValueEnum` for command-line argument parsing:
643///
644/// ```rust,no_run
645/// use clap::Parser;
646/// use helios_fhir::FhirVersion;
647///
648/// #[derive(Parser)]
649/// struct Args {
650///     #[arg(value_enum)]
651///     version: FhirVersion,
652/// }
653/// ```
654#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
655pub enum FhirVersion {
656    /// FHIR 4.0.1 (normative) - The current normative version
657    #[cfg(feature = "R4")]
658    R4,
659    /// FHIR 4.3.0 (ballot) - Intermediate version with additional features
660    #[cfg(feature = "R4B")]
661    R4B,
662    /// FHIR 5.0.0 (ballot) - Next major version with significant changes
663    #[cfg(feature = "R5")]
664    R5,
665    /// FHIR 6.0.0 (draft) - Future version under development
666    #[cfg(feature = "R6")]
667    R6,
668}
669
670impl FhirVersion {
671    /// Returns the string representation of the FHIR version.
672    ///
673    /// This method provides the standard version identifier as used in
674    /// FHIR documentation, URLs, and configuration files.
675    ///
676    /// # Returns
677    ///
678    /// A static string slice representing the version (e.g., "R4", "R5").
679    ///
680    /// # Examples
681    ///
682    /// ```rust
683    /// use helios_fhir::FhirVersion;
684    ///
685    /// # #[cfg(feature = "R4")]
686    /// assert_eq!(FhirVersion::R4.as_str(), "R4");
687    /// # #[cfg(feature = "R5")]
688    /// assert_eq!(FhirVersion::R5.as_str(), "R5");
689    /// ```
690    ///
691    /// # Usage
692    ///
693    /// This method is commonly used for:
694    /// - Logging and debugging output
695    /// - Configuration file parsing
696    /// - API endpoint construction
697    /// - Version-specific resource loading
698    pub fn as_str(&self) -> &'static str {
699        match self {
700            #[cfg(feature = "R4")]
701            FhirVersion::R4 => "R4",
702            #[cfg(feature = "R4B")]
703            FhirVersion::R4B => "R4B",
704            #[cfg(feature = "R5")]
705            FhirVersion::R5 => "R5",
706            #[cfg(feature = "R6")]
707            FhirVersion::R6 => "R6",
708        }
709    }
710}
711
712/// Implements `Display` trait for user-friendly output formatting.
713///
714/// This enables `FhirVersion` to be used in string formatting operations
715/// and provides consistent output across different contexts.
716///
717/// # Examples
718///
719/// ```rust
720/// use helios_fhir::FhirVersion;
721///
722/// # #[cfg(feature = "R5")]
723/// # {
724/// let version = FhirVersion::R5;
725/// println!("Using FHIR version: {}", version); // Prints: "Using FHIR version: R5"
726///
727/// let formatted = format!("fhir-{}.json", version);
728/// assert_eq!(formatted, "fhir-R5.json");
729/// # }
730/// ```
731impl std::fmt::Display for FhirVersion {
732    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
733        write!(f, "{}", self.as_str())
734    }
735}
736
737/// Provides a default FHIR version when R4 feature is enabled.
738///
739/// R4 is chosen as the default because it is the current normative version
740/// of the FHIR specification and is widely adopted in production systems.
741///
742/// # Examples
743///
744/// ```rust
745/// use helios_fhir::FhirVersion;
746///
747/// # #[cfg(feature = "R4")]
748/// # {
749/// let default_version = FhirVersion::default();
750/// assert_eq!(default_version, FhirVersion::R4);
751/// # }
752/// ```
753#[cfg(feature = "R4")]
754impl Default for FhirVersion {
755    fn default() -> Self {
756        FhirVersion::R4
757    }
758}
759
760/// Implements `clap::ValueEnum` for command-line argument parsing.
761///
762/// This implementation enables `FhirVersion` to be used directly as a command-line
763/// argument type with clap, providing automatic parsing, validation, and help text
764/// generation.
765///
766/// # Examples
767///
768/// ```rust,no_run
769/// use clap::Parser;
770/// use helios_fhir::FhirVersion;
771///
772/// #[derive(Parser)]
773/// struct Args {
774///     /// FHIR specification version to use
775///     #[arg(value_enum, default_value_t = FhirVersion::default())]
776///     version: FhirVersion,
777/// }
778///
779/// // Command line: my-app --version R5
780/// let args = Args::parse();
781/// println!("Using FHIR version: {}", args.version);
782/// ```
783///
784/// # Generated Help Text
785///
786/// When using this enum with clap, the help text will automatically include
787/// all available FHIR versions based on enabled feature flags.
788impl clap::ValueEnum for FhirVersion {
789    fn value_variants<'a>() -> &'a [Self] {
790        &[
791            #[cfg(feature = "R4")]
792            FhirVersion::R4,
793            #[cfg(feature = "R4B")]
794            FhirVersion::R4B,
795            #[cfg(feature = "R5")]
796            FhirVersion::R5,
797            #[cfg(feature = "R6")]
798            FhirVersion::R6,
799        ]
800    }
801
802    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
803        Some(clap::builder::PossibleValue::new(self.as_str()))
804    }
805}
806
807/// Trait for providing FHIR resource type information
808///
809/// This trait allows querying which resource types are available in a specific
810/// FHIR version without hardcoding resource type lists in multiple places.
811pub trait FhirResourceTypeProvider {
812    /// Returns a vector of all resource type names supported in this FHIR version
813    fn get_resource_type_names() -> Vec<&'static str>;
814
815    /// Checks if a given type name is a resource type in this FHIR version
816    fn is_resource_type(type_name: &str) -> bool {
817        Self::get_resource_type_names()
818            .iter()
819            .any(|&resource_type| resource_type.eq_ignore_ascii_case(type_name))
820    }
821}
822
823// --- Internal Visitor for Element Object Deserialization ---
824
825/// Internal visitor struct for deserializing Element objects from JSON maps.
826///
827/// This visitor handles the complex deserialization logic for Element<V, E> when
828/// the JSON input is an object containing id, extension, and value fields.
829struct ElementObjectVisitor<V, E>(PhantomData<(V, E)>);
830
831impl<'de, V, E> Visitor<'de> for ElementObjectVisitor<V, E>
832where
833    V: Deserialize<'de>,
834    E: Deserialize<'de>,
835{
836    type Value = Element<V, E>;
837
838    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
839        formatter.write_str("an Element object")
840    }
841
842    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
843    where
844        A: MapAccess<'de>,
845    {
846        let mut id: Option<String> = None;
847        let mut extension: Option<Vec<E>> = None;
848        let mut value: Option<V> = None;
849
850        // Manually deserialize fields from the map
851        while let Some(key) = map.next_key::<String>()? {
852            match key.as_str() {
853                "id" => {
854                    if id.is_some() {
855                        return Err(de::Error::duplicate_field("id"));
856                    }
857                    id = Some(map.next_value()?);
858                }
859                "extension" => {
860                    if extension.is_some() {
861                        return Err(de::Error::duplicate_field("extension"));
862                    }
863                    extension = Some(map.next_value()?);
864                }
865                "value" => {
866                    if value.is_some() {
867                        return Err(de::Error::duplicate_field("value"));
868                    }
869                    // Deserialize directly into Option<V>
870                    value = Some(map.next_value()?);
871                }
872                // Ignore any unknown fields encountered
873                _ => {
874                    let _ = map.next_value::<de::IgnoredAny>()?;
875                }
876            }
877        }
878
879        Ok(Element {
880            id,
881            extension,
882            value,
883        })
884    }
885}
886
887/// Generic element container supporting FHIR's extension mechanism.
888///
889/// In FHIR, most primitive elements can be extended with additional metadata
890/// through the `id` and `extension` fields. This container type provides
891/// the infrastructure to support this pattern across all FHIR data types.
892///
893/// # Type Parameters
894///
895/// * `V` - The value type (e.g., `String`, `i32`, `PreciseDecimal`)
896/// * `E` - The extension type (typically the generated `Extension` struct)
897///
898/// # FHIR Element Structure
899///
900/// FHIR elements can appear in three forms:
901/// 1. **Primitive value**: Just the value itself (e.g., `"text"`, `42`)
902/// 2. **Extended primitive**: An object with `value`, `id`, and/or `extension` fields
903/// 3. **Extension-only**: An object with just `id` and/or `extension` (no value)
904///
905/// # Examples
906///
907/// ```rust
908/// use helios_fhir::{Element, r4::Extension};
909///
910/// // Simple primitive value
911/// let simple: Element<String, Extension> = Element {
912///     value: Some("Hello World".to_string()),
913///     id: None,
914///     extension: None,
915/// };
916///
917/// // Extended primitive with ID
918/// let with_id: Element<String, Extension> = Element {
919///     value: Some("Hello World".to_string()),
920///     id: Some("text-element-1".to_string()),
921///     extension: None,
922/// };
923///
924/// // Extension-only element (no value)
925/// let extension_only: Element<String, Extension> = Element {
926///     value: None,
927///     id: Some("disabled-element".to_string()),
928///     extension: Some(vec![/* extensions */]),
929/// };
930/// ```
931///
932/// # Serialization Behavior
933///
934/// - If only `value` is present: serializes as the primitive value directly
935/// - If `id` or `extension` are present: serializes as an object with all fields
936/// - If everything is `None`: serializes as `null`
937#[derive(Debug, PartialEq, Eq, Clone, Default)]
938pub struct Element<V, E> {
939    /// Optional element identifier for referencing within the resource
940    pub id: Option<String>,
941    /// Optional extensions providing additional metadata
942    pub extension: Option<Vec<E>>,
943    /// The actual primitive value
944    pub value: Option<V>,
945}
946
947// Custom Deserialize for Element<V, E>
948// Remove PartialEq/Eq bounds for V and E as they are not needed for deserialization itself
949impl<'de, V, E> Deserialize<'de> for Element<V, E>
950where
951    V: Deserialize<'de> + 'static, // Added 'static for TypeId comparisons
952    E: Deserialize<'de>,           // Removed PartialEq
953{
954    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
955    where
956        D: Deserializer<'de>,
957    {
958        // Use the AnyValueVisitor approach to handle different JSON input types
959        struct AnyValueVisitor<V, E>(PhantomData<(V, E)>);
960
961        impl<'de, V, E> Visitor<'de> for AnyValueVisitor<V, E>
962        where
963            V: Deserialize<'de> + 'static,
964            E: Deserialize<'de>,
965        {
966            type Value = Element<V, E>;
967
968            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
969                formatter
970                    .write_str("a primitive value (string, number, boolean), an object, or null")
971            }
972
973            // Handle primitive types by attempting to deserialize V and wrapping it
974            fn visit_bool<Er>(self, v: bool) -> Result<Self::Value, Er>
975            where
976                Er: de::Error,
977            {
978                V::deserialize(de::value::BoolDeserializer::new(v)).map(|value| Element {
979                    id: None,
980                    extension: None,
981                    value: Some(value),
982                })
983            }
984            fn visit_i64<Er>(self, v: i64) -> Result<Self::Value, Er>
985            where
986                Er: de::Error,
987            {
988                V::deserialize(de::value::I64Deserializer::new(v)).map(|value| Element {
989                    id: None,
990                    extension: None,
991                    value: Some(value),
992                })
993            }
994            fn visit_u64<Er>(self, v: u64) -> Result<Self::Value, Er>
995            where
996                Er: de::Error,
997            {
998                V::deserialize(de::value::U64Deserializer::new(v)).map(|value| Element {
999                    id: None,
1000                    extension: None,
1001                    value: Some(value),
1002                })
1003            }
1004            fn visit_f64<Er>(self, v: f64) -> Result<Self::Value, Er>
1005            where
1006                Er: de::Error,
1007            {
1008                V::deserialize(de::value::F64Deserializer::new(v)).map(|value| Element {
1009                    id: None,
1010                    extension: None,
1011                    value: Some(value),
1012                })
1013            }
1014            fn visit_str<Er>(self, v: &str) -> Result<Self::Value, Er>
1015            where
1016                Er: de::Error,
1017            {
1018                use std::any::TypeId;
1019
1020                // Try to handle numeric strings for integer types
1021                if TypeId::of::<V>() == TypeId::of::<i64>() {
1022                    if let Ok(int_val) = v.parse::<i64>() {
1023                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
1024                            |value| Element {
1025                                id: None,
1026                                extension: None,
1027                                value: Some(value),
1028                            },
1029                        );
1030                    }
1031                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
1032                    if let Ok(int_val) = v.parse::<i32>() {
1033                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
1034                            |value| Element {
1035                                id: None,
1036                                extension: None,
1037                                value: Some(value),
1038                            },
1039                        );
1040                    }
1041                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
1042                    if let Ok(int_val) = v.parse::<u64>() {
1043                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
1044                            |value| Element {
1045                                id: None,
1046                                extension: None,
1047                                value: Some(value),
1048                            },
1049                        );
1050                    }
1051                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
1052                    if let Ok(int_val) = v.parse::<u32>() {
1053                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
1054                            |value| Element {
1055                                id: None,
1056                                extension: None,
1057                                value: Some(value),
1058                            },
1059                        );
1060                    }
1061                }
1062
1063                // Fall back to normal string deserialization
1064                V::deserialize(de::value::StrDeserializer::new(v)).map(|value| Element {
1065                    id: None,
1066                    extension: None,
1067                    value: Some(value),
1068                })
1069            }
1070            fn visit_string<Er>(self, v: String) -> Result<Self::Value, Er>
1071            where
1072                Er: de::Error,
1073            {
1074                use std::any::TypeId;
1075
1076                // Try to handle numeric strings for integer types
1077                if TypeId::of::<V>() == TypeId::of::<i64>() {
1078                    if let Ok(int_val) = v.parse::<i64>() {
1079                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
1080                            |value| Element {
1081                                id: None,
1082                                extension: None,
1083                                value: Some(value),
1084                            },
1085                        );
1086                    }
1087                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
1088                    if let Ok(int_val) = v.parse::<i32>() {
1089                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
1090                            |value| Element {
1091                                id: None,
1092                                extension: None,
1093                                value: Some(value),
1094                            },
1095                        );
1096                    }
1097                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
1098                    if let Ok(int_val) = v.parse::<u64>() {
1099                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
1100                            |value| Element {
1101                                id: None,
1102                                extension: None,
1103                                value: Some(value),
1104                            },
1105                        );
1106                    }
1107                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
1108                    if let Ok(int_val) = v.parse::<u32>() {
1109                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
1110                            |value| Element {
1111                                id: None,
1112                                extension: None,
1113                                value: Some(value),
1114                            },
1115                        );
1116                    }
1117                }
1118
1119                // Fall back to normal string deserialization
1120                V::deserialize(de::value::StringDeserializer::new(v.clone())).map(|value| Element {
1121                    // Clone v for error message
1122                    id: None,
1123                    extension: None,
1124                    value: Some(value),
1125                })
1126            }
1127            fn visit_borrowed_str<Er>(self, v: &'de str) -> Result<Self::Value, Er>
1128            where
1129                Er: de::Error,
1130            {
1131                use std::any::TypeId;
1132
1133                // Try to handle numeric strings for integer types
1134                if TypeId::of::<V>() == TypeId::of::<i64>() {
1135                    if let Ok(int_val) = v.parse::<i64>() {
1136                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
1137                            |value| Element {
1138                                id: None,
1139                                extension: None,
1140                                value: Some(value),
1141                            },
1142                        );
1143                    }
1144                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
1145                    if let Ok(int_val) = v.parse::<i32>() {
1146                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
1147                            |value| Element {
1148                                id: None,
1149                                extension: None,
1150                                value: Some(value),
1151                            },
1152                        );
1153                    }
1154                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
1155                    if let Ok(int_val) = v.parse::<u64>() {
1156                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
1157                            |value| Element {
1158                                id: None,
1159                                extension: None,
1160                                value: Some(value),
1161                            },
1162                        );
1163                    }
1164                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
1165                    if let Ok(int_val) = v.parse::<u32>() {
1166                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
1167                            |value| Element {
1168                                id: None,
1169                                extension: None,
1170                                value: Some(value),
1171                            },
1172                        );
1173                    }
1174                }
1175
1176                // Fall back to normal string deserialization
1177                V::deserialize(de::value::BorrowedStrDeserializer::new(v)).map(|value| Element {
1178                    id: None,
1179                    extension: None,
1180                    value: Some(value),
1181                })
1182            }
1183            fn visit_bytes<Er>(self, v: &[u8]) -> Result<Self::Value, Er>
1184            where
1185                Er: de::Error,
1186            {
1187                V::deserialize(de::value::BytesDeserializer::new(v)).map(|value| Element {
1188                    id: None,
1189                    extension: None,
1190                    value: Some(value),
1191                })
1192            }
1193            fn visit_byte_buf<Er>(self, v: Vec<u8>) -> Result<Self::Value, Er>
1194            where
1195                Er: de::Error,
1196            {
1197                // Use BytesDeserializer with a slice reference &v
1198                V::deserialize(de::value::BytesDeserializer::new(&v)).map(|value| Element {
1199                    id: None,
1200                    extension: None,
1201                    value: Some(value),
1202                })
1203            }
1204
1205            // Handle null
1206            fn visit_none<Er>(self) -> Result<Self::Value, Er>
1207            where
1208                Er: de::Error,
1209            {
1210                Ok(Element {
1211                    id: None,
1212                    extension: None,
1213                    value: None,
1214                })
1215            }
1216            fn visit_unit<Er>(self) -> Result<Self::Value, Er>
1217            where
1218                Er: de::Error,
1219            {
1220                Ok(Element {
1221                    id: None,
1222                    extension: None,
1223                    value: None,
1224                })
1225            }
1226
1227            // Handle Option<T> by visiting Some
1228            fn visit_some<De>(self, deserializer: De) -> Result<Self::Value, De::Error>
1229            where
1230                De: Deserializer<'de>,
1231            {
1232                // Re-dispatch to deserialize_any to handle the inner type correctly
1233                deserializer.deserialize_any(self)
1234            }
1235
1236            // Handle object
1237            fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
1238            where
1239                A: MapAccess<'de>,
1240            {
1241                // Deserialize the map using ElementObjectVisitor
1242                // Need to create a deserializer from the map access
1243                let map_deserializer = de::value::MapAccessDeserializer::new(map);
1244                map_deserializer.deserialize_map(ElementObjectVisitor(PhantomData))
1245            }
1246
1247            // We don't expect sequences for a single Element
1248            fn visit_seq<A>(self, _seq: A) -> Result<Self::Value, A::Error>
1249            where
1250                A: de::SeqAccess<'de>,
1251            {
1252                Err(de::Error::invalid_type(de::Unexpected::Seq, &self))
1253            }
1254        }
1255
1256        // Start deserialization using the visitor
1257        deserializer.deserialize_any(AnyValueVisitor(PhantomData))
1258    }
1259}
1260
1261// Custom Serialize for Element<V, E>
1262// Remove PartialEq/Eq bounds for V and E as they are not needed for serialization itself
1263impl<V, E> Serialize for Element<V, E>
1264where
1265    V: Serialize, // Removed PartialEq + Eq
1266    E: Serialize, // Removed PartialEq
1267{
1268    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1269    where
1270        S: Serializer,
1271    {
1272        // If id and extension are None, serialize value directly (or null)
1273        if self.id.is_none() && self.extension.is_none() {
1274            match &self.value {
1275                Some(val) => val.serialize(serializer),
1276                None => serializer.serialize_none(),
1277            }
1278        } else {
1279            // Otherwise, serialize as an object containing id, extension, value if present
1280            let mut len = 0;
1281            if self.id.is_some() {
1282                len += 1;
1283            }
1284            if self.extension.is_some() {
1285                len += 1;
1286            }
1287            if self.value.is_some() {
1288                len += 1;
1289            }
1290
1291            let mut state = serializer.serialize_struct("Element", len)?;
1292            if let Some(id) = &self.id {
1293                state.serialize_field("id", id)?;
1294            }
1295            if let Some(extension) = &self.extension {
1296                state.serialize_field("extension", extension)?;
1297            }
1298            // Restore value serialization for direct Element serialization
1299            if let Some(value) = &self.value {
1300                state.serialize_field("value", value)?;
1301            }
1302            state.end()
1303        }
1304    }
1305}
1306
1307/// Specialized element container for FHIR decimal values with precision preservation.
1308///
1309/// This type combines the generic `Element` pattern with `PreciseDecimal` to provide
1310/// a complete solution for FHIR decimal elements that require both extension support
1311/// and precision preservation during serialization round-trips.
1312///
1313/// # Type Parameters
1314///
1315/// * `E` - The extension type (typically the generated `Extension` struct)
1316///
1317/// # FHIR Decimal Requirements
1318///
1319/// FHIR decimal elements must:
1320/// - Preserve original string precision (e.g., "12.30" vs "12.3")
1321/// - Support mathematical operations using `Decimal` arithmetic
1322/// - Handle extension metadata through `id` and `extension` fields
1323/// - Serialize back to the exact original format when possible
1324///
1325/// # Examples
1326///
1327/// ```rust
1328/// use helios_fhir::{DecimalElement, PreciseDecimal, r4::Extension};
1329/// use rust_decimal::Decimal;
1330///
1331/// // Create from a Decimal value
1332/// let decimal_elem = DecimalElement::<Extension>::new(Decimal::new(1234, 2)); // 12.34
1333///
1334/// // Create with extensions
1335/// let extended_decimal: DecimalElement<Extension> = DecimalElement {
1336///     value: Some(PreciseDecimal::from_parts(
1337///         Some(Decimal::new(12300, 3)),
1338///         "12.300".to_string()
1339///     )),
1340///     id: Some("precision-example".to_string()),
1341///     extension: Some(vec![/* extensions */]),
1342/// };
1343///
1344/// // Access the mathematical value
1345/// if let Some(precise) = &extended_decimal.value {
1346///     if let Some(decimal_val) = precise.value() {
1347///         println!("Mathematical value: {}", decimal_val);
1348///     }
1349///     println!("Original format: {}", precise.original_string());
1350/// }
1351/// ```
1352///
1353/// # Serialization Behavior
1354///
1355/// - **Value only**: Serializes as a JSON number preserving original precision
1356/// - **With extensions**: Serializes as an object with `value`, `id`, and `extension` fields
1357/// - **No value**: Serializes as an object with just the extension fields, or `null` if empty
1358///
1359/// # Integration with FHIRPath
1360///
1361/// When used with FHIRPath evaluation, `DecimalElement` returns:
1362/// - The `Decimal` value for mathematical operations
1363/// - An object representation when extension metadata is accessed
1364/// - Empty collection when the element has no value or extensions
1365#[derive(Debug, PartialEq, Eq, Clone, Default)]
1366pub struct DecimalElement<E> {
1367    /// Optional element identifier for referencing within the resource
1368    pub id: Option<String>,
1369    /// Optional extensions providing additional metadata
1370    pub extension: Option<Vec<E>>,
1371    /// The decimal value with precision preservation
1372    pub value: Option<PreciseDecimal>,
1373}
1374
1375impl<E> DecimalElement<E> {
1376    /// Creates a new `DecimalElement` with the specified decimal value.
1377    ///
1378    /// This constructor creates a simple decimal element with no extensions or ID,
1379    /// containing only the decimal value. The original string representation is
1380    /// automatically derived from the `Decimal` value's `Display` implementation.
1381    ///
1382    /// # Arguments
1383    ///
1384    /// * `value` - The `Decimal` value to store
1385    ///
1386    /// # Returns
1387    ///
1388    /// A new `DecimalElement` with the value set and `id`/`extension` as `None`.
1389    ///
1390    /// # Examples
1391    ///
1392    /// ```rust
1393    /// use helios_fhir::{DecimalElement, r4::Extension};
1394    /// use rust_decimal::Decimal;
1395    ///
1396    /// // Create a simple decimal element
1397    /// let element = DecimalElement::<Extension>::new(Decimal::new(12345, 3)); // 12.345
1398    ///
1399    /// // Verify the structure
1400    /// assert!(element.id.is_none());
1401    /// assert!(element.extension.is_none());
1402    /// assert!(element.value.is_some());
1403    ///
1404    /// // Access the decimal value
1405    /// if let Some(precise_decimal) = &element.value {
1406    ///     assert_eq!(precise_decimal.value(), Some(Decimal::new(12345, 3)));
1407    ///     assert_eq!(precise_decimal.original_string(), "12.345");
1408    /// }
1409    /// ```
1410    ///
1411    /// # Usage in FHIR Resources
1412    ///
1413    /// This method is typically used when creating FHIR elements programmatically:
1414    ///
1415    /// ```rust
1416    /// use helios_fhir::{DecimalElement, r4::{Extension, Observation}};
1417    /// use rust_decimal::Decimal;
1418    ///
1419    /// let temperature = DecimalElement::<Extension>::new(Decimal::new(3672, 2)); // 36.72
1420    ///
1421    /// // Would be used in an Observation like:
1422    /// // observation.value_quantity.value = Some(temperature);
1423    /// ```
1424    pub fn new(value: Decimal) -> Self {
1425        // Convert the Decimal to PreciseDecimal, which automatically handles
1426        // storing the original string representation via the From trait
1427        let precise_value = PreciseDecimal::from(value);
1428        Self {
1429            id: None,
1430            extension: None,
1431            value: Some(precise_value),
1432        }
1433    }
1434}
1435
1436// Custom Deserialize for DecimalElement<E> using intermediate Value
1437impl<'de, E> Deserialize<'de> for DecimalElement<E>
1438where
1439    E: Deserialize<'de> + Default,
1440{
1441    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1442    where
1443        D: Deserializer<'de>,
1444    {
1445        // Deserialize into an intermediate serde_json::Value first
1446        let json_value = serde_json::Value::deserialize(deserializer)?;
1447
1448        match json_value {
1449            // Handle primitive JSON Number
1450            serde_json::Value::Number(n) => {
1451                // Directly parse the number string to create PreciseDecimal
1452                let s = n.to_string(); // Note: n.to_string() might normalize exponent case (e.g., 'E' -> 'e')
1453                // Replace 'E' with 'e' for parsing
1454                let s_for_parsing = s.replace('E', "e");
1455                // Use from_scientific if 'e' is present, otherwise parse
1456                let parsed_value = if s_for_parsing.contains('e') {
1457                    Decimal::from_scientific(&s_for_parsing).ok()
1458                } else {
1459                    s_for_parsing.parse::<Decimal>().ok()
1460                };
1461                // Store the ORIGINAL string `s` (as returned by n.to_string()).
1462                let pd = PreciseDecimal::from_parts(parsed_value, s);
1463                Ok(DecimalElement {
1464                    id: None,
1465                    extension: None,
1466                    value: Some(pd),
1467                })
1468            }
1469            // Handle primitive JSON String
1470            serde_json::Value::String(s) => {
1471                // Directly parse the string to create PreciseDecimal
1472                // Replace 'E' with 'e' for parsing
1473                let s_for_parsing = s.replace('E', "e");
1474                // Use from_scientific if 'e' is present, otherwise parse
1475                let parsed_value = if s_for_parsing.contains('e') {
1476                    Decimal::from_scientific(&s_for_parsing).ok()
1477                } else {
1478                    s_for_parsing.parse::<Decimal>().ok()
1479                };
1480                // Store the ORIGINAL string `s`.
1481                let pd = PreciseDecimal::from_parts(parsed_value, s); // s is owned, no clone needed
1482                Ok(DecimalElement {
1483                    id: None,
1484                    extension: None,
1485                    value: Some(pd),
1486                })
1487            }
1488            // Handle JSON object: deserialize fields individually
1489            serde_json::Value::Object(map) => {
1490                let mut id: Option<String> = None;
1491                let mut extension: Option<Vec<E>> = None;
1492                let mut value: Option<PreciseDecimal> = None;
1493
1494                for (k, v) in map {
1495                    match k.as_str() {
1496                        "id" => {
1497                            if id.is_some() {
1498                                return Err(de::Error::duplicate_field("id"));
1499                            }
1500                            // Deserialize id directly from its Value
1501                            id = Deserialize::deserialize(v).map_err(de::Error::custom)?;
1502                        }
1503                        "extension" => {
1504                            if extension.is_some() {
1505                                return Err(de::Error::duplicate_field("extension"));
1506                            }
1507                            // Deserialize extension directly from its Value
1508                            extension = Deserialize::deserialize(v).map_err(de::Error::custom)?;
1509                        }
1510                        "value" => {
1511                            if value.is_some() {
1512                                return Err(de::Error::duplicate_field("value"));
1513                            }
1514                            // Deserialize value using PreciseDecimal::deserialize from its Value
1515                            // Handle null explicitly within the value field
1516                            if v.is_null() {
1517                                value = None;
1518                            } else {
1519                                value = Some(
1520                                    PreciseDecimal::deserialize(v).map_err(de::Error::custom)?,
1521                                );
1522                            }
1523                        }
1524                        // Ignore any unknown fields encountered
1525                        _ => {} // Simply ignore unknown fields
1526                    }
1527                }
1528                Ok(DecimalElement {
1529                    id,
1530                    extension,
1531                    value,
1532                })
1533            }
1534            // Handle JSON Null for the whole element
1535            serde_json::Value::Null => Ok(DecimalElement::default()), // Default has value: None
1536            // Handle other unexpected types
1537            other => Err(de::Error::invalid_type(
1538                match other {
1539                    serde_json::Value::Bool(b) => de::Unexpected::Bool(b),
1540                    serde_json::Value::Array(_) => de::Unexpected::Seq,
1541                    _ => de::Unexpected::Other("unexpected JSON type for DecimalElement"),
1542                },
1543                &"a decimal number, string, object, or null",
1544            )),
1545        }
1546    }
1547}
1548
1549// Reinstate custom Serialize implementation for DecimalElement
1550// Remove PartialEq bound for E
1551impl<E> Serialize for DecimalElement<E>
1552where
1553    E: Serialize, // Removed PartialEq bound for E
1554{
1555    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1556    where
1557        S: Serializer,
1558    {
1559        // If we only have a value and no other fields, serialize just the value
1560        if self.id.is_none() && self.extension.is_none() {
1561            if let Some(value) = &self.value {
1562                // Serialize the PreciseDecimal directly, invoking its custom Serialize impl
1563                return value.serialize(serializer);
1564            } else {
1565                // If value is also None, serialize as null
1566                // based on updated test_serialize_decimal_with_no_fields
1567                return serializer.serialize_none();
1568            }
1569        }
1570
1571        // Otherwise, serialize as a struct with all present fields
1572        // Calculate the number of fields that are NOT None
1573        let mut len = 0;
1574        if self.id.is_some() {
1575            len += 1;
1576        }
1577        if self.extension.is_some() {
1578            len += 1;
1579        }
1580        if self.value.is_some() {
1581            len += 1;
1582        }
1583
1584        // Start serializing a struct with the calculated length
1585        let mut state = serializer.serialize_struct("DecimalElement", len)?;
1586
1587        // Serialize 'id' field if it's Some
1588        if let Some(id) = &self.id {
1589            state.serialize_field("id", id)?;
1590        }
1591
1592        // Serialize 'extension' field if it's Some
1593        if let Some(extension) = &self.extension {
1594            state.serialize_field("extension", extension)?;
1595        }
1596
1597        // Serialize 'value' field if it's Some
1598        if let Some(value) = &self.value {
1599            // Serialize the PreciseDecimal directly, invoking its custom Serialize impl
1600            state.serialize_field("value", value)?;
1601        }
1602
1603        // End the struct serialization
1604        state.end()
1605    }
1606}
1607
1608// For Element<V, E> - Returns Object with id, extension, value if present
1609impl<V, E> IntoEvaluationResult for Element<V, E>
1610where
1611    V: IntoEvaluationResult + Clone + 'static,
1612    E: IntoEvaluationResult + Clone,
1613{
1614    fn to_evaluation_result(&self) -> EvaluationResult {
1615        use std::any::TypeId;
1616
1617        // Prioritize returning the primitive value if it exists
1618        if let Some(v) = &self.value {
1619            let result = v.to_evaluation_result();
1620            // For primitive values, we need to preserve FHIR type information
1621            return match result {
1622                EvaluationResult::Boolean(b, _) => {
1623                    // Return FHIR boolean
1624                    EvaluationResult::fhir_boolean(b)
1625                }
1626                EvaluationResult::Integer(i, _) => {
1627                    // Return FHIR integer
1628                    EvaluationResult::fhir_integer(i)
1629                }
1630                #[cfg(not(any(feature = "R4", feature = "R4B")))]
1631                EvaluationResult::Integer64(i, _) => {
1632                    // Return FHIR integer64 (R5 and above)
1633                    EvaluationResult::fhir_integer64(i)
1634                }
1635                EvaluationResult::String(s, _) => {
1636                    // Determine the FHIR type name based on V's type
1637                    let fhir_type_name = if TypeId::of::<V>() == TypeId::of::<String>() {
1638                        // For strings, we need more context to determine the exact FHIR type
1639                        // Default to "string" but this could be date, dateTime, etc.
1640                        "string"
1641                    } else {
1642                        // Default fallback
1643                        "string"
1644                    };
1645                    EvaluationResult::fhir_string(s, fhir_type_name)
1646                }
1647                _ => result, // For other types, return as-is
1648            };
1649        } else if self.id.is_some() || self.extension.is_some() {
1650            // If value is None, but id or extension exist, return an Object with those
1651            let mut map = std::collections::HashMap::new();
1652            if let Some(id) = &self.id {
1653                map.insert("id".to_string(), EvaluationResult::string(id.clone()));
1654            }
1655            if let Some(ext) = &self.extension {
1656                let ext_collection: Vec<EvaluationResult> =
1657                    ext.iter().map(|e| e.to_evaluation_result()).collect();
1658                if !ext_collection.is_empty() {
1659                    map.insert(
1660                        "extension".to_string(),
1661                        EvaluationResult::collection(ext_collection),
1662                    );
1663                }
1664            }
1665            // Only return Object if map is not empty (i.e., id or extension was actually present)
1666            if !map.is_empty() {
1667                return EvaluationResult::typed_object(map, "FHIR", "Element");
1668            }
1669        }
1670
1671        // If value, id, and extension are all None, return Empty
1672        EvaluationResult::Empty
1673    }
1674}
1675
1676// For DecimalElement<E> - Returns Decimal value if present, otherwise handles id/extension
1677impl<E> IntoEvaluationResult for DecimalElement<E>
1678where
1679    E: IntoEvaluationResult + Clone,
1680{
1681    fn to_evaluation_result(&self) -> EvaluationResult {
1682        // Prioritize returning the primitive decimal value if it exists
1683        if let Some(precise_decimal) = &self.value {
1684            if let Some(decimal_val) = precise_decimal.value() {
1685                // Return FHIR decimal
1686                return EvaluationResult::fhir_decimal(decimal_val);
1687            }
1688            // If PreciseDecimal holds None for value, fall through to check id/extension
1689        }
1690
1691        // If value is None, but id or extension exist, return an Object with those
1692        if self.id.is_some() || self.extension.is_some() {
1693            let mut map = std::collections::HashMap::new();
1694            if let Some(id) = &self.id {
1695                map.insert("id".to_string(), EvaluationResult::string(id.clone()));
1696            }
1697            if let Some(ext) = &self.extension {
1698                let ext_collection: Vec<EvaluationResult> =
1699                    ext.iter().map(|e| e.to_evaluation_result()).collect();
1700                if !ext_collection.is_empty() {
1701                    map.insert(
1702                        "extension".to_string(),
1703                        EvaluationResult::collection(ext_collection),
1704                    );
1705                }
1706            }
1707            // Only return Object if map is not empty
1708            if !map.is_empty() {
1709                return EvaluationResult::typed_object(map, "FHIR", "decimal");
1710            }
1711        }
1712
1713        // If value, id, and extension are all None, return Empty
1714        EvaluationResult::Empty
1715    }
1716}
1717
1718// Implement the trait for the top-level enum
1719impl IntoEvaluationResult for FhirResource {
1720    fn to_evaluation_result(&self) -> EvaluationResult {
1721        match self {
1722            #[cfg(feature = "R4")]
1723            FhirResource::R4(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r4::Resource>
1724            #[cfg(feature = "R4B")]
1725            FhirResource::R4B(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r4b::Resource>
1726            #[cfg(feature = "R5")]
1727            FhirResource::R5(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r5::Resource>
1728            #[cfg(feature = "R6")]
1729            FhirResource::R6(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r6::Resource>
1730                                                                // Note: If no features are enabled, this match might be empty or non-exhaustive.
1731                                                                // This is generally okay as the enum itself wouldn't be usable.
1732        }
1733    }
1734}
1735
1736#[cfg(test)]
1737mod tests {
1738    use super::*;
1739
1740    #[test]
1741    fn test_integer_string_deserialization() {
1742        // Test deserializing a string "2" into Element<i64, ()>
1743        type TestElement = Element<i64, ()>;
1744
1745        // Test case 1: String containing integer
1746        let json_str = r#""2""#;
1747        let result: Result<TestElement, _> = serde_json::from_str(json_str);
1748        assert!(
1749            result.is_ok(),
1750            "Failed to deserialize string '2' as i64: {:?}",
1751            result.err()
1752        );
1753
1754        let element = result.unwrap();
1755        assert_eq!(element.value, Some(2i64));
1756        assert_eq!(element.id, None);
1757        assert_eq!(element.extension, None);
1758
1759        // Test case 2: Number
1760        let json_num = r#"2"#;
1761        let result: Result<TestElement, _> = serde_json::from_str(json_num);
1762        assert!(
1763            result.is_ok(),
1764            "Failed to deserialize number 2 as i64: {:?}",
1765            result.err()
1766        );
1767
1768        let element = result.unwrap();
1769        assert_eq!(element.value, Some(2i64));
1770    }
1771
1772    #[test]
1773    fn test_i32_string_deserialization() {
1774        type TestElement = Element<i32, ()>;
1775
1776        let json_str = r#""123""#;
1777        let result: Result<TestElement, _> = serde_json::from_str(json_str);
1778        assert!(result.is_ok());
1779
1780        let element = result.unwrap();
1781        assert_eq!(element.value, Some(123i32));
1782    }
1783
1784    #[test]
1785    fn test_invalid_string_fallback() {
1786        type TestElement = Element<i64, ()>;
1787
1788        // Non-numeric string should fail for integer type
1789        let json_str = r#""not_a_number""#;
1790        let result: Result<TestElement, _> = serde_json::from_str(json_str);
1791        assert!(
1792            result.is_err(),
1793            "Should fail to deserialize non-numeric string as i64"
1794        );
1795    }
1796}