Skip to main content

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 chrono::{DateTime as ChronoDateTime, NaiveDate, NaiveTime, Utc};
45use helios_fhirpath_support::{EvaluationResult, IntoEvaluationResult, TypeInfoResult};
46use rust_decimal::Decimal;
47use serde::{
48    Deserialize, Serialize,
49    de::{self, Deserializer, MapAccess, Visitor},
50    ser::{SerializeStruct, Serializer},
51};
52use std::cmp::Ordering;
53use std::fmt;
54use std::marker::PhantomData;
55use std::sync::Arc;
56
57/// Custom deserializer that is more forgiving of null values in JSON.
58///
59/// This creates a custom `Option<T>` deserializer that will return None for null values
60/// but also for any deserialization errors. This makes it possible to skip over
61/// malformed or unexpected values in FHIR JSON.
62pub fn deserialize_forgiving_option<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
63where
64    T: Deserialize<'de>,
65    D: Deserializer<'de>,
66{
67    // Use the intermediate Value approach to check for null first
68    let json_value = serde_json::Value::deserialize(deserializer)?;
69
70    match json_value {
71        serde_json::Value::Null => Ok(None),
72        _ => {
73            // Try to deserialize the value, but return None if it fails
74            match T::deserialize(json_value) {
75                Ok(value) => Ok(Some(value)),
76                Err(_) => Ok(None), // Ignore errors and return None
77            }
78        }
79    }
80}
81
82/// High-precision decimal type that preserves original string representation.
83///
84/// FHIR requires that decimal values maintain their original precision and format
85/// when serialized back to JSON. This type stores both the parsed `Decimal` value
86/// for mathematical operations and the original string for serialization.
87///
88/// # FHIR Precision Requirements
89///
90/// FHIR decimal values must:
91/// - Preserve trailing zeros (e.g., "12.340" vs "12.34")
92/// - Maintain original precision during round-trip serialization
93/// - Support high-precision arithmetic without floating-point errors
94/// - Handle edge cases like very large or very small numbers
95///
96/// # Examples
97///
98/// ```rust
99/// use helios_fhir::PreciseDecimal;
100/// use rust_decimal::Decimal;
101///
102/// // Create from Decimal (derives string representation)
103/// let precise = PreciseDecimal::from(Decimal::new(12340, 3)); // 12.340
104/// assert_eq!(precise.original_string(), "12.340");
105///
106/// // Create with specific string format
107/// let precise = PreciseDecimal::from_parts(
108///     Some(Decimal::new(1000, 2)),
109///     "10.00".to_string()
110/// );
111/// assert_eq!(precise.original_string(), "10.00");
112/// ```
113#[derive(Debug, Clone)]
114pub struct PreciseDecimal {
115    /// The parsed decimal value, `None` if parsing failed (e.g., out of range)
116    value: Option<Decimal>,
117    /// The original string representation preserving format and precision
118    original_string: Arc<str>,
119}
120
121/// Implements equality comparison based on the parsed decimal value.
122///
123/// Two `PreciseDecimal` values are equal if their parsed `Decimal` values are equal,
124/// regardless of their original string representations. This enables mathematical
125/// equality while preserving string format for serialization.
126///
127/// # Examples
128///
129/// ```rust
130/// use helios_fhir::PreciseDecimal;
131/// use rust_decimal::Decimal;
132///
133/// let a = PreciseDecimal::from_parts(Some(Decimal::new(100, 1)), "10.0".to_string());
134/// let b = PreciseDecimal::from_parts(Some(Decimal::new(1000, 2)), "10.00".to_string());
135/// assert_eq!(a, b); // Same decimal value (10.0 == 10.00)
136/// ```
137impl PartialEq for PreciseDecimal {
138    fn eq(&self, other: &Self) -> bool {
139        // Compare parsed decimal values for mathematical equality
140        self.value == other.value
141    }
142}
143
144/// Marker trait implementation indicating total equality for `PreciseDecimal`.
145impl Eq for PreciseDecimal {}
146
147/// Implements partial ordering based on the parsed decimal value.
148///
149/// Ordering is based on the mathematical value of the decimal, not the string
150/// representation. `None` values (unparseable decimals) are considered less than
151/// any valid decimal value.
152impl PartialOrd for PreciseDecimal {
153    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
154        Some(self.cmp(other))
155    }
156}
157
158/// Implements total ordering for `PreciseDecimal`.
159///
160/// Provides a consistent ordering for sorting operations. The ordering is based
161/// on the mathematical value: `None` < `Some(smaller_decimal)` < `Some(larger_decimal)`.
162impl Ord for PreciseDecimal {
163    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
164        self.value.cmp(&other.value)
165    }
166}
167
168// === PreciseDecimal Methods ===
169
170impl PreciseDecimal {
171    /// Creates a new `PreciseDecimal` from its constituent parts.
172    ///
173    /// This constructor allows explicit control over both the parsed value and the
174    /// original string representation. Use this when you need to preserve a specific
175    /// string format or when parsing has already been attempted.
176    ///
177    /// # Arguments
178    ///
179    /// * `value` - The parsed decimal value, or `None` if parsing failed
180    /// * `original_string` - The original string representation to preserve
181    ///
182    /// # Examples
183    ///
184    /// ```rust
185    /// use helios_fhir::PreciseDecimal;
186    /// use rust_decimal::Decimal;
187    ///
188    /// // Create with successful parsing
189    /// let precise = PreciseDecimal::from_parts(
190    ///     Some(Decimal::new(12340, 3)),
191    ///     "12.340".to_string()
192    /// );
193    ///
194    /// // Create with failed parsing (preserves original string)
195    /// let invalid = PreciseDecimal::from_parts(
196    ///     None,
197    ///     "invalid_decimal".to_string()
198    /// );
199    /// ```
200    pub fn from_parts(value: Option<Decimal>, original_string: String) -> Self {
201        Self {
202            value,
203            original_string: Arc::from(original_string.as_str()),
204        }
205    }
206
207    /// Helper method to parse a decimal string with support for scientific notation.
208    ///
209    /// This method handles the complexity of parsing decimal strings that may be in
210    /// scientific notation (with 'E' or 'e' exponents) or regular decimal format.
211    /// It normalizes 'E' to 'e' for consistent parsing while preserving the original
212    /// string representation for serialization.
213    ///
214    /// # Arguments
215    ///
216    /// * `s` - The string to parse as a decimal
217    ///
218    /// # Returns
219    ///
220    /// `Some(Decimal)` if parsing succeeds, `None` if the string is not a valid decimal.
221    ///
222    /// # Examples
223    ///
224    /// ```ignore
225    /// use helios_fhir::PreciseDecimal;
226    /// use rust_decimal::Decimal;
227    ///
228    /// // Regular decimal format
229    /// assert!(PreciseDecimal::parse_decimal_string("123.45").is_some());
230    ///
231    /// // Scientific notation with 'e'
232    /// assert!(PreciseDecimal::parse_decimal_string("1.23e2").is_some());
233    ///
234    /// // Scientific notation with 'E' (normalized to 'e')
235    /// assert!(PreciseDecimal::parse_decimal_string("1.23E2").is_some());
236    ///
237    /// // Invalid format
238    /// assert!(PreciseDecimal::parse_decimal_string("invalid").is_none());
239    /// ```
240    fn parse_decimal_string(s: &str) -> Option<Decimal> {
241        // Normalize 'E' to 'e' for consistent parsing
242        let normalized = s.replace('E', "e");
243
244        if normalized.contains('e') {
245            // Use scientific notation parsing
246            Decimal::from_scientific(&normalized).ok()
247        } else {
248            // Use regular decimal parsing
249            normalized.parse::<Decimal>().ok()
250        }
251    }
252
253    /// Returns the parsed decimal value if parsing was successful.
254    ///
255    /// This method provides access to the mathematical value for arithmetic
256    /// operations and comparisons. Returns `None` if the original string
257    /// could not be parsed as a valid decimal.
258    ///
259    /// # Examples
260    ///
261    /// ```rust
262    /// use helios_fhir::PreciseDecimal;
263    /// use rust_decimal::Decimal;
264    ///
265    /// let precise = PreciseDecimal::from(Decimal::new(1234, 2)); // 12.34
266    /// assert_eq!(precise.value(), Some(Decimal::new(1234, 2)));
267    ///
268    /// let invalid = PreciseDecimal::from_parts(None, "invalid".to_string());
269    /// assert_eq!(invalid.value(), None);
270    /// ```
271    pub fn value(&self) -> Option<Decimal> {
272        self.value
273    }
274
275    /// Returns the original string representation.
276    ///
277    /// This method provides access to the exact string format that was used
278    /// to create this `PreciseDecimal`. This string is used during serialization
279    /// to maintain FHIR's precision requirements.
280    ///
281    /// # Examples
282    ///
283    /// ```rust
284    /// use helios_fhir::PreciseDecimal;
285    /// use rust_decimal::Decimal;
286    ///
287    /// let precise = PreciseDecimal::from_parts(
288    ///     Some(Decimal::new(100, 2)),
289    ///     "1.00".to_string()
290    /// );
291    /// assert_eq!(precise.original_string(), "1.00");
292    /// ```
293    pub fn original_string(&self) -> &str {
294        &self.original_string
295    }
296}
297
298/// Converts a `Decimal` to `PreciseDecimal` with derived string representation.
299///
300/// This implementation allows easy conversion from `rust_decimal::Decimal` values
301/// by automatically generating the string representation using the decimal's
302/// `Display` implementation.
303///
304/// # Examples
305///
306/// ```rust
307/// use helios_fhir::PreciseDecimal;
308/// use rust_decimal::Decimal;
309///
310/// let decimal = Decimal::new(12345, 3); // 12.345
311/// let precise: PreciseDecimal = decimal.into();
312/// assert_eq!(precise.value(), Some(decimal));
313/// assert_eq!(precise.original_string(), "12.345");
314/// ```
315impl From<Decimal> for PreciseDecimal {
316    fn from(value: Decimal) -> Self {
317        // Generate string representation from the decimal value
318        let original_string = Arc::from(value.to_string());
319        Self {
320            value: Some(value),
321            original_string,
322        }
323    }
324}
325
326/// Implements serialization for `PreciseDecimal` preserving original format.
327///
328/// This implementation ensures that the exact original string representation
329/// is preserved during JSON serialization, maintaining FHIR's precision
330/// requirements including trailing zeros and specific formatting.
331///
332/// # FHIR Compliance
333///
334/// FHIR requires that decimal values maintain their original precision when
335/// round-tripped through JSON. This implementation uses `serde_json::RawValue`
336/// to serialize the original string directly as a JSON number.
337///
338/// # Examples
339///
340/// ```rust
341/// use helios_fhir::PreciseDecimal;
342/// use rust_decimal::Decimal;
343/// use serde_json;
344///
345/// let precise = PreciseDecimal::from_parts(
346///     Some(Decimal::new(1230, 2)),
347///     "12.30".to_string()
348/// );
349///
350/// let json = serde_json::to_string(&precise).unwrap();
351/// assert_eq!(json, "12.30"); // Preserves trailing zero
352/// ```
353impl Serialize for PreciseDecimal {
354    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
355    where
356        S: Serializer,
357    {
358        // Use RawValue to preserve exact string format in JSON
359        match serde_json::value::RawValue::from_string(self.original_string.to_string()) {
360            Ok(raw_value) => raw_value.serialize(serializer),
361            Err(e) => Err(serde::ser::Error::custom(format!(
362                "Failed to serialize PreciseDecimal '{}': {}",
363                self.original_string, e
364            ))),
365        }
366    }
367}
368
369/// Implements deserialization for `PreciseDecimal` preserving original format.
370///
371/// This implementation deserializes JSON numbers and strings into `PreciseDecimal`
372/// while preserving the exact original string representation. It handles various
373/// JSON formats including scientific notation and nested object structures.
374///
375/// # Supported Formats
376///
377/// - Direct numbers: `12.340`
378/// - String numbers: `"12.340"`
379/// - Scientific notation: `1.234e2` or `1.234E2`
380/// - Nested objects: `{"value": 12.340}` (for macro-generated structures)
381///
382/// # Examples
383///
384/// ```rust
385/// use helios_fhir::PreciseDecimal;
386/// use serde_json;
387///
388/// // Deserialize from JSON number (trailing zeros are normalized)
389/// let precise: PreciseDecimal = serde_json::from_str("12.340").unwrap();
390/// assert_eq!(precise.original_string(), "12.340"); // JSON number format
391///
392/// // Deserialize from JSON string (preserves exact format)
393/// let precise: PreciseDecimal = serde_json::from_str("\"12.340\"").unwrap();
394/// assert_eq!(precise.original_string(), "12.340"); // Preserves string format
395/// ```
396impl<'de> Deserialize<'de> for PreciseDecimal {
397    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
398    where
399        D: Deserializer<'de>,
400    {
401        // Use intermediate Value to capture exact string representation
402        let json_value = serde_json::Value::deserialize(deserializer)?;
403
404        match json_value {
405            serde_json::Value::Number(n) => {
406                // Extract string representation from JSON number
407                let original_string = n.to_string();
408                let parsed_value = Self::parse_decimal_string(&original_string);
409                Ok(PreciseDecimal::from_parts(parsed_value, original_string))
410            }
411            serde_json::Value::String(s) => {
412                // Use string value directly (preserves exact format)
413                let parsed_value = Self::parse_decimal_string(&s);
414                Ok(PreciseDecimal::from_parts(parsed_value, s))
415            }
416            // Handle nested object format (for macro-generated structures)
417            serde_json::Value::Object(map) => match map.get("value") {
418                Some(serde_json::Value::Number(n)) => {
419                    let original_string = n.to_string();
420                    let parsed_value = Self::parse_decimal_string(&original_string);
421                    Ok(PreciseDecimal::from_parts(parsed_value, original_string))
422                }
423                Some(serde_json::Value::String(s)) => {
424                    let original_string = s.clone();
425                    let parsed_value = Self::parse_decimal_string(&original_string);
426                    Ok(PreciseDecimal::from_parts(parsed_value, original_string))
427                }
428                Some(serde_json::Value::Null) => Err(de::Error::invalid_value(
429                    de::Unexpected::Unit,
430                    &"a number or string for decimal value",
431                )),
432                None => Err(de::Error::missing_field("value")),
433                _ => Err(de::Error::invalid_type(
434                    de::Unexpected::Map,
435                    &"a map with a 'value' field containing a number or string",
436                )),
437            },
438            // Handle remaining unexpected types
439            other => Err(de::Error::invalid_type(
440                match other {
441                    serde_json::Value::Null => de::Unexpected::Unit, // Or Unexpected::Option if mapping null to None
442                    serde_json::Value::Bool(b) => de::Unexpected::Bool(b),
443                    serde_json::Value::Array(_) => de::Unexpected::Seq,
444                    _ => de::Unexpected::Other("unexpected JSON type for PreciseDecimal"),
445                },
446                &"a number, string, or object with a 'value' field",
447            )),
448        }
449    }
450}
451
452// --- End PreciseDecimal ---
453
454/// Precision levels for FHIR Date values.
455///
456/// FHIR dates support partial precision, allowing year-only, year-month,
457/// or full date specifications. This enum tracks which components are present.
458#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
459pub enum DatePrecision {
460    /// Year only (YYYY)
461    Year,
462    /// Year and month (YYYY-MM)
463    YearMonth,
464    /// Full date (YYYY-MM-DD)
465    Full,
466}
467
468/// Precision levels for FHIR Time values.
469///
470/// FHIR times support partial precision from hour-only through
471/// sub-second precision. This enum tracks which components are present.
472#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
473pub enum TimePrecision {
474    /// Hour only (HH)
475    Hour,
476    /// Hour and minute (HH:MM)
477    HourMinute,
478    /// Hour, minute, and second (HH:MM:SS)
479    HourMinuteSecond,
480    /// Full time with sub-second precision (HH:MM:SS.sss)
481    Millisecond,
482}
483
484/// Precision levels for FHIR DateTime values.
485///
486/// FHIR datetimes support partial precision from year-only through
487/// sub-second precision with optional timezone information.
488#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
489pub enum DateTimePrecision {
490    /// Year only (YYYY)
491    Year,
492    /// Year and month (YYYY-MM)
493    YearMonth,
494    /// Date only (YYYY-MM-DD)
495    Date,
496    /// Date with hour (YYYY-MM-DDTHH)
497    DateHour,
498    /// Date with hour and minute (YYYY-MM-DDTHH:MM)
499    DateHourMinute,
500    /// Date with time to seconds (YYYY-MM-DDTHH:MM:SS)
501    DateHourMinuteSecond,
502    /// Full datetime with sub-second precision (YYYY-MM-DDTHH:MM:SS.sss)
503    Full,
504}
505
506impl Default for PrecisionDate {
507    fn default() -> Self {
508        // Default to epoch date 1970-01-01
509        Self::from_ymd(1970, 1, 1)
510    }
511}
512
513/// Precision-aware FHIR Date type.
514///
515/// This type preserves the original precision and string representation
516/// of FHIR date values while providing typed access to date components.
517///
518/// # FHIR Date Formats
519/// - `YYYY` - Year only
520/// - `YYYY-MM` - Year and month  
521/// - `YYYY-MM-DD` - Full date
522///
523/// # Examples
524/// ```rust
525/// use helios_fhir::{PrecisionDate, DatePrecision};
526///
527/// // Create a year-only date
528/// let year_date = PrecisionDate::from_year(2023);
529/// assert_eq!(year_date.precision(), DatePrecision::Year);
530/// assert_eq!(year_date.original_string(), "2023");
531///
532/// // Create a full date
533/// let full_date = PrecisionDate::from_ymd(2023, 3, 15);
534/// assert_eq!(full_date.precision(), DatePrecision::Full);
535/// assert_eq!(full_date.original_string(), "2023-03-15");
536/// ```
537#[derive(Debug, Clone, PartialEq, Eq)]
538pub struct PrecisionDate {
539    /// Year component (always present)
540    year: i32,
541    /// Month component (1-12, None for year-only precision)
542    month: Option<u32>,
543    /// Day component (1-31, None for year or year-month precision)
544    day: Option<u32>,
545    /// Precision level of this date
546    precision: DatePrecision,
547    /// Original string representation
548    original_string: Arc<str>,
549}
550
551impl PrecisionDate {
552    /// Creates a year-only precision date.
553    pub fn from_year(year: i32) -> Self {
554        Self {
555            year,
556            month: None,
557            day: None,
558            precision: DatePrecision::Year,
559            original_string: Arc::from(format!("{:04}", year)),
560        }
561    }
562
563    /// Creates a year-month precision date.
564    pub fn from_year_month(year: i32, month: u32) -> Self {
565        Self {
566            year,
567            month: Some(month),
568            day: None,
569            precision: DatePrecision::YearMonth,
570            original_string: Arc::from(format!("{:04}-{:02}", year, month)),
571        }
572    }
573
574    /// Creates a full precision date.
575    pub fn from_ymd(year: i32, month: u32, day: u32) -> Self {
576        Self {
577            year,
578            month: Some(month),
579            day: Some(day),
580            precision: DatePrecision::Full,
581            original_string: Arc::from(format!("{:04}-{:02}-{:02}", year, month, day)),
582        }
583    }
584
585    /// Parses a FHIR date string, preserving precision.
586    pub fn parse(s: &str) -> Option<Self> {
587        // Remove @ prefix if present
588        let s = s.strip_prefix('@').unwrap_or(s);
589
590        let parts: Vec<&str> = s.split('-').collect();
591        match parts.len() {
592            1 => {
593                // Year only
594                let year = parts[0].parse::<i32>().ok()?;
595                Some(Self {
596                    year,
597                    month: None,
598                    day: None,
599                    precision: DatePrecision::Year,
600                    original_string: Arc::from(s),
601                })
602            }
603            2 => {
604                // Year-month
605                let year = parts[0].parse::<i32>().ok()?;
606                let month = parts[1].parse::<u32>().ok()?;
607                if !(1..=12).contains(&month) {
608                    return None;
609                }
610                Some(Self {
611                    year,
612                    month: Some(month),
613                    day: None,
614                    precision: DatePrecision::YearMonth,
615                    original_string: Arc::from(s),
616                })
617            }
618            3 => {
619                // Full date
620                let year = parts[0].parse::<i32>().ok()?;
621                let month = parts[1].parse::<u32>().ok()?;
622                let day = parts[2].parse::<u32>().ok()?;
623                if !(1..=12).contains(&month) || !(1..=31).contains(&day) {
624                    return None;
625                }
626                Some(Self {
627                    year,
628                    month: Some(month),
629                    day: Some(day),
630                    precision: DatePrecision::Full,
631                    original_string: Arc::from(s),
632                })
633            }
634            _ => None,
635        }
636    }
637
638    /// Returns the precision level of this date.
639    pub fn precision(&self) -> DatePrecision {
640        self.precision
641    }
642
643    /// Returns the original string representation.
644    pub fn original_string(&self) -> &str {
645        &self.original_string
646    }
647
648    /// Returns the year component.
649    pub fn year(&self) -> i32 {
650        self.year
651    }
652
653    /// Returns the month component if present.
654    pub fn month(&self) -> Option<u32> {
655        self.month
656    }
657
658    /// Returns the day component if present.
659    pub fn day(&self) -> Option<u32> {
660        self.day
661    }
662
663    /// Converts to a NaiveDate, using defaults for missing components.
664    pub fn to_naive_date(&self) -> NaiveDate {
665        NaiveDate::from_ymd_opt(self.year, self.month.unwrap_or(1), self.day.unwrap_or(1))
666            .expect("Valid date components")
667    }
668
669    /// Compares two dates considering precision.
670    /// Returns None if comparison is indeterminate due to precision differences.
671    pub fn compare(&self, other: &Self) -> Option<Ordering> {
672        // Compare years first
673        match self.year.cmp(&other.year) {
674            Ordering::Equal => {
675                // Years are equal, check month precision
676                match (self.month, other.month) {
677                    (None, None) => Some(Ordering::Equal),
678                    (None, Some(_)) | (Some(_), None) => {
679                        // Different precisions - comparison may be indeterminate
680                        // For < and > we can still determine, but for = it's indeterminate
681                        None
682                    }
683                    (Some(m1), Some(m2)) => match m1.cmp(&m2) {
684                        Ordering::Equal => {
685                            // Months are equal, check day precision
686                            match (self.day, other.day) {
687                                (None, None) => Some(Ordering::Equal),
688                                (None, Some(_)) | (Some(_), None) => {
689                                    // Different precisions - indeterminate
690                                    None
691                                }
692                                (Some(d1), Some(d2)) => Some(d1.cmp(&d2)),
693                            }
694                        }
695                        other => Some(other),
696                    },
697                }
698            }
699            other => Some(other),
700        }
701    }
702}
703
704impl Default for PrecisionTime {
705    fn default() -> Self {
706        // Default to midnight 00:00:00
707        Self::from_hms(0, 0, 0)
708    }
709}
710
711/// Precision-aware FHIR Time type.
712///
713/// This type preserves the original precision and string representation
714/// of FHIR time values. Note that FHIR times do not support timezone information.
715///
716/// # FHIR Time Formats
717/// - `HH` - Hour only
718/// - `HH:MM` - Hour and minute
719/// - `HH:MM:SS` - Hour, minute, and second
720/// - `HH:MM:SS.sss` - Full time with milliseconds
721///
722/// # Examples
723/// ```rust
724/// use helios_fhir::{PrecisionTime, TimePrecision};
725///
726/// // Create an hour-only time
727/// let hour_time = PrecisionTime::from_hour(14);
728/// assert_eq!(hour_time.precision(), TimePrecision::Hour);
729/// assert_eq!(hour_time.original_string(), "14");
730///
731/// // Create a full precision time
732/// let full_time = PrecisionTime::from_hms_milli(14, 30, 45, 123);
733/// assert_eq!(full_time.precision(), TimePrecision::Millisecond);
734/// assert_eq!(full_time.original_string(), "14:30:45.123");
735/// ```
736#[derive(Debug, Clone, PartialEq, Eq)]
737pub struct PrecisionTime {
738    /// Hour component (0-23, always present)
739    hour: u32,
740    /// Minute component (0-59)
741    minute: Option<u32>,
742    /// Second component (0-59)
743    second: Option<u32>,
744    /// Millisecond component (0-999)
745    millisecond: Option<u32>,
746    /// Precision level of this time
747    precision: TimePrecision,
748    /// Original string representation
749    original_string: Arc<str>,
750}
751
752impl PrecisionTime {
753    /// Creates an hour-only precision time.
754    pub fn from_hour(hour: u32) -> Self {
755        Self {
756            hour,
757            minute: None,
758            second: None,
759            millisecond: None,
760            precision: TimePrecision::Hour,
761            original_string: Arc::from(format!("{:02}", hour)),
762        }
763    }
764
765    /// Creates an hour-minute precision time.
766    pub fn from_hm(hour: u32, minute: u32) -> Self {
767        Self {
768            hour,
769            minute: Some(minute),
770            second: None,
771            millisecond: None,
772            precision: TimePrecision::HourMinute,
773            original_string: Arc::from(format!("{:02}:{:02}", hour, minute)),
774        }
775    }
776
777    /// Creates an hour-minute-second precision time.
778    pub fn from_hms(hour: u32, minute: u32, second: u32) -> Self {
779        Self {
780            hour,
781            minute: Some(minute),
782            second: Some(second),
783            millisecond: None,
784            precision: TimePrecision::HourMinuteSecond,
785            original_string: Arc::from(format!("{:02}:{:02}:{:02}", hour, minute, second)),
786        }
787    }
788
789    /// Creates a full precision time with milliseconds.
790    pub fn from_hms_milli(hour: u32, minute: u32, second: u32, millisecond: u32) -> Self {
791        Self {
792            hour,
793            minute: Some(minute),
794            second: Some(second),
795            millisecond: Some(millisecond),
796            precision: TimePrecision::Millisecond,
797            original_string: Arc::from(format!(
798                "{:02}:{:02}:{:02}.{:03}",
799                hour, minute, second, millisecond
800            )),
801        }
802    }
803
804    /// Parses a FHIR time string, preserving precision.
805    pub fn parse(s: &str) -> Option<Self> {
806        // Remove @ and T prefixes if present
807        let s = s.strip_prefix('@').unwrap_or(s);
808        let s = s.strip_prefix('T').unwrap_or(s);
809
810        // Check for timezone (not allowed in FHIR time)
811        if s.contains('+') || s.contains('-') || s.ends_with('Z') {
812            return None;
813        }
814
815        let parts: Vec<&str> = s.split(':').collect();
816        match parts.len() {
817            1 => {
818                // Hour only
819                let hour = parts[0].parse::<u32>().ok()?;
820                if hour > 23 {
821                    return None;
822                }
823                Some(Self {
824                    hour,
825                    minute: None,
826                    second: None,
827                    millisecond: None,
828                    precision: TimePrecision::Hour,
829                    original_string: Arc::from(s),
830                })
831            }
832            2 => {
833                // Hour:minute
834                let hour = parts[0].parse::<u32>().ok()?;
835                let minute = parts[1].parse::<u32>().ok()?;
836                if hour > 23 || minute > 59 {
837                    return None;
838                }
839                Some(Self {
840                    hour,
841                    minute: Some(minute),
842                    second: None,
843                    millisecond: None,
844                    precision: TimePrecision::HourMinute,
845                    original_string: Arc::from(s),
846                })
847            }
848            3 => {
849                // Hour:minute:second[.millisecond]
850                let hour = parts[0].parse::<u32>().ok()?;
851                let minute = parts[1].parse::<u32>().ok()?;
852
853                // Check for milliseconds
854                let (second, millisecond, precision) = if parts[2].contains('.') {
855                    let sec_parts: Vec<&str> = parts[2].split('.').collect();
856                    if sec_parts.len() != 2 {
857                        return None;
858                    }
859                    let second = sec_parts[0].parse::<u32>().ok()?;
860                    // Parse milliseconds, padding or truncating as needed
861                    let ms_str = sec_parts[1];
862                    let ms = if ms_str.len() <= 3 {
863                        // Pad with zeros if needed
864                        let padded = format!("{:0<3}", ms_str);
865                        padded.parse::<u32>().ok()?
866                    } else {
867                        // Truncate to 3 digits
868                        ms_str[..3].parse::<u32>().ok()?
869                    };
870                    (second, Some(ms), TimePrecision::Millisecond)
871                } else {
872                    let second = parts[2].parse::<u32>().ok()?;
873                    (second, None, TimePrecision::HourMinuteSecond)
874                };
875
876                if hour > 23 || minute > 59 || second > 59 {
877                    return None;
878                }
879
880                Some(Self {
881                    hour,
882                    minute: Some(minute),
883                    second: Some(second),
884                    millisecond,
885                    precision,
886                    original_string: Arc::from(s),
887                })
888            }
889            _ => None,
890        }
891    }
892
893    /// Returns the precision level of this time.
894    pub fn precision(&self) -> TimePrecision {
895        self.precision
896    }
897
898    /// Returns the original string representation.
899    pub fn original_string(&self) -> &str {
900        &self.original_string
901    }
902
903    /// Converts to a NaiveTime, using defaults for missing components.
904    pub fn to_naive_time(&self) -> NaiveTime {
905        let milli = self.millisecond.unwrap_or(0);
906        let micro = milli * 1000; // Convert milliseconds to microseconds
907        NaiveTime::from_hms_micro_opt(
908            self.hour,
909            self.minute.unwrap_or(0),
910            self.second.unwrap_or(0),
911            micro,
912        )
913        .expect("Valid time components")
914    }
915
916    /// Compares two times considering precision.
917    /// Per FHIRPath spec: seconds and milliseconds are considered the same precision level
918    pub fn compare(&self, other: &Self) -> Option<Ordering> {
919        match self.hour.cmp(&other.hour) {
920            Ordering::Equal => {
921                match (self.minute, other.minute) {
922                    (None, None) => Some(Ordering::Equal),
923                    (None, Some(_)) | (Some(_), None) => None,
924                    (Some(m1), Some(m2)) => match m1.cmp(&m2) {
925                        Ordering::Equal => {
926                            match (self.second, other.second) {
927                                (None, None) => Some(Ordering::Equal),
928                                (None, Some(_)) | (Some(_), None) => None,
929                                (Some(s1), Some(s2)) => {
930                                    // Per FHIRPath spec: second and millisecond precisions are
931                                    // considered a single precision using decimal comparison
932                                    let ms1 = self.millisecond.unwrap_or(0);
933                                    let ms2 = other.millisecond.unwrap_or(0);
934                                    let total1 = s1 * 1000 + ms1;
935                                    let total2 = s2 * 1000 + ms2;
936                                    Some(total1.cmp(&total2))
937                                }
938                            }
939                        }
940                        other => Some(other),
941                    },
942                }
943            }
944            other => Some(other),
945        }
946    }
947}
948
949impl Default for PrecisionDateTime {
950    fn default() -> Self {
951        // Default to Unix epoch 1970-01-01T00:00:00
952        Self::from_date(1970, 1, 1)
953    }
954}
955
956/// Precision-aware FHIR DateTime type.
957///
958/// This type preserves the original precision and string representation
959/// of FHIR datetime values, including timezone information when present.
960///
961/// # FHIR DateTime Formats
962/// - `YYYY` - Year only
963/// - `YYYY-MM` - Year and month
964/// - `YYYY-MM-DD` - Date only
965/// - `YYYY-MM-DDTHH` - Date with hour
966/// - `YYYY-MM-DDTHH:MM` - Date with hour and minute
967/// - `YYYY-MM-DDTHH:MM:SS` - Date with time to seconds
968/// - `YYYY-MM-DDTHH:MM:SS.sss` - Full datetime with milliseconds
969/// - All time formats can include timezone: `Z`, `+HH:MM`, `-HH:MM`
970///
971/// # Examples
972/// ```rust
973/// use helios_fhir::{PrecisionDateTime, DateTimePrecision};
974///
975/// // Create a date-only datetime
976/// let date_dt = PrecisionDateTime::from_date(2023, 3, 15);
977/// assert_eq!(date_dt.precision(), DateTimePrecision::Date);
978/// assert_eq!(date_dt.original_string(), "2023-03-15");
979///
980/// // Create a full datetime with timezone
981/// let full_dt = PrecisionDateTime::parse("2023-03-15T14:30:45.123Z").unwrap();
982/// assert_eq!(full_dt.precision(), DateTimePrecision::Full);
983/// ```
984#[derive(Debug, Clone, PartialEq, Eq)]
985pub struct PrecisionDateTime {
986    /// Date components
987    pub date: PrecisionDate,
988    /// Time components (if precision includes time)
989    time: Option<PrecisionTime>,
990    /// Timezone offset in minutes from UTC (None means local/unspecified)
991    timezone_offset: Option<i32>,
992    /// Precision level of this datetime
993    precision: DateTimePrecision,
994    /// Original string representation
995    original_string: Arc<str>,
996}
997
998impl PrecisionDateTime {
999    /// Creates a year-only datetime.
1000    pub fn from_year(year: i32) -> Self {
1001        let date = PrecisionDate::from_year(year);
1002        Self {
1003            original_string: date.original_string.clone(),
1004            date,
1005            time: None,
1006            timezone_offset: None,
1007            precision: DateTimePrecision::Year,
1008        }
1009    }
1010
1011    /// Creates a year-month datetime.
1012    pub fn from_year_month(year: i32, month: u32) -> Self {
1013        let date = PrecisionDate::from_year_month(year, month);
1014        Self {
1015            original_string: date.original_string.clone(),
1016            date,
1017            time: None,
1018            timezone_offset: None,
1019            precision: DateTimePrecision::YearMonth,
1020        }
1021    }
1022
1023    /// Creates a date-only datetime.
1024    pub fn from_date(year: i32, month: u32, day: u32) -> Self {
1025        let date = PrecisionDate::from_ymd(year, month, day);
1026        Self {
1027            original_string: date.original_string.clone(),
1028            date,
1029            time: None,
1030            timezone_offset: None,
1031            precision: DateTimePrecision::Date,
1032        }
1033    }
1034
1035    /// Parses a FHIR datetime string, preserving precision and timezone.
1036    pub fn parse(s: &str) -> Option<Self> {
1037        // Remove @ prefix if present
1038        let s = s.strip_prefix('@').unwrap_or(s);
1039
1040        // Check for 'T' separator to determine if time is present
1041        if let Some(t_pos) = s.find('T') {
1042            let date_part = &s[..t_pos];
1043            let time_and_tz = &s[t_pos + 1..];
1044
1045            // Parse date part
1046            let date = PrecisionDate::parse(date_part)?;
1047
1048            // Check for timezone at the end
1049            let (time_part, timezone_offset) = if let Some(stripped) = time_and_tz.strip_suffix('Z')
1050            {
1051                (stripped, Some(0))
1052            } else if let Some(plus_pos) = time_and_tz.rfind('+') {
1053                let tz_str = &time_and_tz[plus_pos + 1..];
1054                let offset = Self::parse_timezone_offset(tz_str)?;
1055                (&time_and_tz[..plus_pos], Some(offset))
1056            } else if let Some(minus_pos) = time_and_tz.rfind('-') {
1057                // Be careful not to confuse negative timezone with date separator
1058                if minus_pos > 0 && time_and_tz[..minus_pos].contains(':') {
1059                    let tz_str = &time_and_tz[minus_pos + 1..];
1060                    let offset = Self::parse_timezone_offset(tz_str)?;
1061                    (&time_and_tz[..minus_pos], Some(-offset))
1062                } else {
1063                    (time_and_tz, None)
1064                }
1065            } else {
1066                (time_and_tz, None)
1067            };
1068
1069            // Parse time part if not empty
1070            let (time, precision) = if time_part.is_empty() {
1071                // Just "T" with no time components (partial datetime)
1072                (
1073                    None,
1074                    match date.precision {
1075                        DatePrecision::Full => DateTimePrecision::Date,
1076                        DatePrecision::YearMonth => DateTimePrecision::YearMonth,
1077                        DatePrecision::Year => DateTimePrecision::Year,
1078                    },
1079                )
1080            } else {
1081                let time = PrecisionTime::parse(time_part)?;
1082                let precision = match time.precision {
1083                    TimePrecision::Hour => DateTimePrecision::DateHour,
1084                    TimePrecision::HourMinute => DateTimePrecision::DateHourMinute,
1085                    TimePrecision::HourMinuteSecond => DateTimePrecision::DateHourMinuteSecond,
1086                    TimePrecision::Millisecond => DateTimePrecision::Full,
1087                };
1088                (Some(time), precision)
1089            };
1090
1091            Some(Self {
1092                date,
1093                time,
1094                timezone_offset,
1095                precision,
1096                original_string: Arc::from(s),
1097            })
1098        } else {
1099            // No 'T' separator, just a date
1100            let date = PrecisionDate::parse(s)?;
1101            let precision = match date.precision {
1102                DatePrecision::Year => DateTimePrecision::Year,
1103                DatePrecision::YearMonth => DateTimePrecision::YearMonth,
1104                DatePrecision::Full => DateTimePrecision::Date,
1105            };
1106
1107            Some(Self {
1108                original_string: Arc::from(s),
1109                date,
1110                time: None,
1111                timezone_offset: None,
1112                precision,
1113            })
1114        }
1115    }
1116
1117    /// Parses a timezone offset string (e.g., "05:30") into minutes.
1118    fn parse_timezone_offset(s: &str) -> Option<i32> {
1119        let parts: Vec<&str> = s.split(':').collect();
1120        match parts.len() {
1121            1 => {
1122                // Just hours
1123                let hours = parts[0].parse::<i32>().ok()?;
1124                Some(hours * 60)
1125            }
1126            2 => {
1127                // Hours and minutes
1128                let hours = parts[0].parse::<i32>().ok()?;
1129                let minutes = parts[1].parse::<i32>().ok()?;
1130                Some(hours * 60 + minutes)
1131            }
1132            _ => None,
1133        }
1134    }
1135
1136    /// Creates a PrecisionDateTime from a PrecisionDate (for date to datetime conversion).
1137    pub fn from_precision_date(date: PrecisionDate) -> Self {
1138        let precision = match date.precision {
1139            DatePrecision::Year => DateTimePrecision::Year,
1140            DatePrecision::YearMonth => DateTimePrecision::YearMonth,
1141            DatePrecision::Full => DateTimePrecision::Date,
1142        };
1143        Self {
1144            original_string: date.original_string.clone(),
1145            date,
1146            time: None,
1147            timezone_offset: None,
1148            precision,
1149        }
1150    }
1151
1152    /// Returns the precision level of this datetime.
1153    pub fn precision(&self) -> DateTimePrecision {
1154        self.precision
1155    }
1156
1157    /// Returns the original string representation.
1158    pub fn original_string(&self) -> &str {
1159        &self.original_string
1160    }
1161
1162    /// Converts to a chrono DateTime<Utc>, using defaults for missing components.
1163    pub fn to_chrono_datetime(&self) -> ChronoDateTime<Utc> {
1164        let naive_date = self.date.to_naive_date();
1165        let naive_time = self
1166            .time
1167            .as_ref()
1168            .map(|t| t.to_naive_time())
1169            .unwrap_or_else(|| NaiveTime::from_hms_opt(0, 0, 0).unwrap());
1170
1171        let naive_dt = naive_date.and_time(naive_time);
1172
1173        // Apply timezone offset if present
1174        if let Some(offset_minutes) = self.timezone_offset {
1175            // The datetime is in local time with the given offset
1176            // We need to subtract the offset to get UTC
1177            let utc_naive = naive_dt - chrono::Duration::minutes(offset_minutes as i64);
1178            ChronoDateTime::<Utc>::from_naive_utc_and_offset(utc_naive, Utc)
1179        } else {
1180            // No timezone means we assume UTC
1181            ChronoDateTime::<Utc>::from_naive_utc_and_offset(naive_dt, Utc)
1182        }
1183    }
1184
1185    /// Compares two datetimes considering precision and timezones.
1186    pub fn compare(&self, other: &Self) -> Option<Ordering> {
1187        // Check if precisions are compatible
1188        // Per FHIRPath spec: seconds and milliseconds are the same precision
1189        let self_precision_normalized = match self.precision {
1190            DateTimePrecision::Full => DateTimePrecision::DateHourMinuteSecond,
1191            p => p,
1192        };
1193        let other_precision_normalized = match other.precision {
1194            DateTimePrecision::Full => DateTimePrecision::DateHourMinuteSecond,
1195            p => p,
1196        };
1197
1198        // If precisions don't match (except for seconds/milliseconds), return None
1199        if self_precision_normalized != other_precision_normalized {
1200            // Special handling for date vs datetime with time components
1201            if self.time.is_none() != other.time.is_none() {
1202                return None;
1203            }
1204        }
1205
1206        // If both have sufficient precision and timezone info, compare as full datetimes
1207        if self.precision >= DateTimePrecision::DateHour
1208            && other.precision >= DateTimePrecision::DateHour
1209            && self.timezone_offset.is_some()
1210            && other.timezone_offset.is_some()
1211        {
1212            // Convert to UTC and compare
1213            return Some(self.to_chrono_datetime().cmp(&other.to_chrono_datetime()));
1214        }
1215
1216        // If one has timezone and the other doesn't, comparison is indeterminate
1217        if self.timezone_offset.is_some() != other.timezone_offset.is_some() {
1218            return None;
1219        }
1220
1221        // Otherwise, compare components with precision awareness
1222        match self.date.compare(&other.date) {
1223            Some(Ordering::Equal) => {
1224                // Dates are equal at their precision level
1225                match (&self.time, &other.time) {
1226                    (None, None) => Some(Ordering::Equal),
1227                    (None, Some(_)) | (Some(_), None) => None, // Different precisions
1228                    (Some(t1), Some(t2)) => t1.compare(t2),
1229                }
1230            }
1231            other => other,
1232        }
1233    }
1234}
1235
1236// === Display Implementations for Precision Types ===
1237
1238impl std::fmt::Display for PrecisionDate {
1239    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1240        write!(f, "{}", self.original_string)
1241    }
1242}
1243
1244impl std::fmt::Display for PrecisionDateTime {
1245    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1246        write!(f, "{}", self.original_string)
1247    }
1248}
1249
1250impl std::fmt::Display for PrecisionTime {
1251    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1252        write!(f, "{}", self.original_string)
1253    }
1254}
1255
1256// === Serde Implementations for Precision Types ===
1257
1258impl Serialize for PrecisionDate {
1259    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1260    where
1261        S: Serializer,
1262    {
1263        // Serialize as a simple string
1264        serializer.serialize_str(&self.original_string)
1265    }
1266}
1267
1268impl<'de> Deserialize<'de> for PrecisionDate {
1269    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1270    where
1271        D: Deserializer<'de>,
1272    {
1273        let s = String::deserialize(deserializer)?;
1274        PrecisionDate::parse(&s)
1275            .ok_or_else(|| de::Error::custom(format!("Invalid FHIR date format: {}", s)))
1276    }
1277}
1278
1279impl Serialize for PrecisionTime {
1280    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1281    where
1282        S: Serializer,
1283    {
1284        // Serialize as a simple string
1285        serializer.serialize_str(&self.original_string)
1286    }
1287}
1288
1289impl<'de> Deserialize<'de> for PrecisionTime {
1290    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1291    where
1292        D: Deserializer<'de>,
1293    {
1294        let s = String::deserialize(deserializer)?;
1295        PrecisionTime::parse(&s)
1296            .ok_or_else(|| de::Error::custom(format!("Invalid FHIR time format: {}", s)))
1297    }
1298}
1299
1300impl Serialize for PrecisionDateTime {
1301    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1302    where
1303        S: Serializer,
1304    {
1305        // Serialize as a simple string
1306        serializer.serialize_str(&self.original_string)
1307    }
1308}
1309
1310impl<'de> Deserialize<'de> for PrecisionDateTime {
1311    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1312    where
1313        D: Deserializer<'de>,
1314    {
1315        let s = String::deserialize(deserializer)?;
1316        PrecisionDateTime::parse(&s)
1317            .ok_or_else(|| de::Error::custom(format!("Invalid FHIR datetime format: {}", s)))
1318    }
1319}
1320
1321// === PrecisionInstant Implementation ===
1322
1323/// A FHIR instant value that preserves the original string representation and precision.
1324///
1325/// Instants in FHIR must be complete date-time values with timezone information,
1326/// representing a specific moment in time. This type wraps PrecisionDateTime but
1327/// enforces instant-specific constraints.
1328#[derive(Debug, Clone, PartialEq, Eq, Default)]
1329pub struct PrecisionInstant {
1330    inner: PrecisionDateTime,
1331}
1332
1333impl PrecisionInstant {
1334    /// Parses a FHIR instant string.
1335    /// Returns None if the string is not a valid instant (must have full date, time, and timezone).
1336    pub fn parse(s: &str) -> Option<Self> {
1337        // Parse as PrecisionDateTime first
1338        let dt = PrecisionDateTime::parse(s)?;
1339
1340        // For now, accept any valid datetime as an instant
1341        // In strict mode, we could require timezone, but many FHIR resources
1342        // use instant fields without explicit timezones
1343        Some(PrecisionInstant { inner: dt })
1344    }
1345
1346    /// Returns the original string representation
1347    pub fn original_string(&self) -> &str {
1348        self.inner.original_string()
1349    }
1350
1351    /// Get the inner PrecisionDateTime
1352    pub fn as_datetime(&self) -> &PrecisionDateTime {
1353        &self.inner
1354    }
1355
1356    /// Convert to chrono DateTime<Utc>
1357    pub fn to_chrono_datetime(&self) -> ChronoDateTime<Utc> {
1358        // PrecisionDateTime::to_chrono_datetime returns ChronoDateTime<Utc>
1359        self.inner.to_chrono_datetime()
1360    }
1361}
1362
1363impl fmt::Display for PrecisionInstant {
1364    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1365        write!(f, "{}", self.inner)
1366    }
1367}
1368
1369impl Serialize for PrecisionInstant {
1370    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1371    where
1372        S: Serializer,
1373    {
1374        self.inner.serialize(serializer)
1375    }
1376}
1377
1378impl<'de> Deserialize<'de> for PrecisionInstant {
1379    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1380    where
1381        D: Deserializer<'de>,
1382    {
1383        let s = String::deserialize(deserializer)?;
1384        PrecisionInstant::parse(&s)
1385            .ok_or_else(|| de::Error::custom(format!("Invalid FHIR instant format: {}", s)))
1386    }
1387}
1388
1389// === IntoEvaluationResult Implementations for Precision Types ===
1390
1391impl IntoEvaluationResult for PrecisionDate {
1392    fn to_evaluation_result(&self) -> EvaluationResult {
1393        EvaluationResult::date(self.original_string.to_string())
1394    }
1395}
1396
1397impl IntoEvaluationResult for PrecisionTime {
1398    fn to_evaluation_result(&self) -> EvaluationResult {
1399        EvaluationResult::time(self.original_string.to_string())
1400    }
1401}
1402
1403impl IntoEvaluationResult for PrecisionDateTime {
1404    fn to_evaluation_result(&self) -> EvaluationResult {
1405        EvaluationResult::datetime(self.original_string.to_string())
1406    }
1407}
1408
1409impl IntoEvaluationResult for PrecisionInstant {
1410    fn to_evaluation_result(&self) -> EvaluationResult {
1411        // Return as datetime with instant type info
1412        EvaluationResult::DateTime(
1413            self.inner.original_string.to_string(),
1414            Some(TypeInfoResult::new("FHIR", "instant")),
1415        )
1416    }
1417}
1418
1419// Removed DecimalElementObjectVisitor
1420
1421#[cfg(feature = "R4")]
1422pub mod r4;
1423#[cfg(feature = "R4B")]
1424pub mod r4b;
1425#[cfg(feature = "R5")]
1426pub mod r5;
1427#[cfg(feature = "R6")]
1428pub mod r6;
1429
1430pub mod parameters;
1431
1432// Re-export commonly used types from parameters module
1433pub use parameters::{ParameterValueAccessor, VersionIndependentParameters};
1434
1435/// Multi-version FHIR resource container supporting version-agnostic operations.
1436///
1437/// This enum provides a unified interface for working with FHIR resources across
1438/// different specification versions. It enables applications to handle multiple
1439/// FHIR versions simultaneously while maintaining type safety and version-specific
1440/// behavior where needed.
1441///
1442/// # Supported Versions
1443///
1444/// - **R4**: FHIR 4.0.1 (normative)
1445/// - **R4B**: FHIR 4.3.0 (ballot)  
1446/// - **R5**: FHIR 5.0.0 (ballot)
1447/// - **R6**: FHIR 6.0.0 (draft)
1448///
1449/// # Feature Flags
1450///
1451/// Each FHIR version is controlled by a corresponding Cargo feature flag.
1452/// Only enabled versions will be available in the enum variants.
1453///
1454/// # Examples
1455///
1456/// ```rust
1457/// use helios_fhir::{FhirResource, FhirVersion};
1458/// # #[cfg(feature = "R4")]
1459/// use helios_fhir::r4::{Patient, HumanName};
1460///
1461/// # #[cfg(feature = "R4")]
1462/// {
1463///     // Create an R4 patient
1464///     let patient = Patient {
1465///         name: Some(vec![HumanName {
1466///             family: Some("Doe".to_string().into()),
1467///             given: Some(vec!["John".to_string().into()]),
1468///             ..Default::default()
1469///         }]),
1470///         ..Default::default()
1471///     };
1472///
1473///     // Wrap in version-agnostic container
1474///     let resource = FhirResource::R4(Box::new(helios_fhir::r4::Resource::Patient(patient)));
1475///     assert_eq!(resource.version(), FhirVersion::R4);
1476/// }
1477/// ```
1478///
1479/// # Version Detection
1480///
1481/// Use the `version()` method to determine which FHIR version a resource uses:
1482///
1483/// ```rust
1484/// # use helios_fhir::{FhirResource, FhirVersion};
1485/// # #[cfg(feature = "R4")]
1486/// # {
1487/// # let resource = FhirResource::R4(Box::new(helios_fhir::r4::Resource::Patient(Default::default())));
1488/// match resource.version() {
1489///     #[cfg(feature = "R4")]
1490///     FhirVersion::R4 => println!("This is an R4 resource"),
1491///     #[cfg(feature = "R4B")]
1492///     FhirVersion::R4B => println!("This is an R4B resource"),
1493///     #[cfg(feature = "R5")]
1494///     FhirVersion::R5 => println!("This is an R5 resource"),
1495///     #[cfg(feature = "R6")]
1496///     FhirVersion::R6 => println!("This is an R6 resource"),
1497/// }
1498/// # }
1499/// ```
1500#[derive(Debug)]
1501pub enum FhirResource {
1502    /// FHIR 4.0.1 (normative) resource
1503    #[cfg(feature = "R4")]
1504    R4(Box<r4::Resource>),
1505    /// FHIR 4.3.0 (ballot) resource
1506    #[cfg(feature = "R4B")]
1507    R4B(Box<r4b::Resource>),
1508    /// FHIR 5.0.0 (ballot) resource
1509    #[cfg(feature = "R5")]
1510    R5(Box<r5::Resource>),
1511    /// FHIR 6.0.0 (draft) resource
1512    #[cfg(feature = "R6")]
1513    R6(Box<r6::Resource>),
1514}
1515
1516impl FhirResource {
1517    /// Returns the FHIR specification version of this resource.
1518    ///
1519    /// This method provides version detection for multi-version applications,
1520    /// enabling version-specific processing logic and compatibility checks.
1521    ///
1522    /// # Returns
1523    ///
1524    /// The `FhirVersion` enum variant corresponding to this resource's specification.
1525    ///
1526    /// # Examples
1527    ///
1528    /// ```rust
1529    /// use helios_fhir::{FhirResource, FhirVersion};
1530    ///
1531    /// # #[cfg(feature = "R5")]
1532    /// # {
1533    /// # let resource = FhirResource::R5(Box::new(helios_fhir::r5::Resource::Patient(Default::default())));
1534    /// let version = resource.version();
1535    /// assert_eq!(version, FhirVersion::R5);
1536    ///
1537    /// // Use version for conditional logic
1538    /// match version {
1539    ///     FhirVersion::R5 => {
1540    ///         println!("Processing R5 resource with latest features");
1541    ///     },
1542    ///     FhirVersion::R4 => {
1543    ///         println!("Processing R4 resource with normative features");
1544    ///     },
1545    ///     _ => {
1546    ///         println!("Processing other FHIR version");
1547    ///     }
1548    /// }
1549    /// # }
1550    /// ```
1551    pub fn version(&self) -> FhirVersion {
1552        match self {
1553            #[cfg(feature = "R4")]
1554            FhirResource::R4(_) => FhirVersion::R4,
1555            #[cfg(feature = "R4B")]
1556            FhirResource::R4B(_) => FhirVersion::R4B,
1557            #[cfg(feature = "R5")]
1558            FhirResource::R5(_) => FhirVersion::R5,
1559            #[cfg(feature = "R6")]
1560            FhirResource::R6(_) => FhirVersion::R6,
1561        }
1562    }
1563}
1564
1565/// Enumeration of supported FHIR specification versions.
1566///
1567/// This enum represents the different versions of the FHIR (Fast Healthcare
1568/// Interoperability Resources) specification that this library supports.
1569/// Each version represents a specific release of the FHIR standard with
1570/// its own set of features, resources, and compatibility requirements.
1571///
1572/// # Version Status
1573///
1574/// - **R4** (4.0.1): Normative version, widely adopted in production
1575/// - **R4B** (4.3.0): Ballot version with additional features
1576/// - **R5** (5.0.0): Ballot version with significant enhancements
1577/// - **R6** (6.0.0): Draft version under active development
1578///
1579/// # Feature Flags
1580///
1581/// Each version is controlled by a corresponding Cargo feature flag:
1582/// - `R4`: Enables FHIR R4 support
1583/// - `R4B`: Enables FHIR R4B support  
1584/// - `R5`: Enables FHIR R5 support
1585/// - `R6`: Enables FHIR R6 support
1586///
1587/// # Examples
1588///
1589/// ```rust
1590/// use helios_fhir::FhirVersion;
1591///
1592/// // Version comparison
1593/// # #[cfg(all(feature = "R4", feature = "R5"))]
1594/// # {
1595/// assert_ne!(FhirVersion::R4, FhirVersion::R5);
1596/// # }
1597///
1598/// // String representation
1599/// # #[cfg(feature = "R4")]
1600/// # {
1601/// let version = FhirVersion::R4;
1602/// assert_eq!(version.as_str(), "R4");
1603/// assert_eq!(version.to_string(), "R4");
1604/// # }
1605/// ```
1606///
1607/// # CLI Integration
1608///
1609/// This enum implements `clap::ValueEnum` for command-line argument parsing:
1610///
1611/// ```rust,no_run
1612/// use clap::Parser;
1613/// use helios_fhir::FhirVersion;
1614///
1615/// #[derive(Parser)]
1616/// struct Args {
1617///     #[arg(value_enum)]
1618///     version: FhirVersion,
1619/// }
1620/// ```
1621#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1622pub enum FhirVersion {
1623    /// FHIR 4.0.1 (normative) - The current normative version
1624    #[cfg(feature = "R4")]
1625    R4,
1626    /// FHIR 4.3.0 (ballot) - Intermediate version with additional features
1627    #[cfg(feature = "R4B")]
1628    R4B,
1629    /// FHIR 5.0.0 (ballot) - Next major version with significant changes
1630    #[cfg(feature = "R5")]
1631    R5,
1632    /// FHIR 6.0.0 (draft) - Future version under development
1633    #[cfg(feature = "R6")]
1634    R6,
1635}
1636
1637impl FhirVersion {
1638    /// Returns the string representation of the FHIR version.
1639    ///
1640    /// This method provides the standard version identifier as used in
1641    /// FHIR documentation, URLs, and configuration files.
1642    ///
1643    /// # Returns
1644    ///
1645    /// A static string slice representing the version (e.g., "R4", "R5").
1646    ///
1647    /// # Examples
1648    ///
1649    /// ```rust
1650    /// use helios_fhir::FhirVersion;
1651    ///
1652    /// # #[cfg(feature = "R4")]
1653    /// assert_eq!(FhirVersion::R4.as_str(), "R4");
1654    /// # #[cfg(feature = "R5")]
1655    /// assert_eq!(FhirVersion::R5.as_str(), "R5");
1656    /// ```
1657    ///
1658    /// # Usage
1659    ///
1660    /// This method is commonly used for:
1661    /// - Logging and debugging output
1662    /// - Configuration file parsing
1663    /// - API endpoint construction
1664    /// - Version-specific resource loading
1665    pub fn as_str(&self) -> &'static str {
1666        match self {
1667            #[cfg(feature = "R4")]
1668            FhirVersion::R4 => "R4",
1669            #[cfg(feature = "R4B")]
1670            FhirVersion::R4B => "R4B",
1671            #[cfg(feature = "R5")]
1672            FhirVersion::R5 => "R5",
1673            #[cfg(feature = "R6")]
1674            FhirVersion::R6 => "R6",
1675        }
1676    }
1677}
1678
1679/// Implements `Display` trait for user-friendly output formatting.
1680///
1681/// This enables `FhirVersion` to be used in string formatting operations
1682/// and provides consistent output across different contexts.
1683///
1684/// # Examples
1685///
1686/// ```rust
1687/// use helios_fhir::FhirVersion;
1688///
1689/// # #[cfg(feature = "R5")]
1690/// # {
1691/// let version = FhirVersion::R5;
1692/// println!("Using FHIR version: {}", version); // Prints: "Using FHIR version: R5"
1693///
1694/// let formatted = format!("fhir-{}.json", version);
1695/// assert_eq!(formatted, "fhir-R5.json");
1696/// # }
1697/// ```
1698impl std::fmt::Display for FhirVersion {
1699    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1700        write!(f, "{}", self.as_str())
1701    }
1702}
1703
1704/// Provides a default FHIR version when R4 feature is enabled.
1705///
1706/// R4 is chosen as the default because it is the current normative version
1707/// of the FHIR specification and is widely adopted in production systems.
1708///
1709/// # Examples
1710///
1711/// ```rust
1712/// use helios_fhir::FhirVersion;
1713///
1714/// # #[cfg(feature = "R4")]
1715/// # {
1716/// let default_version = FhirVersion::default();
1717/// assert_eq!(default_version, FhirVersion::R4);
1718/// # }
1719/// ```
1720#[cfg(feature = "R4")]
1721impl Default for FhirVersion {
1722    fn default() -> Self {
1723        FhirVersion::R4
1724    }
1725}
1726
1727/// Implements `clap::ValueEnum` for command-line argument parsing.
1728///
1729/// This implementation enables `FhirVersion` to be used directly as a command-line
1730/// argument type with clap, providing automatic parsing, validation, and help text
1731/// generation.
1732///
1733/// # Examples
1734///
1735/// ```rust,no_run
1736/// use clap::Parser;
1737/// use helios_fhir::FhirVersion;
1738///
1739/// #[derive(Parser)]
1740/// struct Args {
1741///     /// FHIR specification version to use
1742///     #[arg(value_enum, default_value_t = FhirVersion::default())]
1743///     version: FhirVersion,
1744/// }
1745///
1746/// // Command line: my-app --version R5
1747/// let args = Args::parse();
1748/// println!("Using FHIR version: {}", args.version);
1749/// ```
1750///
1751/// # Generated Help Text
1752///
1753/// When using this enum with clap, the help text will automatically include
1754/// all available FHIR versions based on enabled feature flags.
1755impl clap::ValueEnum for FhirVersion {
1756    fn value_variants<'a>() -> &'a [Self] {
1757        &[
1758            #[cfg(feature = "R4")]
1759            FhirVersion::R4,
1760            #[cfg(feature = "R4B")]
1761            FhirVersion::R4B,
1762            #[cfg(feature = "R5")]
1763            FhirVersion::R5,
1764            #[cfg(feature = "R6")]
1765            FhirVersion::R6,
1766        ]
1767    }
1768
1769    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
1770        Some(clap::builder::PossibleValue::new(self.as_str()))
1771    }
1772}
1773
1774/// Trait for providing FHIR resource type information
1775///
1776/// This trait allows querying which resource types are available in a specific
1777/// FHIR version without hardcoding resource type lists in multiple places.
1778pub trait FhirResourceTypeProvider {
1779    /// Returns a vector of all resource type names supported in this FHIR version
1780    fn get_resource_type_names() -> Vec<&'static str>;
1781
1782    /// Checks if a given type name is a resource type in this FHIR version
1783    fn is_resource_type(type_name: &str) -> bool {
1784        Self::get_resource_type_names()
1785            .iter()
1786            .any(|&resource_type| resource_type.eq_ignore_ascii_case(type_name))
1787    }
1788}
1789
1790/// Trait for providing FHIR complex type information
1791///
1792/// This trait allows querying which complex data types are available in a specific
1793/// FHIR version without hardcoding complex type lists in multiple places.
1794pub trait FhirComplexTypeProvider {
1795    /// Returns a vector of all complex type names supported in this FHIR version
1796    fn get_complex_type_names() -> Vec<&'static str>;
1797
1798    /// Checks if a given type name is a complex type in this FHIR version
1799    fn is_complex_type(type_name: &str) -> bool {
1800        Self::get_complex_type_names()
1801            .iter()
1802            .any(|&complex_type| complex_type.eq_ignore_ascii_case(type_name))
1803    }
1804}
1805
1806// --- Internal Visitor for Element Object Deserialization ---
1807
1808/// Internal visitor struct for deserializing Element objects from JSON maps.
1809///
1810/// This visitor handles the complex deserialization logic for Element<V, E> when
1811/// the JSON input is an object containing id, extension, and value fields.
1812struct ElementObjectVisitor<V, E>(PhantomData<(V, E)>);
1813
1814impl<'de, V, E> Visitor<'de> for ElementObjectVisitor<V, E>
1815where
1816    V: Deserialize<'de>,
1817    E: Deserialize<'de>,
1818{
1819    type Value = Element<V, E>;
1820
1821    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1822        formatter.write_str("an Element object")
1823    }
1824
1825    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
1826    where
1827        A: MapAccess<'de>,
1828    {
1829        let mut id: Option<String> = None;
1830        let mut extension: Option<Vec<E>> = None;
1831        let mut value: Option<V> = None;
1832
1833        // Manually deserialize fields from the map
1834        while let Some(key) = map.next_key::<String>()? {
1835            match key.as_str() {
1836                "id" => {
1837                    if id.is_some() {
1838                        return Err(de::Error::duplicate_field("id"));
1839                    }
1840                    id = Some(map.next_value()?);
1841                }
1842                "extension" => {
1843                    if extension.is_some() {
1844                        return Err(de::Error::duplicate_field("extension"));
1845                    }
1846                    extension = Some(map.next_value()?);
1847                }
1848                "value" => {
1849                    if value.is_some() {
1850                        return Err(de::Error::duplicate_field("value"));
1851                    }
1852                    // Deserialize directly into Option<V>
1853                    value = Some(map.next_value()?);
1854                }
1855                // Ignore any unknown fields encountered
1856                _ => {
1857                    let _ = map.next_value::<de::IgnoredAny>()?;
1858                }
1859            }
1860        }
1861
1862        Ok(Element {
1863            id,
1864            extension,
1865            value,
1866        })
1867    }
1868}
1869
1870/// Generic element container supporting FHIR's extension mechanism.
1871///
1872/// In FHIR, most primitive elements can be extended with additional metadata
1873/// through the `id` and `extension` fields. This container type provides
1874/// the infrastructure to support this pattern across all FHIR data types.
1875///
1876/// # Type Parameters
1877///
1878/// * `V` - The value type (e.g., `String`, `i32`, `PreciseDecimal`)
1879/// * `E` - The extension type (typically the generated `Extension` struct)
1880///
1881/// # FHIR Element Structure
1882///
1883/// FHIR elements can appear in three forms:
1884/// 1. **Primitive value**: Just the value itself (e.g., `"text"`, `42`)
1885/// 2. **Extended primitive**: An object with `value`, `id`, and/or `extension` fields
1886/// 3. **Extension-only**: An object with just `id` and/or `extension` (no value)
1887///
1888/// # Examples
1889///
1890/// ```rust
1891/// use helios_fhir::{Element, r4::Extension};
1892///
1893/// // Simple primitive value
1894/// let simple: Element<String, Extension> = Element {
1895///     value: Some("Hello World".to_string()),
1896///     id: None,
1897///     extension: None,
1898/// };
1899///
1900/// // Extended primitive with ID
1901/// let with_id: Element<String, Extension> = Element {
1902///     value: Some("Hello World".to_string()),
1903///     id: Some("text-element-1".to_string()),
1904///     extension: None,
1905/// };
1906///
1907/// // Extension-only element (no value)
1908/// let extension_only: Element<String, Extension> = Element {
1909///     value: None,
1910///     id: Some("disabled-element".to_string()),
1911///     extension: Some(vec![/* extensions */]),
1912/// };
1913/// ```
1914///
1915/// # Serialization Behavior
1916///
1917/// - If only `value` is present: serializes as the primitive value directly
1918/// - If `id` or `extension` are present: serializes as an object with all fields
1919/// - If everything is `None`: serializes as `null`
1920#[derive(Debug, PartialEq, Eq, Clone, Default)]
1921pub struct Element<V, E> {
1922    /// Optional element identifier for referencing within the resource
1923    pub id: Option<String>,
1924    /// Optional extensions providing additional metadata
1925    pub extension: Option<Vec<E>>,
1926    /// The actual primitive value
1927    pub value: Option<V>,
1928}
1929
1930impl<V, E> Element<V, E> {
1931    /// Returns `true` if no value, id, or extensions are present.
1932    #[inline]
1933    pub fn is_empty(&self) -> bool {
1934        self.value.is_none() && self.id.is_none() && self.extension.is_none()
1935    }
1936}
1937
1938// Custom Deserialize for Element<V, E>
1939// Remove PartialEq/Eq bounds for V and E as they are not needed for deserialization itself
1940impl<'de, V, E> Deserialize<'de> for Element<V, E>
1941where
1942    V: Deserialize<'de> + 'static, // Added 'static for TypeId comparisons
1943    E: Deserialize<'de>,           // Removed PartialEq
1944{
1945    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1946    where
1947        D: Deserializer<'de>,
1948    {
1949        // Use the AnyValueVisitor approach to handle different JSON input types
1950        struct AnyValueVisitor<V, E>(PhantomData<(V, E)>);
1951
1952        impl<'de, V, E> Visitor<'de> for AnyValueVisitor<V, E>
1953        where
1954            V: Deserialize<'de> + 'static,
1955            E: Deserialize<'de>,
1956        {
1957            type Value = Element<V, E>;
1958
1959            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1960                formatter
1961                    .write_str("a primitive value (string, number, boolean), an object, or null")
1962            }
1963
1964            // Handle primitive types by attempting to deserialize V and wrapping it
1965            fn visit_bool<Er>(self, v: bool) -> Result<Self::Value, Er>
1966            where
1967                Er: de::Error,
1968            {
1969                V::deserialize(de::value::BoolDeserializer::new(v)).map(|value| Element {
1970                    id: None,
1971                    extension: None,
1972                    value: Some(value),
1973                })
1974            }
1975            fn visit_i64<Er>(self, v: i64) -> Result<Self::Value, Er>
1976            where
1977                Er: de::Error,
1978            {
1979                V::deserialize(de::value::I64Deserializer::new(v)).map(|value| Element {
1980                    id: None,
1981                    extension: None,
1982                    value: Some(value),
1983                })
1984            }
1985            fn visit_u64<Er>(self, v: u64) -> Result<Self::Value, Er>
1986            where
1987                Er: de::Error,
1988            {
1989                V::deserialize(de::value::U64Deserializer::new(v)).map(|value| Element {
1990                    id: None,
1991                    extension: None,
1992                    value: Some(value),
1993                })
1994            }
1995            fn visit_f64<Er>(self, v: f64) -> Result<Self::Value, Er>
1996            where
1997                Er: de::Error,
1998            {
1999                V::deserialize(de::value::F64Deserializer::new(v)).map(|value| Element {
2000                    id: None,
2001                    extension: None,
2002                    value: Some(value),
2003                })
2004            }
2005            fn visit_str<Er>(self, v: &str) -> Result<Self::Value, Er>
2006            where
2007                Er: de::Error,
2008            {
2009                use std::any::TypeId;
2010
2011                // Try to handle numeric strings for integer types
2012                if TypeId::of::<V>() == TypeId::of::<i64>() {
2013                    if let Ok(int_val) = v.parse::<i64>() {
2014                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
2015                            |value| Element {
2016                                id: None,
2017                                extension: None,
2018                                value: Some(value),
2019                            },
2020                        );
2021                    }
2022                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
2023                    if let Ok(int_val) = v.parse::<i32>() {
2024                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
2025                            |value| Element {
2026                                id: None,
2027                                extension: None,
2028                                value: Some(value),
2029                            },
2030                        );
2031                    }
2032                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
2033                    if let Ok(int_val) = v.parse::<u64>() {
2034                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
2035                            |value| Element {
2036                                id: None,
2037                                extension: None,
2038                                value: Some(value),
2039                            },
2040                        );
2041                    }
2042                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
2043                    if let Ok(int_val) = v.parse::<u32>() {
2044                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
2045                            |value| Element {
2046                                id: None,
2047                                extension: None,
2048                                value: Some(value),
2049                            },
2050                        );
2051                    }
2052                }
2053
2054                // Fall back to normal string deserialization
2055                V::deserialize(de::value::StrDeserializer::new(v)).map(|value| Element {
2056                    id: None,
2057                    extension: None,
2058                    value: Some(value),
2059                })
2060            }
2061            fn visit_string<Er>(self, v: String) -> Result<Self::Value, Er>
2062            where
2063                Er: de::Error,
2064            {
2065                use std::any::TypeId;
2066
2067                // Try to handle numeric strings for integer types
2068                if TypeId::of::<V>() == TypeId::of::<i64>() {
2069                    if let Ok(int_val) = v.parse::<i64>() {
2070                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
2071                            |value| Element {
2072                                id: None,
2073                                extension: None,
2074                                value: Some(value),
2075                            },
2076                        );
2077                    }
2078                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
2079                    if let Ok(int_val) = v.parse::<i32>() {
2080                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
2081                            |value| Element {
2082                                id: None,
2083                                extension: None,
2084                                value: Some(value),
2085                            },
2086                        );
2087                    }
2088                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
2089                    if let Ok(int_val) = v.parse::<u64>() {
2090                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
2091                            |value| Element {
2092                                id: None,
2093                                extension: None,
2094                                value: Some(value),
2095                            },
2096                        );
2097                    }
2098                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
2099                    if let Ok(int_val) = v.parse::<u32>() {
2100                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
2101                            |value| Element {
2102                                id: None,
2103                                extension: None,
2104                                value: Some(value),
2105                            },
2106                        );
2107                    }
2108                }
2109
2110                // Fall back to normal string deserialization
2111                V::deserialize(de::value::StringDeserializer::new(v.clone())).map(|value| Element {
2112                    // Clone v for error message
2113                    id: None,
2114                    extension: None,
2115                    value: Some(value),
2116                })
2117            }
2118            fn visit_borrowed_str<Er>(self, v: &'de str) -> Result<Self::Value, Er>
2119            where
2120                Er: de::Error,
2121            {
2122                use std::any::TypeId;
2123
2124                // Try to handle numeric strings for integer types
2125                if TypeId::of::<V>() == TypeId::of::<i64>() {
2126                    if let Ok(int_val) = v.parse::<i64>() {
2127                        return V::deserialize(de::value::I64Deserializer::new(int_val)).map(
2128                            |value| Element {
2129                                id: None,
2130                                extension: None,
2131                                value: Some(value),
2132                            },
2133                        );
2134                    }
2135                } else if TypeId::of::<V>() == TypeId::of::<i32>() {
2136                    if let Ok(int_val) = v.parse::<i32>() {
2137                        return V::deserialize(de::value::I32Deserializer::new(int_val)).map(
2138                            |value| Element {
2139                                id: None,
2140                                extension: None,
2141                                value: Some(value),
2142                            },
2143                        );
2144                    }
2145                } else if TypeId::of::<V>() == TypeId::of::<u64>() {
2146                    if let Ok(int_val) = v.parse::<u64>() {
2147                        return V::deserialize(de::value::U64Deserializer::new(int_val)).map(
2148                            |value| Element {
2149                                id: None,
2150                                extension: None,
2151                                value: Some(value),
2152                            },
2153                        );
2154                    }
2155                } else if TypeId::of::<V>() == TypeId::of::<u32>() {
2156                    if let Ok(int_val) = v.parse::<u32>() {
2157                        return V::deserialize(de::value::U32Deserializer::new(int_val)).map(
2158                            |value| Element {
2159                                id: None,
2160                                extension: None,
2161                                value: Some(value),
2162                            },
2163                        );
2164                    }
2165                }
2166
2167                // Fall back to normal string deserialization
2168                V::deserialize(de::value::BorrowedStrDeserializer::new(v)).map(|value| Element {
2169                    id: None,
2170                    extension: None,
2171                    value: Some(value),
2172                })
2173            }
2174            fn visit_bytes<Er>(self, v: &[u8]) -> Result<Self::Value, Er>
2175            where
2176                Er: de::Error,
2177            {
2178                V::deserialize(de::value::BytesDeserializer::new(v)).map(|value| Element {
2179                    id: None,
2180                    extension: None,
2181                    value: Some(value),
2182                })
2183            }
2184            fn visit_byte_buf<Er>(self, v: Vec<u8>) -> Result<Self::Value, Er>
2185            where
2186                Er: de::Error,
2187            {
2188                // Use BytesDeserializer with a slice reference &v
2189                V::deserialize(de::value::BytesDeserializer::new(&v)).map(|value| Element {
2190                    id: None,
2191                    extension: None,
2192                    value: Some(value),
2193                })
2194            }
2195
2196            // Handle null
2197            fn visit_none<Er>(self) -> Result<Self::Value, Er>
2198            where
2199                Er: de::Error,
2200            {
2201                Ok(Element {
2202                    id: None,
2203                    extension: None,
2204                    value: None,
2205                })
2206            }
2207            fn visit_unit<Er>(self) -> Result<Self::Value, Er>
2208            where
2209                Er: de::Error,
2210            {
2211                Ok(Element {
2212                    id: None,
2213                    extension: None,
2214                    value: None,
2215                })
2216            }
2217
2218            // Handle Option<T> by visiting Some
2219            fn visit_some<De>(self, deserializer: De) -> Result<Self::Value, De::Error>
2220            where
2221                De: Deserializer<'de>,
2222            {
2223                // Re-dispatch to deserialize_any to handle the inner type correctly
2224                deserializer.deserialize_any(self)
2225            }
2226
2227            // Handle object
2228            fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
2229            where
2230                A: MapAccess<'de>,
2231            {
2232                // Deserialize the map using ElementObjectVisitor
2233                // Need to create a deserializer from the map access
2234                let map_deserializer = de::value::MapAccessDeserializer::new(map);
2235                map_deserializer.deserialize_map(ElementObjectVisitor(PhantomData))
2236            }
2237
2238            // We don't expect sequences for a single Element
2239            fn visit_seq<A>(self, _seq: A) -> Result<Self::Value, A::Error>
2240            where
2241                A: de::SeqAccess<'de>,
2242            {
2243                Err(de::Error::invalid_type(de::Unexpected::Seq, &self))
2244            }
2245        }
2246
2247        // Start deserialization using the visitor
2248        deserializer.deserialize_any(AnyValueVisitor(PhantomData))
2249    }
2250}
2251
2252// Custom Serialize for Element<V, E>
2253// Remove PartialEq/Eq bounds for V and E as they are not needed for serialization itself
2254impl<V, E> Serialize for Element<V, E>
2255where
2256    V: Serialize, // Removed PartialEq + Eq
2257    E: Serialize, // Removed PartialEq
2258{
2259    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2260    where
2261        S: Serializer,
2262    {
2263        // If id and extension are None, serialize value directly (or null)
2264        if self.id.is_none() && self.extension.is_none() {
2265            match &self.value {
2266                Some(val) => val.serialize(serializer),
2267                None => serializer.serialize_none(),
2268            }
2269        } else {
2270            // Otherwise, serialize as an object containing id, extension, value if present
2271            let mut len = 0;
2272            if self.id.is_some() {
2273                len += 1;
2274            }
2275            if self.extension.is_some() {
2276                len += 1;
2277            }
2278            if self.value.is_some() {
2279                len += 1;
2280            }
2281
2282            let mut state = serializer.serialize_struct("Element", len)?;
2283            if let Some(id) = &self.id {
2284                state.serialize_field("id", id)?;
2285            }
2286            if let Some(extension) = &self.extension {
2287                state.serialize_field("extension", extension)?;
2288            }
2289            // Restore value serialization for direct Element serialization
2290            if let Some(value) = &self.value {
2291                state.serialize_field("value", value)?;
2292            }
2293            state.end()
2294        }
2295    }
2296}
2297
2298/// Specialized element container for FHIR decimal values with precision preservation.
2299///
2300/// This type combines the generic `Element` pattern with `PreciseDecimal` to provide
2301/// a complete solution for FHIR decimal elements that require both extension support
2302/// and precision preservation during serialization round-trips.
2303///
2304/// # Type Parameters
2305///
2306/// * `E` - The extension type (typically the generated `Extension` struct)
2307///
2308/// # FHIR Decimal Requirements
2309///
2310/// FHIR decimal elements must:
2311/// - Preserve original string precision (e.g., "12.30" vs "12.3")
2312/// - Support mathematical operations using `Decimal` arithmetic
2313/// - Handle extension metadata through `id` and `extension` fields
2314/// - Serialize back to the exact original format when possible
2315///
2316/// # Examples
2317///
2318/// ```rust
2319/// use helios_fhir::{DecimalElement, PreciseDecimal, r4::Extension};
2320/// use rust_decimal::Decimal;
2321///
2322/// // Create from a Decimal value
2323/// let decimal_elem = DecimalElement::<Extension>::new(Decimal::new(1234, 2)); // 12.34
2324///
2325/// // Create with extensions
2326/// let extended_decimal: DecimalElement<Extension> = DecimalElement {
2327///     value: Some(PreciseDecimal::from_parts(
2328///         Some(Decimal::new(12300, 3)),
2329///         "12.300".to_string()
2330///     )),
2331///     id: Some("precision-example".to_string()),
2332///     extension: Some(vec![/* extensions */]),
2333/// };
2334///
2335/// // Access the mathematical value
2336/// if let Some(precise) = &extended_decimal.value {
2337///     if let Some(decimal_val) = precise.value() {
2338///         println!("Mathematical value: {}", decimal_val);
2339///     }
2340///     println!("Original format: {}", precise.original_string());
2341/// }
2342/// ```
2343///
2344/// # Serialization Behavior
2345///
2346/// - **Value only**: Serializes as a JSON number preserving original precision
2347/// - **With extensions**: Serializes as an object with `value`, `id`, and `extension` fields
2348/// - **No value**: Serializes as an object with just the extension fields, or `null` if empty
2349///
2350/// # Integration with FHIRPath
2351///
2352/// When used with FHIRPath evaluation, `DecimalElement` returns:
2353/// - The `Decimal` value for mathematical operations
2354/// - An object representation when extension metadata is accessed
2355/// - Empty collection when the element has no value or extensions
2356#[derive(Debug, PartialEq, Eq, Clone, Default)]
2357pub struct DecimalElement<E> {
2358    /// Optional element identifier for referencing within the resource
2359    pub id: Option<String>,
2360    /// Optional extensions providing additional metadata
2361    pub extension: Option<Vec<E>>,
2362    /// The decimal value with precision preservation
2363    pub value: Option<PreciseDecimal>,
2364}
2365
2366impl<E> DecimalElement<E> {
2367    /// Creates a new `DecimalElement` with the specified decimal value.
2368    ///
2369    /// This constructor creates a simple decimal element with no extensions or ID,
2370    /// containing only the decimal value. The original string representation is
2371    /// automatically derived from the `Decimal` value's `Display` implementation.
2372    ///
2373    /// # Arguments
2374    ///
2375    /// * `value` - The `Decimal` value to store
2376    ///
2377    /// # Returns
2378    ///
2379    /// A new `DecimalElement` with the value set and `id`/`extension` as `None`.
2380    ///
2381    /// # Examples
2382    ///
2383    /// ```rust
2384    /// use helios_fhir::{DecimalElement, r4::Extension};
2385    /// use rust_decimal::Decimal;
2386    ///
2387    /// // Create a simple decimal element
2388    /// let element = DecimalElement::<Extension>::new(Decimal::new(12345, 3)); // 12.345
2389    ///
2390    /// // Verify the structure
2391    /// assert!(element.id.is_none());
2392    /// assert!(element.extension.is_none());
2393    /// assert!(element.value.is_some());
2394    ///
2395    /// // Access the decimal value
2396    /// if let Some(precise_decimal) = &element.value {
2397    ///     assert_eq!(precise_decimal.value(), Some(Decimal::new(12345, 3)));
2398    ///     assert_eq!(precise_decimal.original_string(), "12.345");
2399    /// }
2400    /// ```
2401    ///
2402    /// # Usage in FHIR Resources
2403    ///
2404    /// This method is typically used when creating FHIR elements programmatically:
2405    ///
2406    /// ```rust
2407    /// use helios_fhir::{DecimalElement, r4::{Extension, Observation}};
2408    /// use rust_decimal::Decimal;
2409    ///
2410    /// let temperature = DecimalElement::<Extension>::new(Decimal::new(3672, 2)); // 36.72
2411    ///
2412    /// // Would be used in an Observation like:
2413    /// // observation.value_quantity.value = Some(temperature);
2414    /// ```
2415    pub fn new(value: Decimal) -> Self {
2416        // Convert the Decimal to PreciseDecimal, which automatically handles
2417        // storing the original string representation via the From trait
2418        let precise_value = PreciseDecimal::from(value);
2419        Self {
2420            id: None,
2421            extension: None,
2422            value: Some(precise_value),
2423        }
2424    }
2425
2426    /// Returns `true` if the element has no value, id, or extensions.
2427    #[inline]
2428    pub fn is_empty(&self) -> bool {
2429        self.value.is_none() && self.id.is_none() && self.extension.is_none()
2430    }
2431}
2432
2433// Custom Deserialize for DecimalElement<E> using intermediate Value
2434impl<'de, E> Deserialize<'de> for DecimalElement<E>
2435where
2436    E: Deserialize<'de> + Default,
2437{
2438    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2439    where
2440        D: Deserializer<'de>,
2441    {
2442        // Deserialize into an intermediate serde_json::Value first
2443        let json_value = serde_json::Value::deserialize(deserializer)?;
2444
2445        match json_value {
2446            // Handle primitive JSON Number
2447            serde_json::Value::Number(n) => {
2448                // Directly parse the number string to create PreciseDecimal
2449                let s = n.to_string(); // Note: n.to_string() might normalize exponent case (e.g., 'E' -> 'e')
2450                // Replace 'E' with 'e' for parsing
2451                let s_for_parsing = s.replace('E', "e");
2452                // Use from_scientific if 'e' is present, otherwise parse
2453                let parsed_value = if s_for_parsing.contains('e') {
2454                    Decimal::from_scientific(&s_for_parsing).ok()
2455                } else {
2456                    s_for_parsing.parse::<Decimal>().ok()
2457                };
2458                // Store the ORIGINAL string `s` (as returned by n.to_string()).
2459                let pd = PreciseDecimal::from_parts(parsed_value, s);
2460                Ok(DecimalElement {
2461                    id: None,
2462                    extension: None,
2463                    value: Some(pd),
2464                })
2465            }
2466            // Handle primitive JSON String
2467            serde_json::Value::String(s) => {
2468                // Directly parse the string to create PreciseDecimal
2469                // Replace 'E' with 'e' for parsing
2470                let s_for_parsing = s.replace('E', "e");
2471                // Use from_scientific if 'e' is present, otherwise parse
2472                let parsed_value = if s_for_parsing.contains('e') {
2473                    Decimal::from_scientific(&s_for_parsing).ok()
2474                } else {
2475                    s_for_parsing.parse::<Decimal>().ok()
2476                };
2477                // Store the ORIGINAL string `s`.
2478                let pd = PreciseDecimal::from_parts(parsed_value, s); // s is owned, no clone needed
2479                Ok(DecimalElement {
2480                    id: None,
2481                    extension: None,
2482                    value: Some(pd),
2483                })
2484            }
2485            // Handle JSON object: deserialize fields individually
2486            serde_json::Value::Object(map) => {
2487                let mut id: Option<String> = None;
2488                let mut extension: Option<Vec<E>> = None;
2489                let mut value: Option<PreciseDecimal> = None;
2490
2491                for (k, v) in map {
2492                    match k.as_str() {
2493                        "id" => {
2494                            if id.is_some() {
2495                                return Err(de::Error::duplicate_field("id"));
2496                            }
2497                            // Deserialize id directly from its Value
2498                            id = Deserialize::deserialize(v).map_err(de::Error::custom)?;
2499                        }
2500                        "extension" => {
2501                            if extension.is_some() {
2502                                return Err(de::Error::duplicate_field("extension"));
2503                            }
2504                            // Deserialize extension directly from its Value
2505                            extension = Deserialize::deserialize(v).map_err(de::Error::custom)?;
2506                        }
2507                        "value" => {
2508                            if value.is_some() {
2509                                return Err(de::Error::duplicate_field("value"));
2510                            }
2511                            // Deserialize value using PreciseDecimal::deserialize from its Value
2512                            // Handle null explicitly within the value field
2513                            if v.is_null() {
2514                                value = None;
2515                            } else {
2516                                value = Some(
2517                                    PreciseDecimal::deserialize(v).map_err(de::Error::custom)?,
2518                                );
2519                            }
2520                        }
2521                        // Ignore any unknown fields encountered
2522                        _ => {} // Simply ignore unknown fields
2523                    }
2524                }
2525                Ok(DecimalElement {
2526                    id,
2527                    extension,
2528                    value,
2529                })
2530            }
2531            // Handle JSON Null for the whole element
2532            serde_json::Value::Null => Ok(DecimalElement::default()), // Default has value: None
2533            // Handle other unexpected types
2534            other => Err(de::Error::invalid_type(
2535                match other {
2536                    serde_json::Value::Bool(b) => de::Unexpected::Bool(b),
2537                    serde_json::Value::Array(_) => de::Unexpected::Seq,
2538                    _ => de::Unexpected::Other("unexpected JSON type for DecimalElement"),
2539                },
2540                &"a decimal number, string, object, or null",
2541            )),
2542        }
2543    }
2544}
2545
2546// Reinstate custom Serialize implementation for DecimalElement
2547// Remove PartialEq bound for E
2548impl<E> Serialize for DecimalElement<E>
2549where
2550    E: Serialize, // Removed PartialEq bound for E
2551{
2552    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2553    where
2554        S: Serializer,
2555    {
2556        // If we only have a value and no other fields, serialize just the value
2557        if self.id.is_none() && self.extension.is_none() {
2558            if let Some(value) = &self.value {
2559                // Serialize the PreciseDecimal directly, invoking its custom Serialize impl
2560                return value.serialize(serializer);
2561            } else {
2562                // If value is also None, serialize as null
2563                // based on updated test_serialize_decimal_with_no_fields
2564                return serializer.serialize_none();
2565            }
2566        }
2567
2568        // Otherwise, serialize as a struct with all present fields
2569        // Calculate the number of fields that are NOT None
2570        let mut len = 0;
2571        if self.id.is_some() {
2572            len += 1;
2573        }
2574        if self.extension.is_some() {
2575            len += 1;
2576        }
2577        if self.value.is_some() {
2578            len += 1;
2579        }
2580
2581        // Start serializing a struct with the calculated length
2582        let mut state = serializer.serialize_struct("DecimalElement", len)?;
2583
2584        // Serialize 'id' field if it's Some
2585        if let Some(id) = &self.id {
2586            state.serialize_field("id", id)?;
2587        }
2588
2589        // Serialize 'extension' field if it's Some
2590        if let Some(extension) = &self.extension {
2591            state.serialize_field("extension", extension)?;
2592        }
2593
2594        // Serialize 'value' field if it's Some
2595        if let Some(value) = &self.value {
2596            // Serialize the PreciseDecimal directly, invoking its custom Serialize impl
2597            state.serialize_field("value", value)?;
2598        }
2599
2600        // End the struct serialization
2601        state.end()
2602    }
2603}
2604
2605// For Element<V, E> - Returns Object with id, extension, value if present
2606impl<V, E> IntoEvaluationResult for Element<V, E>
2607where
2608    V: IntoEvaluationResult + Clone + 'static,
2609    E: IntoEvaluationResult + Clone,
2610{
2611    fn to_evaluation_result(&self) -> EvaluationResult {
2612        use std::any::TypeId;
2613
2614        // Prioritize returning the primitive value if it exists
2615        if let Some(v) = &self.value {
2616            let result = v.to_evaluation_result();
2617            // For primitive values, we need to preserve FHIR type information
2618            return match result {
2619                EvaluationResult::Boolean(b, _) => {
2620                    // Return FHIR boolean
2621                    EvaluationResult::fhir_boolean(b)
2622                }
2623                EvaluationResult::Integer(i, _) => {
2624                    // Return FHIR integer
2625                    EvaluationResult::fhir_integer(i)
2626                }
2627                #[cfg(not(any(feature = "R4", feature = "R4B")))]
2628                EvaluationResult::Integer64(i, _) => {
2629                    // Return FHIR integer64 (R5 and above)
2630                    EvaluationResult::fhir_integer64(i)
2631                }
2632                EvaluationResult::String(s, _) => {
2633                    // Determine the FHIR type name based on V's type
2634                    let fhir_type_name = if TypeId::of::<V>() == TypeId::of::<String>() {
2635                        // For strings, we need more context to determine the exact FHIR type
2636                        // Default to "string" but this could be date, dateTime, etc.
2637                        "string"
2638                    } else {
2639                        // Default fallback
2640                        "string"
2641                    };
2642                    EvaluationResult::fhir_string(s, fhir_type_name)
2643                }
2644                EvaluationResult::DateTime(dt, type_info) => {
2645                    // Check if V is PrecisionInstant - if so, this is an instant
2646                    if TypeId::of::<V>() == TypeId::of::<PrecisionInstant>() {
2647                        // Return as FHIR instant
2648                        EvaluationResult::DateTime(dt, Some(TypeInfoResult::new("FHIR", "instant")))
2649                    } else {
2650                        // Preserve original type info for PrecisionDateTime
2651                        EvaluationResult::DateTime(dt, type_info)
2652                    }
2653                }
2654                _ => result, // For other types, return as-is
2655            };
2656        } else if self.id.is_some() || self.extension.is_some() {
2657            // If value is None, but id or extension exist, return an Object with those
2658            let mut map = std::collections::HashMap::new();
2659            if let Some(id) = &self.id {
2660                map.insert("id".to_string(), EvaluationResult::string(id.clone()));
2661            }
2662            if let Some(ext) = &self.extension {
2663                let ext_collection: Vec<EvaluationResult> =
2664                    ext.iter().map(|e| e.to_evaluation_result()).collect();
2665                if !ext_collection.is_empty() {
2666                    map.insert(
2667                        "extension".to_string(),
2668                        EvaluationResult::collection(ext_collection),
2669                    );
2670                }
2671            }
2672            // Only return Object if map is not empty (i.e., id or extension was actually present)
2673            if !map.is_empty() {
2674                return EvaluationResult::typed_object(map, "FHIR", "Element");
2675            }
2676        }
2677
2678        // If value, id, and extension are all None, return Empty
2679        EvaluationResult::Empty
2680    }
2681}
2682
2683// For DecimalElement<E> - Returns Decimal value if present, otherwise handles id/extension
2684impl<E> IntoEvaluationResult for DecimalElement<E>
2685where
2686    E: IntoEvaluationResult + Clone,
2687{
2688    fn to_evaluation_result(&self) -> EvaluationResult {
2689        // Prioritize returning the primitive decimal value if it exists
2690        if let Some(precise_decimal) = &self.value {
2691            if let Some(decimal_val) = precise_decimal.value() {
2692                // Return FHIR decimal
2693                return EvaluationResult::fhir_decimal(decimal_val);
2694            }
2695            // If PreciseDecimal holds None for value, fall through to check id/extension
2696        }
2697
2698        // If value is None, but id or extension exist, return an Object with those
2699        if self.id.is_some() || self.extension.is_some() {
2700            let mut map = std::collections::HashMap::new();
2701            if let Some(id) = &self.id {
2702                map.insert("id".to_string(), EvaluationResult::string(id.clone()));
2703            }
2704            if let Some(ext) = &self.extension {
2705                let ext_collection: Vec<EvaluationResult> =
2706                    ext.iter().map(|e| e.to_evaluation_result()).collect();
2707                if !ext_collection.is_empty() {
2708                    map.insert(
2709                        "extension".to_string(),
2710                        EvaluationResult::collection(ext_collection),
2711                    );
2712                }
2713            }
2714            // Only return Object if map is not empty
2715            if !map.is_empty() {
2716                return EvaluationResult::typed_object(map, "FHIR", "decimal");
2717            }
2718        }
2719
2720        // If value, id, and extension are all None, return Empty
2721        EvaluationResult::Empty
2722    }
2723}
2724
2725// Implement the trait for the top-level enum
2726impl IntoEvaluationResult for FhirResource {
2727    fn to_evaluation_result(&self) -> EvaluationResult {
2728        match self {
2729            #[cfg(feature = "R4")]
2730            FhirResource::R4(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r4::Resource>
2731            #[cfg(feature = "R4B")]
2732            FhirResource::R4B(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r4b::Resource>
2733            #[cfg(feature = "R5")]
2734            FhirResource::R5(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r5::Resource>
2735            #[cfg(feature = "R6")]
2736            FhirResource::R6(r) => (*r).to_evaluation_result(), // Call impl on inner Box<r6::Resource>
2737                                                                // Note: If no features are enabled, this match might be empty or non-exhaustive.
2738                                                                // This is generally okay as the enum itself wouldn't be usable.
2739        }
2740    }
2741}
2742
2743#[cfg(test)]
2744mod tests {
2745    use super::*;
2746
2747    #[test]
2748    fn test_integer_string_deserialization() {
2749        // Test deserializing a string "2" into Element<i64, ()>
2750        type TestElement = Element<i64, ()>;
2751
2752        // Test case 1: String containing integer
2753        let json_str = r#""2""#;
2754        let result: Result<TestElement, _> = serde_json::from_str(json_str);
2755        assert!(
2756            result.is_ok(),
2757            "Failed to deserialize string '2' as i64: {:?}",
2758            result.err()
2759        );
2760
2761        let element = result.unwrap();
2762        assert_eq!(element.value, Some(2i64));
2763        assert_eq!(element.id, None);
2764        assert_eq!(element.extension, None);
2765
2766        // Test case 2: Number
2767        let json_num = r#"2"#;
2768        let result: Result<TestElement, _> = serde_json::from_str(json_num);
2769        assert!(
2770            result.is_ok(),
2771            "Failed to deserialize number 2 as i64: {:?}",
2772            result.err()
2773        );
2774
2775        let element = result.unwrap();
2776        assert_eq!(element.value, Some(2i64));
2777    }
2778
2779    #[test]
2780    fn test_i32_string_deserialization() {
2781        type TestElement = Element<i32, ()>;
2782
2783        let json_str = r#""123""#;
2784        let result: Result<TestElement, _> = serde_json::from_str(json_str);
2785        assert!(result.is_ok());
2786
2787        let element = result.unwrap();
2788        assert_eq!(element.value, Some(123i32));
2789    }
2790
2791    #[test]
2792    fn test_invalid_string_fallback() {
2793        type TestElement = Element<i64, ()>;
2794
2795        // Non-numeric string should fail for integer type
2796        let json_str = r#""not_a_number""#;
2797        let result: Result<TestElement, _> = serde_json::from_str(json_str);
2798        assert!(
2799            result.is_err(),
2800            "Should fail to deserialize non-numeric string as i64"
2801        );
2802    }
2803}