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/// Trait for providing FHIR complex type information
824///
825/// This trait allows querying which complex data types are available in a specific
826/// FHIR version without hardcoding complex type lists in multiple places.
827pub trait FhirComplexTypeProvider {
828    /// Returns a vector of all complex type names supported in this FHIR version
829    fn get_complex_type_names() -> Vec<&'static str>;
830
831    /// Checks if a given type name is a complex type in this FHIR version
832    fn is_complex_type(type_name: &str) -> bool {
833        Self::get_complex_type_names()
834            .iter()
835            .any(|&complex_type| complex_type.eq_ignore_ascii_case(type_name))
836    }
837}
838
839// --- Internal Visitor for Element Object Deserialization ---
840
841/// Internal visitor struct for deserializing Element objects from JSON maps.
842///
843/// This visitor handles the complex deserialization logic for Element<V, E> when
844/// the JSON input is an object containing id, extension, and value fields.
845struct ElementObjectVisitor<V, E>(PhantomData<(V, E)>);
846
847impl<'de, V, E> Visitor<'de> for ElementObjectVisitor<V, E>
848where
849    V: Deserialize<'de>,
850    E: Deserialize<'de>,
851{
852    type Value = Element<V, E>;
853
854    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
855        formatter.write_str("an Element object")
856    }
857
858    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
859    where
860        A: MapAccess<'de>,
861    {
862        let mut id: Option<String> = None;
863        let mut extension: Option<Vec<E>> = None;
864        let mut value: Option<V> = None;
865
866        // Manually deserialize fields from the map
867        while let Some(key) = map.next_key::<String>()? {
868            match key.as_str() {
869                "id" => {
870                    if id.is_some() {
871                        return Err(de::Error::duplicate_field("id"));
872                    }
873                    id = Some(map.next_value()?);
874                }
875                "extension" => {
876                    if extension.is_some() {
877                        return Err(de::Error::duplicate_field("extension"));
878                    }
879                    extension = Some(map.next_value()?);
880                }
881                "value" => {
882                    if value.is_some() {
883                        return Err(de::Error::duplicate_field("value"));
884                    }
885                    // Deserialize directly into Option<V>
886                    value = Some(map.next_value()?);
887                }
888                // Ignore any unknown fields encountered
889                _ => {
890                    let _ = map.next_value::<de::IgnoredAny>()?;
891                }
892            }
893        }
894
895        Ok(Element {
896            id,
897            extension,
898            value,
899        })
900    }
901}
902
903/// Generic element container supporting FHIR's extension mechanism.
904///
905/// In FHIR, most primitive elements can be extended with additional metadata
906/// through the `id` and `extension` fields. This container type provides
907/// the infrastructure to support this pattern across all FHIR data types.
908///
909/// # Type Parameters
910///
911/// * `V` - The value type (e.g., `String`, `i32`, `PreciseDecimal`)
912/// * `E` - The extension type (typically the generated `Extension` struct)
913///
914/// # FHIR Element Structure
915///
916/// FHIR elements can appear in three forms:
917/// 1. **Primitive value**: Just the value itself (e.g., `"text"`, `42`)
918/// 2. **Extended primitive**: An object with `value`, `id`, and/or `extension` fields
919/// 3. **Extension-only**: An object with just `id` and/or `extension` (no value)
920///
921/// # Examples
922///
923/// ```rust
924/// use helios_fhir::{Element, r4::Extension};
925///
926/// // Simple primitive value
927/// let simple: Element<String, Extension> = Element {
928///     value: Some("Hello World".to_string()),
929///     id: None,
930///     extension: None,
931/// };
932///
933/// // Extended primitive with ID
934/// let with_id: Element<String, Extension> = Element {
935///     value: Some("Hello World".to_string()),
936///     id: Some("text-element-1".to_string()),
937///     extension: None,
938/// };
939///
940/// // Extension-only element (no value)
941/// let extension_only: Element<String, Extension> = Element {
942///     value: None,
943///     id: Some("disabled-element".to_string()),
944///     extension: Some(vec![/* extensions */]),
945/// };
946/// ```
947///
948/// # Serialization Behavior
949///
950/// - If only `value` is present: serializes as the primitive value directly
951/// - If `id` or `extension` are present: serializes as an object with all fields
952/// - If everything is `None`: serializes as `null`
953#[derive(Debug, PartialEq, Eq, Clone, Default)]
954pub struct Element<V, E> {
955    /// Optional element identifier for referencing within the resource
956    pub id: Option<String>,
957    /// Optional extensions providing additional metadata
958    pub extension: Option<Vec<E>>,
959    /// The actual primitive value
960    pub value: Option<V>,
961}
962
963// Custom Deserialize for Element<V, E>
964// Remove PartialEq/Eq bounds for V and E as they are not needed for deserialization itself
965impl<'de, V, E> Deserialize<'de> for Element<V, E>
966where
967    V: Deserialize<'de> + 'static, // Added 'static for TypeId comparisons
968    E: Deserialize<'de>,           // Removed PartialEq
969{
970    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
971    where
972        D: Deserializer<'de>,
973    {
974        // Use the AnyValueVisitor approach to handle different JSON input types
975        struct AnyValueVisitor<V, E>(PhantomData<(V, E)>);
976
977        impl<'de, V, E> Visitor<'de> for AnyValueVisitor<V, E>
978        where
979            V: Deserialize<'de> + 'static,
980            E: Deserialize<'de>,
981        {
982            type Value = Element<V, E>;
983
984            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
985                formatter
986                    .write_str("a primitive value (string, number, boolean), an object, or null")
987            }
988
989            // Handle primitive types by attempting to deserialize V and wrapping it
990            fn visit_bool<Er>(self, v: bool) -> Result<Self::Value, Er>
991            where
992                Er: de::Error,
993            {
994                V::deserialize(de::value::BoolDeserializer::new(v)).map(|value| Element {
995                    id: None,
996                    extension: None,
997                    value: Some(value),
998                })
999            }
1000            fn visit_i64<Er>(self, v: i64) -> Result<Self::Value, Er>
1001            where
1002                Er: de::Error,
1003            {
1004                V::deserialize(de::value::I64Deserializer::new(v)).map(|value| Element {
1005                    id: None,
1006                    extension: None,
1007                    value: Some(value),
1008                })
1009            }
1010            fn visit_u64<Er>(self, v: u64) -> Result<Self::Value, Er>
1011            where
1012                Er: de::Error,
1013            {
1014                V::deserialize(de::value::U64Deserializer::new(v)).map(|value| Element {
1015                    id: None,
1016                    extension: None,
1017                    value: Some(value),
1018                })
1019            }
1020            fn visit_f64<Er>(self, v: f64) -> Result<Self::Value, Er>
1021            where
1022                Er: de::Error,
1023            {
1024                V::deserialize(de::value::F64Deserializer::new(v)).map(|value| Element {
1025                    id: None,
1026                    extension: None,
1027                    value: Some(value),
1028                })
1029            }
1030            fn visit_str<Er>(self, v: &str) -> Result<Self::Value, Er>
1031            where
1032                Er: de::Error,
1033            {
1034                use std::any::TypeId;
1035
1036                // Try to handle numeric strings for integer types
1037                if TypeId::of::<V>() == TypeId::of::<i64>() {
1038                    if let Ok(int_val) = v.parse::<i64>() {
1039                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
1040                            |value| Element {
1041                                id: None,
1042                                extension: None,
1043                                value: Some(value),
1044                            },
1045                        );
1046                    }
1047                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
1048                    if let Ok(int_val) = v.parse::<i32>() {
1049                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
1050                            |value| Element {
1051                                id: None,
1052                                extension: None,
1053                                value: Some(value),
1054                            },
1055                        );
1056                    }
1057                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
1058                    if let Ok(int_val) = v.parse::<u64>() {
1059                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
1060                            |value| Element {
1061                                id: None,
1062                                extension: None,
1063                                value: Some(value),
1064                            },
1065                        );
1066                    }
1067                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
1068                    if let Ok(int_val) = v.parse::<u32>() {
1069                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
1070                            |value| Element {
1071                                id: None,
1072                                extension: None,
1073                                value: Some(value),
1074                            },
1075                        );
1076                    }
1077                }
1078
1079                // Fall back to normal string deserialization
1080                V::deserialize(de::value::StrDeserializer::new(v)).map(|value| Element {
1081                    id: None,
1082                    extension: None,
1083                    value: Some(value),
1084                })
1085            }
1086            fn visit_string<Er>(self, v: String) -> Result<Self::Value, Er>
1087            where
1088                Er: de::Error,
1089            {
1090                use std::any::TypeId;
1091
1092                // Try to handle numeric strings for integer types
1093                if TypeId::of::<V>() == TypeId::of::<i64>() {
1094                    if let Ok(int_val) = v.parse::<i64>() {
1095                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
1096                            |value| Element {
1097                                id: None,
1098                                extension: None,
1099                                value: Some(value),
1100                            },
1101                        );
1102                    }
1103                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
1104                    if let Ok(int_val) = v.parse::<i32>() {
1105                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
1106                            |value| Element {
1107                                id: None,
1108                                extension: None,
1109                                value: Some(value),
1110                            },
1111                        );
1112                    }
1113                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
1114                    if let Ok(int_val) = v.parse::<u64>() {
1115                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
1116                            |value| Element {
1117                                id: None,
1118                                extension: None,
1119                                value: Some(value),
1120                            },
1121                        );
1122                    }
1123                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
1124                    if let Ok(int_val) = v.parse::<u32>() {
1125                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
1126                            |value| Element {
1127                                id: None,
1128                                extension: None,
1129                                value: Some(value),
1130                            },
1131                        );
1132                    }
1133                }
1134
1135                // Fall back to normal string deserialization
1136                V::deserialize(de::value::StringDeserializer::new(v.clone())).map(|value| Element {
1137                    // Clone v for error message
1138                    id: None,
1139                    extension: None,
1140                    value: Some(value),
1141                })
1142            }
1143            fn visit_borrowed_str<Er>(self, v: &'de str) -> Result<Self::Value, Er>
1144            where
1145                Er: de::Error,
1146            {
1147                use std::any::TypeId;
1148
1149                // Try to handle numeric strings for integer types
1150                if TypeId::of::<V>() == TypeId::of::<i64>() {
1151                    if let Ok(int_val) = v.parse::<i64>() {
1152                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
1153                            |value| Element {
1154                                id: None,
1155                                extension: None,
1156                                value: Some(value),
1157                            },
1158                        );
1159                    }
1160                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
1161                    if let Ok(int_val) = v.parse::<i32>() {
1162                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
1163                            |value| Element {
1164                                id: None,
1165                                extension: None,
1166                                value: Some(value),
1167                            },
1168                        );
1169                    }
1170                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
1171                    if let Ok(int_val) = v.parse::<u64>() {
1172                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
1173                            |value| Element {
1174                                id: None,
1175                                extension: None,
1176                                value: Some(value),
1177                            },
1178                        );
1179                    }
1180                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
1181                    if let Ok(int_val) = v.parse::<u32>() {
1182                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
1183                            |value| Element {
1184                                id: None,
1185                                extension: None,
1186                                value: Some(value),
1187                            },
1188                        );
1189                    }
1190                }
1191
1192                // Fall back to normal string deserialization
1193                V::deserialize(de::value::BorrowedStrDeserializer::new(v)).map(|value| Element {
1194                    id: None,
1195                    extension: None,
1196                    value: Some(value),
1197                })
1198            }
1199            fn visit_bytes<Er>(self, v: &[u8]) -> Result<Self::Value, Er>
1200            where
1201                Er: de::Error,
1202            {
1203                V::deserialize(de::value::BytesDeserializer::new(v)).map(|value| Element {
1204                    id: None,
1205                    extension: None,
1206                    value: Some(value),
1207                })
1208            }
1209            fn visit_byte_buf<Er>(self, v: Vec<u8>) -> Result<Self::Value, Er>
1210            where
1211                Er: de::Error,
1212            {
1213                // Use BytesDeserializer with a slice reference &v
1214                V::deserialize(de::value::BytesDeserializer::new(&v)).map(|value| Element {
1215                    id: None,
1216                    extension: None,
1217                    value: Some(value),
1218                })
1219            }
1220
1221            // Handle null
1222            fn visit_none<Er>(self) -> Result<Self::Value, Er>
1223            where
1224                Er: de::Error,
1225            {
1226                Ok(Element {
1227                    id: None,
1228                    extension: None,
1229                    value: None,
1230                })
1231            }
1232            fn visit_unit<Er>(self) -> Result<Self::Value, Er>
1233            where
1234                Er: de::Error,
1235            {
1236                Ok(Element {
1237                    id: None,
1238                    extension: None,
1239                    value: None,
1240                })
1241            }
1242
1243            // Handle Option<T> by visiting Some
1244            fn visit_some<De>(self, deserializer: De) -> Result<Self::Value, De::Error>
1245            where
1246                De: Deserializer<'de>,
1247            {
1248                // Re-dispatch to deserialize_any to handle the inner type correctly
1249                deserializer.deserialize_any(self)
1250            }
1251
1252            // Handle object
1253            fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
1254            where
1255                A: MapAccess<'de>,
1256            {
1257                // Deserialize the map using ElementObjectVisitor
1258                // Need to create a deserializer from the map access
1259                let map_deserializer = de::value::MapAccessDeserializer::new(map);
1260                map_deserializer.deserialize_map(ElementObjectVisitor(PhantomData))
1261            }
1262
1263            // We don't expect sequences for a single Element
1264            fn visit_seq<A>(self, _seq: A) -> Result<Self::Value, A::Error>
1265            where
1266                A: de::SeqAccess<'de>,
1267            {
1268                Err(de::Error::invalid_type(de::Unexpected::Seq, &self))
1269            }
1270        }
1271
1272        // Start deserialization using the visitor
1273        deserializer.deserialize_any(AnyValueVisitor(PhantomData))
1274    }
1275}
1276
1277// Custom Serialize for Element<V, E>
1278// Remove PartialEq/Eq bounds for V and E as they are not needed for serialization itself
1279impl<V, E> Serialize for Element<V, E>
1280where
1281    V: Serialize, // Removed PartialEq + Eq
1282    E: Serialize, // Removed PartialEq
1283{
1284    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1285    where
1286        S: Serializer,
1287    {
1288        // If id and extension are None, serialize value directly (or null)
1289        if self.id.is_none() && self.extension.is_none() {
1290            match &self.value {
1291                Some(val) => val.serialize(serializer),
1292                None => serializer.serialize_none(),
1293            }
1294        } else {
1295            // Otherwise, serialize as an object containing id, extension, value if present
1296            let mut len = 0;
1297            if self.id.is_some() {
1298                len += 1;
1299            }
1300            if self.extension.is_some() {
1301                len += 1;
1302            }
1303            if self.value.is_some() {
1304                len += 1;
1305            }
1306
1307            let mut state = serializer.serialize_struct("Element", len)?;
1308            if let Some(id) = &self.id {
1309                state.serialize_field("id", id)?;
1310            }
1311            if let Some(extension) = &self.extension {
1312                state.serialize_field("extension", extension)?;
1313            }
1314            // Restore value serialization for direct Element serialization
1315            if let Some(value) = &self.value {
1316                state.serialize_field("value", value)?;
1317            }
1318            state.end()
1319        }
1320    }
1321}
1322
1323/// Specialized element container for FHIR decimal values with precision preservation.
1324///
1325/// This type combines the generic `Element` pattern with `PreciseDecimal` to provide
1326/// a complete solution for FHIR decimal elements that require both extension support
1327/// and precision preservation during serialization round-trips.
1328///
1329/// # Type Parameters
1330///
1331/// * `E` - The extension type (typically the generated `Extension` struct)
1332///
1333/// # FHIR Decimal Requirements
1334///
1335/// FHIR decimal elements must:
1336/// - Preserve original string precision (e.g., "12.30" vs "12.3")
1337/// - Support mathematical operations using `Decimal` arithmetic
1338/// - Handle extension metadata through `id` and `extension` fields
1339/// - Serialize back to the exact original format when possible
1340///
1341/// # Examples
1342///
1343/// ```rust
1344/// use helios_fhir::{DecimalElement, PreciseDecimal, r4::Extension};
1345/// use rust_decimal::Decimal;
1346///
1347/// // Create from a Decimal value
1348/// let decimal_elem = DecimalElement::<Extension>::new(Decimal::new(1234, 2)); // 12.34
1349///
1350/// // Create with extensions
1351/// let extended_decimal: DecimalElement<Extension> = DecimalElement {
1352///     value: Some(PreciseDecimal::from_parts(
1353///         Some(Decimal::new(12300, 3)),
1354///         "12.300".to_string()
1355///     )),
1356///     id: Some("precision-example".to_string()),
1357///     extension: Some(vec![/* extensions */]),
1358/// };
1359///
1360/// // Access the mathematical value
1361/// if let Some(precise) = &extended_decimal.value {
1362///     if let Some(decimal_val) = precise.value() {
1363///         println!("Mathematical value: {}", decimal_val);
1364///     }
1365///     println!("Original format: {}", precise.original_string());
1366/// }
1367/// ```
1368///
1369/// # Serialization Behavior
1370///
1371/// - **Value only**: Serializes as a JSON number preserving original precision
1372/// - **With extensions**: Serializes as an object with `value`, `id`, and `extension` fields
1373/// - **No value**: Serializes as an object with just the extension fields, or `null` if empty
1374///
1375/// # Integration with FHIRPath
1376///
1377/// When used with FHIRPath evaluation, `DecimalElement` returns:
1378/// - The `Decimal` value for mathematical operations
1379/// - An object representation when extension metadata is accessed
1380/// - Empty collection when the element has no value or extensions
1381#[derive(Debug, PartialEq, Eq, Clone, Default)]
1382pub struct DecimalElement<E> {
1383    /// Optional element identifier for referencing within the resource
1384    pub id: Option<String>,
1385    /// Optional extensions providing additional metadata
1386    pub extension: Option<Vec<E>>,
1387    /// The decimal value with precision preservation
1388    pub value: Option<PreciseDecimal>,
1389}
1390
1391impl<E> DecimalElement<E> {
1392    /// Creates a new `DecimalElement` with the specified decimal value.
1393    ///
1394    /// This constructor creates a simple decimal element with no extensions or ID,
1395    /// containing only the decimal value. The original string representation is
1396    /// automatically derived from the `Decimal` value's `Display` implementation.
1397    ///
1398    /// # Arguments
1399    ///
1400    /// * `value` - The `Decimal` value to store
1401    ///
1402    /// # Returns
1403    ///
1404    /// A new `DecimalElement` with the value set and `id`/`extension` as `None`.
1405    ///
1406    /// # Examples
1407    ///
1408    /// ```rust
1409    /// use helios_fhir::{DecimalElement, r4::Extension};
1410    /// use rust_decimal::Decimal;
1411    ///
1412    /// // Create a simple decimal element
1413    /// let element = DecimalElement::<Extension>::new(Decimal::new(12345, 3)); // 12.345
1414    ///
1415    /// // Verify the structure
1416    /// assert!(element.id.is_none());
1417    /// assert!(element.extension.is_none());
1418    /// assert!(element.value.is_some());
1419    ///
1420    /// // Access the decimal value
1421    /// if let Some(precise_decimal) = &element.value {
1422    ///     assert_eq!(precise_decimal.value(), Some(Decimal::new(12345, 3)));
1423    ///     assert_eq!(precise_decimal.original_string(), "12.345");
1424    /// }
1425    /// ```
1426    ///
1427    /// # Usage in FHIR Resources
1428    ///
1429    /// This method is typically used when creating FHIR elements programmatically:
1430    ///
1431    /// ```rust
1432    /// use helios_fhir::{DecimalElement, r4::{Extension, Observation}};
1433    /// use rust_decimal::Decimal;
1434    ///
1435    /// let temperature = DecimalElement::<Extension>::new(Decimal::new(3672, 2)); // 36.72
1436    ///
1437    /// // Would be used in an Observation like:
1438    /// // observation.value_quantity.value = Some(temperature);
1439    /// ```
1440    pub fn new(value: Decimal) -> Self {
1441        // Convert the Decimal to PreciseDecimal, which automatically handles
1442        // storing the original string representation via the From trait
1443        let precise_value = PreciseDecimal::from(value);
1444        Self {
1445            id: None,
1446            extension: None,
1447            value: Some(precise_value),
1448        }
1449    }
1450}
1451
1452// Custom Deserialize for DecimalElement<E> using intermediate Value
1453impl<'de, E> Deserialize<'de> for DecimalElement<E>
1454where
1455    E: Deserialize<'de> + Default,
1456{
1457    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1458    where
1459        D: Deserializer<'de>,
1460    {
1461        // Deserialize into an intermediate serde_json::Value first
1462        let json_value = serde_json::Value::deserialize(deserializer)?;
1463
1464        match json_value {
1465            // Handle primitive JSON Number
1466            serde_json::Value::Number(n) => {
1467                // Directly parse the number string to create PreciseDecimal
1468                let s = n.to_string(); // Note: n.to_string() might normalize exponent case (e.g., 'E' -> 'e')
1469                // Replace 'E' with 'e' for parsing
1470                let s_for_parsing = s.replace('E', "e");
1471                // Use from_scientific if 'e' is present, otherwise parse
1472                let parsed_value = if s_for_parsing.contains('e') {
1473                    Decimal::from_scientific(&s_for_parsing).ok()
1474                } else {
1475                    s_for_parsing.parse::<Decimal>().ok()
1476                };
1477                // Store the ORIGINAL string `s` (as returned by n.to_string()).
1478                let pd = PreciseDecimal::from_parts(parsed_value, s);
1479                Ok(DecimalElement {
1480                    id: None,
1481                    extension: None,
1482                    value: Some(pd),
1483                })
1484            }
1485            // Handle primitive JSON String
1486            serde_json::Value::String(s) => {
1487                // Directly parse the string to create PreciseDecimal
1488                // Replace 'E' with 'e' for parsing
1489                let s_for_parsing = s.replace('E', "e");
1490                // Use from_scientific if 'e' is present, otherwise parse
1491                let parsed_value = if s_for_parsing.contains('e') {
1492                    Decimal::from_scientific(&s_for_parsing).ok()
1493                } else {
1494                    s_for_parsing.parse::<Decimal>().ok()
1495                };
1496                // Store the ORIGINAL string `s`.
1497                let pd = PreciseDecimal::from_parts(parsed_value, s); // s is owned, no clone needed
1498                Ok(DecimalElement {
1499                    id: None,
1500                    extension: None,
1501                    value: Some(pd),
1502                })
1503            }
1504            // Handle JSON object: deserialize fields individually
1505            serde_json::Value::Object(map) => {
1506                let mut id: Option<String> = None;
1507                let mut extension: Option<Vec<E>> = None;
1508                let mut value: Option<PreciseDecimal> = None;
1509
1510                for (k, v) in map {
1511                    match k.as_str() {
1512                        "id" => {
1513                            if id.is_some() {
1514                                return Err(de::Error::duplicate_field("id"));
1515                            }
1516                            // Deserialize id directly from its Value
1517                            id = Deserialize::deserialize(v).map_err(de::Error::custom)?;
1518                        }
1519                        "extension" => {
1520                            if extension.is_some() {
1521                                return Err(de::Error::duplicate_field("extension"));
1522                            }
1523                            // Deserialize extension directly from its Value
1524                            extension = Deserialize::deserialize(v).map_err(de::Error::custom)?;
1525                        }
1526                        "value" => {
1527                            if value.is_some() {
1528                                return Err(de::Error::duplicate_field("value"));
1529                            }
1530                            // Deserialize value using PreciseDecimal::deserialize from its Value
1531                            // Handle null explicitly within the value field
1532                            if v.is_null() {
1533                                value = None;
1534                            } else {
1535                                value = Some(
1536                                    PreciseDecimal::deserialize(v).map_err(de::Error::custom)?,
1537                                );
1538                            }
1539                        }
1540                        // Ignore any unknown fields encountered
1541                        _ => {} // Simply ignore unknown fields
1542                    }
1543                }
1544                Ok(DecimalElement {
1545                    id,
1546                    extension,
1547                    value,
1548                })
1549            }
1550            // Handle JSON Null for the whole element
1551            serde_json::Value::Null => Ok(DecimalElement::default()), // Default has value: None
1552            // Handle other unexpected types
1553            other => Err(de::Error::invalid_type(
1554                match other {
1555                    serde_json::Value::Bool(b) => de::Unexpected::Bool(b),
1556                    serde_json::Value::Array(_) => de::Unexpected::Seq,
1557                    _ => de::Unexpected::Other("unexpected JSON type for DecimalElement"),
1558                },
1559                &"a decimal number, string, object, or null",
1560            )),
1561        }
1562    }
1563}
1564
1565// Reinstate custom Serialize implementation for DecimalElement
1566// Remove PartialEq bound for E
1567impl<E> Serialize for DecimalElement<E>
1568where
1569    E: Serialize, // Removed PartialEq bound for E
1570{
1571    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1572    where
1573        S: Serializer,
1574    {
1575        // If we only have a value and no other fields, serialize just the value
1576        if self.id.is_none() && self.extension.is_none() {
1577            if let Some(value) = &self.value {
1578                // Serialize the PreciseDecimal directly, invoking its custom Serialize impl
1579                return value.serialize(serializer);
1580            } else {
1581                // If value is also None, serialize as null
1582                // based on updated test_serialize_decimal_with_no_fields
1583                return serializer.serialize_none();
1584            }
1585        }
1586
1587        // Otherwise, serialize as a struct with all present fields
1588        // Calculate the number of fields that are NOT None
1589        let mut len = 0;
1590        if self.id.is_some() {
1591            len += 1;
1592        }
1593        if self.extension.is_some() {
1594            len += 1;
1595        }
1596        if self.value.is_some() {
1597            len += 1;
1598        }
1599
1600        // Start serializing a struct with the calculated length
1601        let mut state = serializer.serialize_struct("DecimalElement", len)?;
1602
1603        // Serialize 'id' field if it's Some
1604        if let Some(id) = &self.id {
1605            state.serialize_field("id", id)?;
1606        }
1607
1608        // Serialize 'extension' field if it's Some
1609        if let Some(extension) = &self.extension {
1610            state.serialize_field("extension", extension)?;
1611        }
1612
1613        // Serialize 'value' field if it's Some
1614        if let Some(value) = &self.value {
1615            // Serialize the PreciseDecimal directly, invoking its custom Serialize impl
1616            state.serialize_field("value", value)?;
1617        }
1618
1619        // End the struct serialization
1620        state.end()
1621    }
1622}
1623
1624// For Element<V, E> - Returns Object with id, extension, value if present
1625impl<V, E> IntoEvaluationResult for Element<V, E>
1626where
1627    V: IntoEvaluationResult + Clone + 'static,
1628    E: IntoEvaluationResult + Clone,
1629{
1630    fn to_evaluation_result(&self) -> EvaluationResult {
1631        use std::any::TypeId;
1632
1633        // Prioritize returning the primitive value if it exists
1634        if let Some(v) = &self.value {
1635            let result = v.to_evaluation_result();
1636            // For primitive values, we need to preserve FHIR type information
1637            return match result {
1638                EvaluationResult::Boolean(b, _) => {
1639                    // Return FHIR boolean
1640                    EvaluationResult::fhir_boolean(b)
1641                }
1642                EvaluationResult::Integer(i, _) => {
1643                    // Return FHIR integer
1644                    EvaluationResult::fhir_integer(i)
1645                }
1646                #[cfg(not(any(feature = "R4", feature = "R4B")))]
1647                EvaluationResult::Integer64(i, _) => {
1648                    // Return FHIR integer64 (R5 and above)
1649                    EvaluationResult::fhir_integer64(i)
1650                }
1651                EvaluationResult::String(s, _) => {
1652                    // Determine the FHIR type name based on V's type
1653                    let fhir_type_name = if TypeId::of::<V>() == TypeId::of::<String>() {
1654                        // For strings, we need more context to determine the exact FHIR type
1655                        // Default to "string" but this could be date, dateTime, etc.
1656                        "string"
1657                    } else {
1658                        // Default fallback
1659                        "string"
1660                    };
1661                    EvaluationResult::fhir_string(s, fhir_type_name)
1662                }
1663                _ => result, // For other types, return as-is
1664            };
1665        } else if self.id.is_some() || self.extension.is_some() {
1666            // If value is None, but id or extension exist, return an Object with those
1667            let mut map = std::collections::HashMap::new();
1668            if let Some(id) = &self.id {
1669                map.insert("id".to_string(), EvaluationResult::string(id.clone()));
1670            }
1671            if let Some(ext) = &self.extension {
1672                let ext_collection: Vec<EvaluationResult> =
1673                    ext.iter().map(|e| e.to_evaluation_result()).collect();
1674                if !ext_collection.is_empty() {
1675                    map.insert(
1676                        "extension".to_string(),
1677                        EvaluationResult::collection(ext_collection),
1678                    );
1679                }
1680            }
1681            // Only return Object if map is not empty (i.e., id or extension was actually present)
1682            if !map.is_empty() {
1683                return EvaluationResult::typed_object(map, "FHIR", "Element");
1684            }
1685        }
1686
1687        // If value, id, and extension are all None, return Empty
1688        EvaluationResult::Empty
1689    }
1690}
1691
1692// For DecimalElement<E> - Returns Decimal value if present, otherwise handles id/extension
1693impl<E> IntoEvaluationResult for DecimalElement<E>
1694where
1695    E: IntoEvaluationResult + Clone,
1696{
1697    fn to_evaluation_result(&self) -> EvaluationResult {
1698        // Prioritize returning the primitive decimal value if it exists
1699        if let Some(precise_decimal) = &self.value {
1700            if let Some(decimal_val) = precise_decimal.value() {
1701                // Return FHIR decimal
1702                return EvaluationResult::fhir_decimal(decimal_val);
1703            }
1704            // If PreciseDecimal holds None for value, fall through to check id/extension
1705        }
1706
1707        // If value is None, but id or extension exist, return an Object with those
1708        if self.id.is_some() || self.extension.is_some() {
1709            let mut map = std::collections::HashMap::new();
1710            if let Some(id) = &self.id {
1711                map.insert("id".to_string(), EvaluationResult::string(id.clone()));
1712            }
1713            if let Some(ext) = &self.extension {
1714                let ext_collection: Vec<EvaluationResult> =
1715                    ext.iter().map(|e| e.to_evaluation_result()).collect();
1716                if !ext_collection.is_empty() {
1717                    map.insert(
1718                        "extension".to_string(),
1719                        EvaluationResult::collection(ext_collection),
1720                    );
1721                }
1722            }
1723            // Only return Object if map is not empty
1724            if !map.is_empty() {
1725                return EvaluationResult::typed_object(map, "FHIR", "decimal");
1726            }
1727        }
1728
1729        // If value, id, and extension are all None, return Empty
1730        EvaluationResult::Empty
1731    }
1732}
1733
1734// Implement the trait for the top-level enum
1735impl IntoEvaluationResult for FhirResource {
1736    fn to_evaluation_result(&self) -> EvaluationResult {
1737        match self {
1738            #[cfg(feature = "R4")]
1739            FhirResource::R4(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r4::Resource>
1740            #[cfg(feature = "R4B")]
1741            FhirResource::R4B(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r4b::Resource>
1742            #[cfg(feature = "R5")]
1743            FhirResource::R5(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r5::Resource>
1744            #[cfg(feature = "R6")]
1745            FhirResource::R6(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r6::Resource>
1746                                                                // Note: If no features are enabled, this match might be empty or non-exhaustive.
1747                                                                // This is generally okay as the enum itself wouldn't be usable.
1748        }
1749    }
1750}
1751
1752#[cfg(test)]
1753mod tests {
1754    use super::*;
1755
1756    #[test]
1757    fn test_integer_string_deserialization() {
1758        // Test deserializing a string "2" into Element<i64, ()>
1759        type TestElement = Element<i64, ()>;
1760
1761        // Test case 1: String containing integer
1762        let json_str = r#""2""#;
1763        let result: Result<TestElement, _> = serde_json::from_str(json_str);
1764        assert!(
1765            result.is_ok(),
1766            "Failed to deserialize string '2' as i64: {:?}",
1767            result.err()
1768        );
1769
1770        let element = result.unwrap();
1771        assert_eq!(element.value, Some(2i64));
1772        assert_eq!(element.id, None);
1773        assert_eq!(element.extension, None);
1774
1775        // Test case 2: Number
1776        let json_num = r#"2"#;
1777        let result: Result<TestElement, _> = serde_json::from_str(json_num);
1778        assert!(
1779            result.is_ok(),
1780            "Failed to deserialize number 2 as i64: {:?}",
1781            result.err()
1782        );
1783
1784        let element = result.unwrap();
1785        assert_eq!(element.value, Some(2i64));
1786    }
1787
1788    #[test]
1789    fn test_i32_string_deserialization() {
1790        type TestElement = Element<i32, ()>;
1791
1792        let json_str = r#""123""#;
1793        let result: Result<TestElement, _> = serde_json::from_str(json_str);
1794        assert!(result.is_ok());
1795
1796        let element = result.unwrap();
1797        assert_eq!(element.value, Some(123i32));
1798    }
1799
1800    #[test]
1801    fn test_invalid_string_fallback() {
1802        type TestElement = Element<i64, ()>;
1803
1804        // Non-numeric string should fail for integer type
1805        let json_str = r#""not_a_number""#;
1806        let result: Result<TestElement, _> = serde_json::from_str(json_str);
1807        assert!(
1808            result.is_err(),
1809            "Should fail to deserialize non-numeric string as i64"
1810        );
1811    }
1812}